[ 
https://issues.apache.org/jira/browse/THRIFT-3143?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16703759#comment-16703759
 ] 

ASF GitHub Bot commented on THRIFT-3143:
----------------------------------------

jeking3 closed pull request #1630: THRIFT-3143: Add nodets support
URL: https://github.com/apache/thrift/pull/1630
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/Makefile.am b/Makefile.am
index cdb8bd2f5b..511452dfc8 100755
--- a/Makefile.am
+++ b/Makefile.am
@@ -54,7 +54,7 @@ empty :=
 space := $(empty) $(empty)
 comma := ,
 
-CROSS_LANGS = @MAYBE_CPP@ @MAYBE_C_GLIB@ @MAYBE_CL@ @MAYBE_D@ @MAYBE_JAVA@ 
@MAYBE_CSHARP@ @MAYBE_PYTHON@ @MAYBE_PY3@ @MAYBE_RUBY@ @MAYBE_HASKELL@ 
@MAYBE_PERL@ @MAYBE_PHP@ @MAYBE_GO@ @MAYBE_NODEJS@ @MAYBE_DART@ @MAYBE_ERLANG@ 
@MAYBE_LUA@ @MAYBE_RS@ @MAYBE_DOTNETCORE@
+CROSS_LANGS = @MAYBE_CPP@ @MAYBE_C_GLIB@ @MAYBE_CL@ @MAYBE_D@ @MAYBE_JAVA@ 
@MAYBE_CSHARP@ @MAYBE_PYTHON@ @MAYBE_PY3@ @MAYBE_RUBY@ @MAYBE_HASKELL@ 
@MAYBE_PERL@ @MAYBE_PHP@ @MAYBE_GO@ @MAYBE_NODEJS@ @MAYBE_DART@ @MAYBE_ERLANG@ 
@MAYBE_LUA@ @MAYBE_RS@ @MAYBE_DOTNETCORE@ @MAYBE_NODETS@
 CROSS_LANGS_COMMA_SEPARATED = $(subst $(space),$(comma),$(CROSS_LANGS))
 
 if WITH_PY3
diff --git a/compiler/cpp/src/thrift/generate/t_js_generator.cc 
b/compiler/cpp/src/thrift/generate/t_js_generator.cc
index 840168ef53..61782b9d8b 100644
--- a/compiler/cpp/src/thrift/generate/t_js_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_js_generator.cc
@@ -64,7 +64,7 @@ class t_js_generator : public t_oop_generator {
 
     bool with_ns_ = false;
 
-    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+    for (iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
       if( iter->first.compare("node") == 0) {
         gen_node_ = true;
       } else if( iter->first.compare("jquery") == 0) {
@@ -80,10 +80,6 @@ class t_js_generator : public t_oop_generator {
       }
     }
 
-    if (gen_node_ && gen_ts_) {
-      throw "Invalid switch: [-gen js:node,ts] options not compatible";
-    }
-
     if (gen_es6_ && gen_jquery_) {
       throw "Invalid switch: [-gen js:es6,jquery] options not compatible";
     }
@@ -203,6 +199,7 @@ class t_js_generator : public t_oop_generator {
    */
 
   std::string js_includes();
+  std::string ts_includes();
   std::string render_includes();
   std::string declare_field(t_field* tfield, bool init = false, bool obj = 
false);
   std::string function_signature(t_function* tfunction,
@@ -285,7 +282,7 @@ class t_js_generator : public t_oop_generator {
    * TypeScript Definition File helper functions
    */
 
-  string ts_function_signature(t_function* tfunction, bool include_callback);
+  string ts_function_signature(t_function* tfunction, bool include_callback, 
bool optional_callback);
   string ts_get_type(t_type* type);
 
   /**
@@ -302,11 +299,11 @@ class t_js_generator : public t_oop_generator {
   string ts_declare() { return (ts_module_.empty() ? "declare " : ""); }
 
   /**
-   * Returns "?" if the given field is optional.
+   * Returns "?" if the given field is optional or has a default value.
    * @param t_field The field to check
    * @return string
    */
-  string ts_get_req(t_field* field) { return (field->get_req() == 
t_field::T_OPTIONAL ? "?" : ""); }
+  string ts_get_req(t_field* field) {return (field->get_req() == 
t_field::T_OPTIONAL || field->get_value() != NULL ? "?" : ""); }
 
   /**
    * Returns the documentation, if the provided documentable object has one.
@@ -415,7 +412,7 @@ void t_js_generator::init_generator() {
   f_types_ << js_includes() << endl << render_includes() << endl;
 
   if (gen_ts_) {
-    f_types_ts_ << autogen_comment() << endl;
+    f_types_ts_ << autogen_comment() << ts_includes() << endl;
   }
 
   if (gen_node_) {
@@ -457,6 +454,20 @@ string t_js_generator::js_includes() {
   return "";
 }
 
+/**
+ * Prints standard ts imports
+ */
+string t_js_generator::ts_includes() {
+  if (gen_node_) {
+    return string(
+        "import thrift = require('thrift');\n"
+        "import Thrift = thrift.Thrift;\n"
+        "import Q = thrift.Q;\n");
+  }
+
+  return "";
+}
+
 /**
  * Renders all the imports necessary for including another Thrift program
  */
@@ -518,8 +529,8 @@ void t_js_generator::generate_enum(t_enum* tenum) {
 
   indent_up();
 
-  vector<t_enum_value*> constants = tenum->get_constants();
-  vector<t_enum_value*>::iterator c_iter;
+  vector<t_enum_value*> const& constants = tenum->get_constants();
+  vector<t_enum_value*>::const_iterator c_iter;
   for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
     int value = (*c_iter)->get_value();
     if (gen_ts_) {
@@ -720,6 +731,11 @@ void 
t_js_generator::generate_js_struct_definition(ostream& out,
     string prefix = has_js_namespace(tstruct->get_program()) ? 
js_namespace(tstruct->get_program()) : js_const_type_;
     out << prefix << tstruct->get_name() <<
       (is_exported ? " = module.exports." + tstruct->get_name() : "");
+    if (gen_ts_) {
+      f_types_ts_ << ts_print_doc(tstruct) << ts_indent() << ts_declare() << 
"class "
+                  << tstruct->get_name() << (is_exception ? " extends 
Thrift.TException" : "")
+                  << " {" << endl;
+    }
   } else {
     out << js_namespace(tstruct->get_program()) << tstruct->get_name();
     if (gen_ts_) {
@@ -766,8 +782,14 @@ void 
t_js_generator::generate_js_struct_definition(ostream& out,
       out << indent() << dval << ";" << endl;
     }
     if (gen_ts_) {
-      f_types_ts_ << ts_indent() << (*m_iter)->get_name() << ": "
-                  << ts_get_type((*m_iter)->get_type()) << ";" << endl;
+      if (gen_node_) {
+        f_types_ts_ << ts_indent() << "public " << (*m_iter)->get_name() << ": 
"
+                    << ts_get_type((*m_iter)->get_type()) << ";" << endl;
+      } else {
+        f_types_ts_ << ts_indent() << (*m_iter)->get_name() << ": "
+                    << ts_get_type((*m_iter)->get_type()) << ";" << endl;
+      }
+      
     }
   }
 
@@ -1065,6 +1087,39 @@ void t_js_generator::generate_service(t_service* 
tservice) {
                     << ".d.ts\" />" << endl;
     }
     f_service_ts_ << autogen_comment() << endl;
+    if (gen_node_) {
+      f_service_ts_ << ts_includes() << endl;
+      f_service_ts_ << "import ttypes = require('./" + program_->get_name() + 
"_types');" << endl;
+      // Generate type aliases
+      // enum
+      vector<t_enum*> const& enums = program_->get_enums();
+      vector<t_enum*>::const_iterator e_iter;
+      for (e_iter = enums.begin(); e_iter != enums.end(); ++e_iter) {
+        f_service_ts_ << "import " << (*e_iter)->get_name() << " = ttypes."
+                  << js_namespace(program_) << (*e_iter)->get_name() << endl;
+      }
+      // const
+      vector<t_const*> const& consts = program_->get_consts();
+      vector<t_const*>::const_iterator c_iter;
+      for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+        f_service_ts_ << "import " << (*c_iter)->get_name() << " = ttypes."
+                  << js_namespace(program_) << (*c_iter)->get_name() << endl;
+      }
+      // exception
+      vector<t_struct*> const& exceptions = program_->get_xceptions();
+      vector<t_struct*>::const_iterator x_iter;
+      for (x_iter = exceptions.begin(); x_iter != exceptions.end(); ++x_iter) {
+        f_service_ts_ << "import " << (*x_iter)->get_name() << " = ttypes."
+                  << js_namespace(program_) << (*x_iter)->get_name() << endl;
+      }
+      // structs
+      vector<t_struct*> const& structs = program_->get_structs();
+      vector<t_struct*>::const_iterator s_iter;
+      for (s_iter = structs.begin(); s_iter != structs.end(); ++s_iter) {
+        f_service_ts_ << "import " << (*s_iter)->get_name() << " = ttypes."
+                  << js_namespace(program_) << (*s_iter)->get_name() << endl;
+      }
+    }
     if (!ts_module_.empty()) {
       f_service_ts_ << "declare module " << ts_module_ << " {";
     }
@@ -1112,6 +1167,18 @@ void 
t_js_generator::generate_service_processor(t_service* tservice) {
   if (gen_node_) {
     string prefix = has_js_namespace(tservice->get_program()) ? 
js_namespace(tservice->get_program()) : js_const_type_;
     f_service_ << prefix << service_name_ << "Processor = " << 
"exports.Processor";
+    if (gen_ts_) {
+      f_service_ts_ << endl << "declare class Processor ";
+      if (tservice->get_extends() != NULL) {
+        f_service_ts_ << "extends " << tservice->get_extends()->get_name() << 
"Processor ";
+      }
+      f_service_ts_ << "{" << endl;
+      indent_up();
+      f_service_ts_ << ts_indent() << "private _handler: Object;" << endl << 
endl;
+      f_service_ts_ << ts_indent() << "constructor(handler: Object);" << endl;
+      f_service_ts_ << ts_indent() << "process(input: Thrift.TJSONProtocol, 
output: Thrift.TJSONProtocol): void;" << endl;
+      indent_down();
+    }
   } else {
     f_service_ << js_namespace(tservice->get_program()) << service_name_ << 
"Processor = "
              << "exports.Processor";
@@ -1193,6 +1260,9 @@ void 
t_js_generator::generate_service_processor(t_service* tservice) {
     indent_down();
     indent(f_service_) << "};" << endl;
   }
+  if (gen_node_ && gen_ts_) {
+    f_service_ts_ << "}" << endl;
+  }
 }
 
 /**
@@ -1201,7 +1271,6 @@ void 
t_js_generator::generate_service_processor(t_service* tservice) {
  * @param tfunction The function to write a dispatcher for
  */
 void t_js_generator::generate_process_function(t_service* tservice, 
t_function* tfunction) {
-
   if (gen_es6_) {
     indent(f_service_) << "process_" + tfunction->get_name() + " (seqid, 
input, output) {" << endl;
   } else {
@@ -1209,6 +1278,11 @@ void 
t_js_generator::generate_process_function(t_service* tservice, t_function*
                       << "Processor.prototype.process_" + tfunction->get_name()
                           + " = function(seqid, input, output) {" << endl;
   }
+  if (gen_ts_) {
+    indent_up();
+    f_service_ts_ << ts_indent() << "process_" << tfunction->get_name() << 
"(seqid: number, input: Thrift.TJSONProtocol, output: Thrift.TJSONProtocol): 
void;" << endl;
+    indent_down();
+  }
 
   indent_up();
 
@@ -1475,6 +1549,14 @@ void t_js_generator::generate_service_client(t_service* 
tservice) {
   if (gen_node_) {
     string prefix = has_js_namespace(tservice->get_program()) ? 
js_namespace(tservice->get_program()) : js_const_type_;
     f_service_ << prefix << service_name_ << "Client = " << "exports.Client";
+    if (gen_ts_) {
+      f_service_ts_ << ts_print_doc(tservice) << ts_indent() << ts_declare() 
<< "class "
+                    << "Client ";
+      if (tservice->get_extends() != NULL) {
+        f_service_ts_ << "extends " << tservice->get_extends()->get_name() << 
"Client ";
+      }
+      f_service_ts_ << "{" << endl;
+    }
   } else {
     f_service_ << js_namespace(tservice->get_program()) << service_name_
                << "Client";
@@ -1517,6 +1599,13 @@ void t_js_generator::generate_service_client(t_service* 
tservice) {
     indent(f_service_) << "this.pClass = pClass;" << endl;
     indent(f_service_) << "this._seqid = 0;" << endl;
     indent(f_service_) << "this._reqs = {};" << endl;
+    if (gen_ts_) {
+      f_service_ts_ << ts_indent() << "private input: Thrift.TJSONProtocol;" 
<< endl << ts_indent()
+                    << "private output: Thrift.TJSONProtocol;" << endl << 
ts_indent() << "private seqid: number;"
+                    << endl << endl << ts_indent()
+                    << "constructor(input: Thrift.TJSONProtocol, output?: 
Thrift.TJSONProtocol);"
+                    << endl;
+    }
   } else {
     indent(f_service_) << "this.input = input;" << endl;
     indent(f_service_) << "this.output = (!output) ? input : output;" << endl;
@@ -1585,11 +1674,13 @@ void t_js_generator::generate_service_client(t_service* 
tservice) {
 
     if (gen_ts_) {
       // function definition without callback
-      f_service_ts_ << ts_print_doc(*f_iter) << ts_indent() << 
ts_function_signature(*f_iter, false) << endl;
-
+      f_service_ts_ << ts_print_doc(*f_iter) << ts_indent() << 
ts_function_signature(*f_iter, false, false) << endl;
       if (!gen_es6_) {
         // overload with callback
-        f_service_ts_ << ts_print_doc(*f_iter) << ts_indent() << 
ts_function_signature(*f_iter, true) << endl;
+        f_service_ts_ << ts_print_doc(*f_iter) << ts_indent() << 
ts_function_signature(*f_iter, true, false) << endl;
+      } else {
+        // overload with callback
+        f_service_ts_ << ts_print_doc(*f_iter) << ts_indent() << 
ts_function_signature(*f_iter, true, true) << endl;
       }
     }
 
@@ -2531,7 +2622,7 @@ string t_js_generator::ts_get_type(t_type* type) {
  * @param bool in-/exclude the callback argument
  * @return String of rendered function definition
  */
-std::string t_js_generator::ts_function_signature(t_function* tfunction, bool 
include_callback) {
+std::string t_js_generator::ts_function_signature(t_function* tfunction, bool 
include_callback, bool optional_callback) {
   string str;
   const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
   vector<t_field*>::const_iterator f_iter;
@@ -2547,7 +2638,29 @@ std::string 
t_js_generator::ts_function_signature(t_function* tfunction, bool in
   }
 
   if (include_callback) {
-    str += "callback: (data: " + ts_get_type(tfunction->get_returntype()) + 
")=>void): ";
+    string callback_optional_string = optional_callback ? "?" : "";
+    if (gen_node_) {
+      t_struct* exceptions = tfunction->get_xceptions();
+      string exception_types;
+      if (exceptions) {
+        const vector<t_field*>& members = exceptions->get_members();
+        for (vector<t_field*>::const_iterator it = members.begin(); it != 
members.end(); ++it) {
+          t_type* t = get_true_type((*it)->get_type());
+          if (it == members.begin()) {
+            exception_types = t->get_name();
+          } else {
+            exception_types += " | " + t->get_name();
+          }
+        }
+      }
+      if (exception_types == "") {
+        str += "callback" + callback_optional_string + ": (error: void, 
response: " + ts_get_type(tfunction->get_returntype()) + ")=>void): ";
+      } else {
+        str += "callback" + callback_optional_string + ": (error: " + 
exception_types + ", response: " + ts_get_type(tfunction->get_returntype()) + 
")=>void): ";
+      }
+    } else {
+      str += "callback" + callback_optional_string + ": (data: " + 
ts_get_type(tfunction->get_returntype()) + ")=>void): ";
+    }
 
     if (gen_jquery_) {
       str += "JQueryPromise<" + ts_get_type(tfunction->get_returntype()) +">;";
diff --git a/configure.ac b/configure.ac
index 14a8c2e0bf..aca6f30fd4 100755
--- a/configure.ac
+++ b/configure.ac
@@ -109,6 +109,8 @@ fi
 
 AM_EXTRA_RECURSIVE_TARGETS([style])
 AC_SUBST(CPPSTYLE_CMD, 'find . -type f \( -iname "*.h" -or -iname "*.cpp" -or 
-iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec 
clang-format -i {} \;')
+# '
+# The above comment is to fix editor syntax highlighting
 
 AC_ARG_ENABLE([libs],
   AS_HELP_STRING([--enable-libs], [build the Apache Thrift libraries 
[default=yes]]),
@@ -136,6 +138,7 @@ if test "$enable_libs" = "no"; then
   with_go="no"
   with_d="no"
   with_nodejs="no"
+  with_nodets="no"
   with_lua="no"
   with_rs="no"
 fi
@@ -279,6 +282,18 @@ fi
 AM_CONDITIONAL(WITH_NODEJS, [test "$have_nodejs" = "yes"])
 AM_CONDITIONAL(HAVE_NPM, [test "x$NPM" != "x"])
 
+AX_THRIFT_LIB(nodets, [Nodets], yes)
+have_nodets=no
+if test "$with_nodets" = "yes"; then
+  AC_PATH_PROGS([NODETS], [nodets node])
+  AC_PATH_PROG([NPM], [npm])
+  if test "x$NODETS" != "x" -a "x$NPM" != "x"; then
+    have_nodets="yes"
+  fi
+fi
+AM_CONDITIONAL(WITH_NODETS, [test "$have_nodets" = "yes"])
+AM_CONDITIONAL(HAVE_NPM, [test "x$NPM" != "x"])
+
 AX_THRIFT_LIB(lua, [Lua], yes)
 have_lua=no
 if test "$with_lua" = "yes"; then
@@ -825,6 +840,7 @@ AC_CONFIG_FILES([
   lib/json/test/Makefile
   lib/netcore/Makefile
   lib/nodejs/Makefile
+  lib/nodets/Makefile
   lib/perl/Makefile
   lib/perl/test/Makefile
   lib/php/Makefile
@@ -905,6 +921,8 @@ if test "$have_go" = "yes" ; then MAYBE_GO="go" ; else 
MAYBE_GO="" ; fi
 AC_SUBST([MAYBE_GO])
 if test "$have_nodejs" = "yes" ; then MAYBE_NODEJS="nodejs" ; else 
MAYBE_NODEJS="" ; fi
 AC_SUBST([MAYBE_NODEJS])
+if test "$have_nodets" = "yes" ; then MAYBE_NODETS="nodets" ; else 
MAYBE_NODETS="" ; fi
+AC_SUBST([MAYBE_NODETS])
 if test "$have_erlang" = "yes" ; then MAYBE_ERLANG="erl" ; else 
MAYBE_ERLANG="" ; fi
 AC_SUBST([MAYBE_ERLANG])
 if test "$have_lua" = "yes" ; then MAYBE_LUA="lua" ; else MAYBE_LUA="" ; fi
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 0401c99e11..b31560915e 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -87,6 +87,7 @@ endif
 if WITH_NODEJS
 SUBDIRS += nodejs
 PRECROSS_TARGET += precross-nodejs
+SUBDIRS += nodets
 endif
 
 if WITH_LUA
diff --git a/lib/nodets/.gitignore b/lib/nodets/.gitignore
new file mode 100644
index 0000000000..c7aba89242
--- /dev/null
+++ b/lib/nodets/.gitignore
@@ -0,0 +1 @@
+test-compiled/
diff --git a/lib/nodets/Makefile.am b/lib/nodets/Makefile.am
new file mode 100755
index 0000000000..ea640cf0e7
--- /dev/null
+++ b/lib/nodets/Makefile.am
@@ -0,0 +1,45 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# We call npm twice to work around npm issues
+
+stubs: $(top_srcdir)/test/ThriftTest.thrift
+       mkdir -p test-compiled
+       $(THRIFT) --gen js:node,ts -o test/ 
$(top_srcdir)/test/ThriftTest.thrift && $(THRIFT) --gen js:node,ts -o 
test-compiled $(top_srcdir)/test/ThriftTest.thrift
+
+ts-compile: stubs
+       mkdir -p test-compiled
+       ../../node_modules/typescript/bin/tsc --outDir test-compiled/ --project 
test/tsconfig.json
+
+deps: $(top_srcdir)/package.json
+       $(NPM) install $(top_srcdir)/ || $(NPM) install $(top_srcdir)/
+
+all-local: deps ts-compile
+
+precross: deps stubs ts-compile
+
+check: deps ts-compile
+       cd $(top_srcdir) && $(NPM) run test-ts && cd lib/nodets
+
+clean-local:
+       $(RM) -r test/gen-nodejs
+       $(RM) -r $(top_srcdir)/node_modules
+       $(RM) -r test-compiled
+
+EXTRA_DIST = \
+       test \
+       coding_standards.md
diff --git a/lib/nodets/coding_standards.md b/lib/nodets/coding_standards.md
new file mode 100644
index 0000000000..fa0390bb57
--- /dev/null
+++ b/lib/nodets/coding_standards.md
@@ -0,0 +1 @@
+Please follow [General Coding Standards](/doc/coding_standards.md)
diff --git a/lib/nodets/test/client.ts b/lib/nodets/test/client.ts
new file mode 100644
index 0000000000..eb3db79a89
--- /dev/null
+++ b/lib/nodets/test/client.ts
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import assert = require("assert");
+import thrift = require("thrift");
+import Thrift = thrift.Thrift;
+import ThriftTest = require("./gen-nodejs/ThriftTest");
+import test_driver = require("./test_driver");
+import ThriftTestDriver = test_driver.ThriftTestDriver;
+import ThriftTestDriverPromise = test_driver.ThriftTestDriverPromise;
+
+// var program = require("commander");
+import * as program from "commander";
+
+program
+  .option("--port <port>", "Set thrift server port number to connect", 9090)
+  .option("--promise", "test with promise style functions")
+  .option("--protocol", "Set thrift protocol (binary) [protocol]")
+  .parse(process.argv);
+
+var port: number = program.port;
+var promise = program.promise;
+
+var options = {
+  transport: Thrift.TBufferedTransport,
+  protocol: Thrift.TBinaryProtocol
+};
+
+var testDriver = promise ? ThriftTestDriverPromise : ThriftTestDriver;
+
+var connection = thrift.createConnection("localhost", port, options);
+
+connection.on("error", function(err: string) {
+    assert(false, err);
+});
+
+var client = thrift.createClient(ThriftTest.Client, connection);
+runTests();
+
+function runTests() {
+  testDriver(client, function (status: string) {
+    console.log(status);
+    connection.end();
+  });
+}
+
+exports.expressoTest = function() {};
diff --git a/lib/nodets/test/runClient.sh b/lib/nodets/test/runClient.sh
new file mode 100755
index 0000000000..8d5e9a33f0
--- /dev/null
+++ b/lib/nodets/test/runClient.sh
@@ -0,0 +1,18 @@
+#! /bin/sh
+
+DIR="$( cd "$( dirname "$0" )" && pwd )"
+
+mkdir -p $DIR/../test-compiled
+
+COMPILEDDIR="$(cd $DIR && cd ../test-compiled && pwd)"
+export NODE_PATH="${DIR}:${DIR}/../../nodejs/lib:${NODE_PATH}"
+
+compile()
+{
+  #generating thrift code
+  ${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node,ts 
${DIR}/../../../test/ThriftTest.thrift
+  ${DIR}/../../../compiler/cpp/thrift -o ${COMPILEDDIR} --gen js:node,ts 
${DIR}/../../../test/ThriftTest.thrift
+}
+compile
+
+node ${COMPILEDDIR}/client.js $*
diff --git a/lib/nodets/test/runServer.sh b/lib/nodets/test/runServer.sh
new file mode 100755
index 0000000000..4eee92717e
--- /dev/null
+++ b/lib/nodets/test/runServer.sh
@@ -0,0 +1,20 @@
+#! /bin/sh
+
+DIR="$( cd "$( dirname "$0" )" && pwd )"
+
+mkdir -p $DIR/../test-compiled
+
+COMPILEDDIR="$(cd $DIR && cd ../test-compiled && pwd)"
+export NODE_PATH="${DIR}:${DIR}/../../nodejs/lib:${NODE_PATH}"
+
+compile()
+{
+  #generating thrift code
+  ${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node,ts 
${DIR}/../../../test/ThriftTest.thrift
+  ${DIR}/../../../compiler/cpp/thrift -o ${COMPILEDDIR} --gen js:node,ts 
${DIR}/../../../test/ThriftTest.thrift
+}
+compile
+
+node ${COMPILEDDIR}/server.js $*
+
+
diff --git a/lib/nodets/test/server.ts b/lib/nodets/test/server.ts
new file mode 100644
index 0000000000..2da53aee29
--- /dev/null
+++ b/lib/nodets/test/server.ts
@@ -0,0 +1,26 @@
+import thrift = require("thrift");
+var program = require('commander');
+import ThriftTest = require('./gen-nodejs/ThriftTest');
+import test_handler = require('./test_handler');
+
+
+program
+  .option('--port <port>', 'Set thrift server port', 9090)
+  .option('--promise', 'test with promise style functions')
+  .option('--protocol', '"Set thrift protocol (binary) [protocol]"')
+  .parse(process.argv);
+
+var port: number = program.port;
+
+var options: thrift.ServerOptions = {
+  transport: thrift.TBufferedTransport,
+  protocol: thrift.TBinaryProtocol
+};
+
+var server: thrift.Server;
+if (program.promise) {
+  server = thrift.createServer(ThriftTest.Processor, new 
test_handler.AsyncThriftTestHandler(), options);
+} else {
+  server = thrift.createServer(ThriftTest.Processor, new 
test_handler.SyncThriftTestHandler(), options);
+}
+server.listen(port);
diff --git a/lib/nodets/test/test-cases.ts b/lib/nodets/test/test-cases.ts
new file mode 100644
index 0000000000..ca740ec826
--- /dev/null
+++ b/lib/nodets/test/test-cases.ts
@@ -0,0 +1,113 @@
+'use strict';
+
+import ttypes = require('./gen-nodejs/ThriftTest_types');
+
+//all Languages in UTF-8
+/*jshint -W100 */
+export var stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, " +
+    "Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, " +
+    "Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, " +
+    "বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, " +
+    "Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, " +
+    "Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, " +
+    "Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, " +
+    "Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, " +
+    "Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, " +
+    "Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, " +
+    "Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, " +
+    "ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, " +
+    "Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, " +
+    "Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa " +
+    "Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa " +
+    "Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪" +
+    "Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, " +
+    "Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو, " +
+    "Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română, " +
+    "Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple " +
+    "English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, " +
+    "Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, " +
+    "Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, " +
+    "Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, " +
+    "Bân-lâm-gú, 粵語";
+/*jshint +W100 */
+
+export var specialCharacters = 'quote: \" backslash:' +
+    ' forwardslash-escaped: \/ ' +
+    ' backspace: \b formfeed: \f newline: \n return: \r tab: ' +
+    ' now-all-of-them-together: "\\\/\b\n\r\t' +
+    ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><' +
+    ' char-to-test-json-parsing: ]] \"]] \\" }}}{ [[[ ';
+
+export var mapTestInput = {
+  "a":"123", "a b":"with spaces ", "same":"same", "0":"numeric key",
+  "longValue":stringTest, stringTest:"long key"
+};
+
+export var simple = [
+  ['testVoid', undefined],
+  ['testString', 'Test'],
+  ['testString', ''],
+  ['testString', stringTest],
+  ['testString', specialCharacters],
+  ['testByte', 1],
+  ['testByte', 0],
+  ['testByte', -1],
+  ['testByte', -127],
+  ['testI32', -1],
+  ['testDouble', -5.2098523],
+  ['testDouble', 7.012052175215044],
+  ['testEnum', ttypes.Numberz.ONE]
+];
+
+export var simpleLoose = [
+  ['testI64', 5],
+  ['testI64', -5],
+  ['testI64', 734359738368],
+  ['testI64', -34359738368],
+  ['testI64', -734359738368],
+  ['testTypedef', 69]
+]
+
+var mapout: {[key: number]: number; } = {};
+for (var i = 0; i < 5; ++i) {
+  mapout[i] = i-10;
+}
+
+export var deep = [
+  ['testMap', mapout],
+  ['testSet', [1,2,3]],
+  ['testList', [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]],
+  ['testStringMap', mapTestInput]
+];
+
+export var out = new ttypes.Xtruct({
+  string_thing: 'Zero',
+  byte_thing: 1,
+  i32_thing: -3,
+  i64_thing: 1000000
+});
+
+export var out2 = new ttypes.Xtruct2();
+out2.byte_thing = 1;
+out2.struct_thing = out;
+out2.i32_thing = 5;
+
+export var crazy = new ttypes.Insanity({
+  "userMap":{ "5":5, "8":8 },
+  "xtructs":[new ttypes.Xtruct({
+      "string_thing":"Goodbye4",
+      "byte_thing":4,
+      "i32_thing":4,
+      "i64_thing":4
+    }), new ttypes.Xtruct({
+      "string_thing":"Hello2",
+      "byte_thing":2,
+      "i32_thing":2,
+      "i64_thing":2
+    })]
+});
+
+export var insanity: any = {
+  "1":{ "2": crazy, "3": crazy },
+  "2":{ "6":{ "userMap":{}, "xtructs":[] } }
+};
diff --git a/lib/nodets/test/testAll.sh b/lib/nodets/test/testAll.sh
new file mode 100755
index 0000000000..a7c00bfd93
--- /dev/null
+++ b/lib/nodets/test/testAll.sh
@@ -0,0 +1,38 @@
+#! /bin/sh
+
+DIR="$( cd "$( dirname "$0" )" && pwd )"
+
+mkdir -p $DIR/../test-compiled
+
+COMPILEDDIR="$(cd $DIR && cd ../test-compiled && pwd)"
+export NODE_PATH="${DIR}:${DIR}/../../nodejs/lib:${NODE_PATH}"
+
+compile()
+{
+  #generating thrift code
+  ${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node,ts 
${DIR}/../../../test/ThriftTest.thrift
+  ${DIR}/../../../compiler/cpp/thrift -o ${COMPILEDDIR} --gen js:node,ts 
${DIR}/../../../test/ThriftTest.thrift
+
+  tsc --outDir $COMPILEDDIR --project $DIR/tsconfig.json
+}
+compile
+
+testServer()
+{
+  echo "start server $1"
+  RET=0
+  node ${COMPILEDDIR}/server.js $1 &
+  SERVERPID=$!
+  sleep 1
+  echo "start client $1"
+  node ${COMPILEDDIR}/client.js $1 || RET=1
+  kill -2 $SERVERPID || RET=1
+  return $RET
+}
+
+#integration tests
+
+testServer || TESTOK=1
+testServer --promise || TESTOK=1
+
+exit $TESTOK
diff --git a/lib/nodets/test/test_driver.ts b/lib/nodets/test/test_driver.ts
new file mode 100644
index 0000000000..2c4152616e
--- /dev/null
+++ b/lib/nodets/test/test_driver.ts
@@ -0,0 +1,278 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * 'License'); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+ // This is the Node.js test driver for the standard Apache Thrift
+ // test service. The driver invokes every function defined in the
+ // Thrift Test service with a representative range of parameters.
+ //
+ // The ThriftTestDriver function requires a client object
+ // connected to a server hosting the Thrift Test service and
+ // supports an optional callback function which is called with
+ // a status message when the test is complete.
+
+import test = require("tape");
+import ttypes = require("./gen-nodejs/ThriftTest_types");
+import ThriftTest = require("./gen-nodejs/ThriftTest");
+import thrift = require("thrift");
+import Q = thrift.Q;
+import TException = thrift.Thrift.TException;
+var Int64 = require("node-int64");
+import testCases = require("./test-cases");
+
+export function ThriftTestDriver(client: ThriftTest.Client, callback: (status: 
string) => void) {
+
+  test("NodeJS Style Callback Client Tests", function(assert) {
+
+    var checkRecursively = makeRecursiveCheck(assert);
+
+    function makeAsserter(assertionFn: (a: any, b: any, msg?: string) => void) 
{
+      return function(c: (string | any)[]) {
+        var fnName = c[0];
+        var expected = c[1];
+        (<any>client)[fnName](expected, function(err: any, actual: any) {
+          assert.error(err, fnName + ": no callback error");
+          assertionFn(actual, expected, fnName);
+        })
+      };
+    }
+
+    testCases.simple.forEach(makeAsserter(assert.equal));
+    testCases.simpleLoose.forEach(makeAsserter(function(a, e, m){
+      assert.ok(a == e, m);
+    }));
+    testCases.deep.forEach(makeAsserter(assert.deepEqual));
+
+    client.testMapMap(42, function(err, response) {
+      var expected: typeof response = {
+        "4": {"1":1, "2":2, "3":3, "4":4},
+        "-4": {"-4":-4, "-3":-3, "-2":-2, "-1":-1}
+      };
+      assert.error(err, 'testMapMap: no callback error');
+      assert.deepEqual(expected, response, "testMapMap");
+    });
+
+    client.testStruct(testCases.out, function(err, response) {
+      assert.error(err, "testStruct: no callback error");
+      checkRecursively(testCases.out, response, "testStruct");
+    });
+
+    client.testNest(testCases.out2, function(err, response) {
+      assert.error(err, "testNest: no callback error");
+      checkRecursively(testCases.out2, response, "testNest");
+    });
+
+    client.testInsanity(testCases.crazy, function(err, response) {
+      assert.error(err, "testInsanity: no callback error");
+      checkRecursively(testCases.insanity, response, "testInsanity");
+    });
+
+    client.testException("TException", function(err, response) {
+      assert.ok(err instanceof TException, 'testException: correct error 
type');
+      assert.ok(!Boolean(response), 'testException: no response');
+    });
+
+    client.testException("Xception", function(err, response) {
+      assert.ok(err instanceof ttypes.Xception, 'testException: correct error 
type');
+      assert.ok(!Boolean(response), 'testException: no response');
+      assert.equal(err.errorCode, 1001, 'testException: correct error code');
+      assert.equal('Xception', err.message, 'testException: correct error 
message');
+    });
+
+    client.testException("no Exception", function(err, response) {
+      assert.error(err, 'testException: no callback error');
+      assert.ok(!Boolean(response), 'testException: no response');
+    });
+
+    client.testOneway(0, function(err, response) {
+      assert.error(err, 'testOneway: no callback error');
+      assert.strictEqual(response, undefined, 'testOneway: void response');
+    });
+
+    checkOffByOne(function(done) {
+      client.testI32(-1, function(err, response) {
+        assert.error(err, "checkOffByOne: no callback error");
+        assert.equal(-1, response);
+        assert.end();
+        done();
+      });
+    }, callback);
+
+  });
+};
+
+export function ThriftTestDriverPromise(client: ThriftTest.Client, callback: 
(status: string) => void) {
+
+  test("Q Promise Client Tests", function(assert) {
+
+    var checkRecursively = makeRecursiveCheck(assert);
+
+    function fail(msg: string) {
+      return function(error, response) {
+        if (error !== null) {
+          assert.fail(msg);
+        }
+      }
+    }
+
+    function makeAsserter(assertionFn: (a: any, b: any, msg?: string) => void) 
{
+      return function(c: (string | any)[]) {
+        var fnName = c[0];
+        var expected = c[1];
+        (<any>client)[fnName](expected)
+          .then(function(actual: any) {
+            assertionFn(actual, expected, fnName);
+          })
+          .fail(fail("fnName"));
+      };
+    }
+
+    testCases.simple.forEach(makeAsserter(assert.equal));
+    testCases.simpleLoose.forEach(makeAsserter(function(a, e, m){
+      assert.ok(a == e, m);
+    }));
+    testCases.deep.forEach(makeAsserter(assert.deepEqual));
+
+    Q.resolve(client.testStruct(testCases.out))
+      .then(function(response) {
+        checkRecursively(testCases.out, response, "testStruct");
+      })
+      .fail(fail("testStruct"));
+
+    Q.resolve(client.testNest(testCases.out2))
+      .then(function(response) {
+        checkRecursively(testCases.out2, response, "testNest");
+      })
+      .fail(fail("testNest"));
+
+    Q.resolve(client.testInsanity(testCases.crazy))
+      .then(function(response) {
+        checkRecursively(testCases.insanity, response, "testInsanity");
+      })
+      .fail(fail("testInsanity"));
+
+    Q.resolve(client.testException("TException"))
+      .then(function(response) {
+        fail("testException: TException");
+      })
+      .fail(function(err) {
+        assert.ok(err instanceof TException);
+      });
+
+    Q.resolve(client.testException("Xception"))
+      .then(function(response) {
+        fail("testException: Xception");
+      })
+      .fail(function(err) {
+        assert.ok(err instanceof ttypes.Xception);
+        assert.equal(err.errorCode, 1001);
+        assert.equal("Xception", err.message);
+      });
+
+    Q.resolve(client.testException("no Exception"))
+      .then(function(response) {
+        assert.equal(undefined, response); //void
+      })
+      .fail(fail("testException"));
+
+    client.testOneway(0, fail("testOneway: should not answer"));
+
+    checkOffByOne(function(done) {
+      Q.resolve(client.testI32(-1))
+        .then(function(response) {
+            assert.equal(-1, response);
+            assert.end();
+            done();
+        })
+        .fail(fail("checkOffByOne"));
+    }, callback);
+  });
+};
+
+
+// Helper Functions
+// =========================================================
+
+function makeRecursiveCheck(assert: test.Test) {
+
+  return function (map1: any, map2: any, msg: string) {
+    var equal = true;
+
+    var equal = checkRecursively(map1, map2);
+
+    assert.ok(equal, msg);
+
+    // deepEqual doesn't work with fields using node-int64
+    function checkRecursively(map1: any, map2: any) : boolean {
+      if (!(typeof map1 !== "function" && typeof map2 !== "function")) {
+        return false;
+      }
+      if (!map1 || typeof map1 !== "object") {
+        //Handle int64 types (which use node-int64 in Node.js JavaScript)
+        if ((typeof map1 === "number") && (typeof map2 === "object") &&
+            (map2.buffer) && (map2.buffer instanceof Buffer) && 
(map2.buffer.length === 8)) {
+          var n = new Int64(map2.buffer);
+          return map1 === n.toNumber();
+        } else {
+          return map1 == map2;
+        }
+      } else {
+        return Object.keys(map1).every(function(key) {
+          return checkRecursively(map1[key], map2[key]);
+        });
+      }
+    }
+  }
+}
+
+function checkOffByOne(done: (callback: () => void) => void, callback: 
(message: string) => void) {
+
+  var retry_limit = 30;
+  var retry_interval = 100;
+  var test_complete = false;
+  var retrys = 0;
+
+  /**
+   * redo a simple test after the oneway to make sure we aren't "off by one" --
+   * if the server treated oneway void like normal void, this next test will
+   * fail since it will get the void confirmation rather than the correct
+   * result. In this circumstance, the client will throw the exception:
+   *
+   * Because this is the last test against the server, when it completes
+   * the entire suite is complete by definition (the tests run serially).
+   */
+  done(function() {
+    test_complete = true;
+  });
+
+  //We wait up to retry_limit * retry_interval for the test suite to complete
+  function TestForCompletion() {
+    if(test_complete && callback) {
+      callback("Server successfully tested!");
+    } else {
+      if (++retrys < retry_limit) {
+        setTimeout(TestForCompletion, retry_interval);
+      } else if (callback) {
+        callback("Server test failed to complete after " +
+                 (retry_limit * retry_interval / 1000) + " seconds");
+      }
+    }
+  }
+
+  setTimeout(TestForCompletion, retry_interval);
+}
diff --git a/lib/nodets/test/test_handler.ts b/lib/nodets/test/test_handler.ts
new file mode 100644
index 0000000000..1bc855a709
--- /dev/null
+++ b/lib/nodets/test/test_handler.ts
@@ -0,0 +1,299 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * 'License'); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//This is the server side Node test handler for the standard
+//  Apache Thrift test service.
+
+import ttypes = require("./gen-nodejs/ThriftTest_types");
+import thrift = require("thrift");
+import Thrift = thrift.Thrift;
+import Q = require("q");
+
+
+export class SyncThriftTestHandler {
+  testVoid(): Q.IPromise<void> {
+    //console.log('testVoid()');
+    return Q.resolve<void>(undefined);
+  }
+  testMapMap(hello: number) {
+    //console.log('testMapMap(' + hello + ')');
+
+    var mapmap: {[key: number]: {[key: number]: number; }} = [];
+    var pos: {[key: number]: number; } = [];
+    var neg: {[key: number]: number; } = [];
+    for (var i = 1; i < 5; i++) {
+      pos[i] = i;
+      neg[-i] = -i;
+    }
+    mapmap[4] = pos;
+    mapmap[-4] = neg;
+
+    return Q.resolve(mapmap);
+  }
+  testInsanity(argument: ttypes.Insanity): Q.IPromise<{ [k: number]: any; }> {
+    const first_map: { [k: number]: any; } = [];
+    const second_map: { [k: number]: any; } = [];
+  
+    first_map[ttypes.Numberz.TWO] = argument;
+    first_map[ttypes.Numberz.THREE] = argument;
+  
+    const looney = new ttypes.Insanity();
+    second_map[ttypes.Numberz.SIX] = looney;
+  
+    const insane: { [k: number]: any; } = [];
+    insane[1] = first_map;
+    insane[2] = second_map;
+
+    return Q.resolve(insane);
+  }
+  testMulti(arg0: any, arg1: number, arg2: number, arg3: { [k: number]: 
string; }, arg4: ttypes.Numberz, arg5: number) {
+    var hello = new ttypes.Xtruct();
+    hello.string_thing = 'Hello2';
+    hello.byte_thing = arg0;
+    hello.i32_thing = arg1;
+    hello.i64_thing = arg2;
+    return Q.resolve(hello);
+  }
+  testException(arg: string): Q.IPromise<void> {
+    if (arg === 'Xception') {
+      var x = new ttypes.Xception();
+      x.errorCode = 1001;
+      x.message = arg;
+      throw x;
+    } else if (arg === 'TException') {
+      throw new Thrift.TException(arg);
+    } else {
+      return Q.resolve();
+    }
+  }
+  testMultiException(arg0: string, arg1: string) {
+    if (arg0 === ('Xception')) {
+      var x = new ttypes.Xception();
+      x.errorCode = 1001;
+      x.message = 'This is an Xception';
+      throw x;
+    } else if (arg0 === ('Xception2')) {
+      var x2 = new ttypes.Xception2();
+      x2.errorCode = 2002;
+      x2.struct_thing = new ttypes.Xtruct();
+      x2.struct_thing.string_thing = 'This is an Xception2';
+      throw x2;
+    }
+
+    var res = new ttypes.Xtruct();
+    res.string_thing = arg1;
+    return Q.resolve(res);
+  }
+  testOneway(sleepFor: number) {
+  }
+
+  testString(thing: string) {
+    return Q.resolve(thing);
+  }
+  testBool(thing: boolean) {
+    return Q.resolve(thing);
+  }
+  testByte(thing: number) {
+    return Q.resolve(thing);
+  }
+  testI32(thing: number) {
+    return Q.resolve(thing);
+  }
+  testI64(thing: number) {
+    return Q.resolve(thing);
+  }
+  testDouble(thing: number) {
+    return Q.resolve(thing);
+  }
+  testBinary(thing: Buffer) {
+    return Q.resolve(thing);
+  }
+  testStruct(thing: ttypes.Xtruct) {
+    return Q.resolve(thing);
+  }
+  testNest(thing: ttypes.Xtruct2) {
+    return Q.resolve(thing);
+  }
+  testMap(thing: { [k: number]: number; }) {
+    return Q.resolve(thing);
+  }
+  testStringMap(thing: { [k: string]: string; }) {
+    return Q.resolve(thing);
+  }
+  testSet(thing: number[]) {
+    return Q.resolve(thing);
+  }
+  testList(thing: number[]) {
+    return Q.resolve(thing);
+  }
+  testEnum(thing: ttypes.Numberz) {
+    return Q.resolve(thing);
+  }
+  testTypedef(thing: number) {
+    return Q.resolve(thing);
+  }
+}
+
+export class AsyncThriftTestHandler {
+  private syncHandler: SyncThriftTestHandler;
+  constructor() {
+    this.syncHandler = new SyncThriftTestHandler();
+  }
+
+  testVoid(callback: (result: void) => void): Q.IPromise<void> {
+    callback(undefined);
+    return Q.resolve();
+  }
+  testMapMap(hello: number,
+    callback: (err: any, result: { [k: number]: { [k: number]: number; }; }) 
=> void):
+     Q.IPromise<{ [k: number]: { [k: number]: number; }; }> {
+
+    var mapmap: {[key: number]: {[key: number]: number; }} = [];
+    var pos: {[key: number]: number; } = [];
+    var neg: {[key: number]: number; } = [];
+    for (var i = 1; i < 5; i++) {
+      pos[i] = i;
+      neg[-i] = -i;
+    }
+    mapmap[4] = pos;
+    mapmap[-4] = neg;
+
+    callback(null, mapmap);
+    return Q.resolve();
+  }
+  testInsanity(argument: ttypes.Insanity, callback?: (err: any, result: { [k: 
number]: any; }) => void): Q.IPromise<{ [k: number]: any; }> {
+    const first_map: { [k: number]: any; } = [];
+    const second_map: { [k: number]: any; } = [];
+  
+    first_map[ttypes.Numberz.TWO] = argument;
+    first_map[ttypes.Numberz.THREE] = argument;
+  
+    const looney = new ttypes.Insanity();
+    second_map[ttypes.Numberz.SIX] = looney;
+  
+    const insane: { [k: number]: any; } = [];
+    insane[1] = first_map;
+    insane[2] = second_map;
+
+    if (callback !== undefined){
+      callback(null, insane);
+    }
+    return Q.resolve();
+  }
+  testMulti(arg0: any, arg1: number, arg2: number, arg3: { [k: number]: 
string; }, arg4: ttypes.Numberz, arg5: number, result: Function): 
Q.IPromise<ttypes.Xtruct> {
+    var hello = this.syncHandler.testMulti(arg0, arg1, arg2, arg3, arg4, arg5);
+    hello.then(hello => result(null, hello));
+    return Q.resolve();
+  }
+  testException(arg: string, result: (err: any) => void): Q.IPromise<void> {
+    if (arg === 'Xception') {
+      var x = new ttypes.Xception();
+      x.errorCode = 1001;
+      x.message = arg;
+      result(x);
+    } else if (arg === 'TException') {
+      result(new Thrift.TException(arg));
+    } else {
+      result(null);
+    }
+    return Q.resolve();
+  }
+  testMultiException(arg0: string, arg1: string, result: (err: any, res?: 
ttypes.Xtruct) => void): Q.IPromise<ttypes.Xtruct> {
+    if (arg0 === ('Xception')) {
+      var x = new ttypes.Xception();
+      x.errorCode = 1001;
+      x.message = 'This is an Xception';
+      result(x);
+    } else if (arg0 === ('Xception2')) {
+      var x2 = new ttypes.Xception2();
+      x2.errorCode = 2002;
+      x2.struct_thing = new ttypes.Xtruct();
+      x2.struct_thing.string_thing = 'This is an Xception2';
+      result(x2);
+    } else {
+      var res = new ttypes.Xtruct();
+      res.string_thing = arg1;
+      result(null, res);
+    }
+    return Q.resolve();
+  }
+  testOneway(sleepFor: number, result: Function) {
+    this.syncHandler.testOneway(sleepFor);
+  }
+  testString(thing: string, callback: (err: any, result: string) => void): 
Q.IPromise<string> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testByte(thing: number, callback: (err: any, result: number) => void): 
Q.IPromise<number> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testBool(thing: boolean, callback: (err: any, result: boolean) => void ): 
Q.IPromise<boolean> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testI32(thing: number, callback: (err: any, result: number) => void): 
Q.IPromise<number>  {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testI64(thing: number, callback: (err: any, result: number) => void): 
Q.IPromise<number>  {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testDouble(thing: number, callback: (err: any, result: number) => void): 
Q.IPromise<number>  {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testBinary(thing: Buffer, callback: (err: any, result: Buffer) => void): 
Q.IPromise<Buffer> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testStruct(thing: ttypes.Xtruct, callback: (err: any, result: ttypes.Xtruct) 
=> void): Q.IPromise<ttypes.Xtruct> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testNest(thing: ttypes.Xtruct2, callback: (err: any, result: ttypes.Xtruct2) 
=> void): Q.IPromise<ttypes.Xtruct2> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testMap(thing: { [k: number]: number; }, callback: (err: any, result: { [k: 
number]: number; }) => void): Q.IPromise<{ [k: number]: number; }> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testStringMap(thing: { [k: string]: string; }, callback: (err: any, result: 
{ [k: string]: string; }) => void): Q.IPromise<{ [k: string]: string; }> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testSet(thing: number[], callback: (err: any, result: number[]) => void): 
Q.IPromise<number[]> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testList(thing: number[], callback: (err: any, result: number[]) => void): 
Q.IPromise<number[]> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testEnum(thing: ttypes.Numberz, callback: (err: any, result: ttypes.Numberz) 
=> void): Q.IPromise<ttypes.Numberz> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testTypedef(thing: number, callback: (err: any, result: number) => void): 
Q.IPromise<number> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+}
diff --git a/lib/nodets/test/tsconfig.json b/lib/nodets/test/tsconfig.json
new file mode 100644
index 0000000000..029d06d969
--- /dev/null
+++ b/lib/nodets/test/tsconfig.json
@@ -0,0 +1,22 @@
+{
+    "compilerOptions": {
+        "allowJs": false,
+        "alwaysStrict": true,
+        "baseUrl": ".",
+        "declaration": true,
+        "emitDecoratorMetadata": true,
+        "experimentalDecorators": true,
+        "module": "commonjs",
+        "moduleResolution": "node",
+        "noImplicitThis": true,
+        "noUnusedLocals": true,
+        "preserveConstEnums": true,
+        "removeComments": true,
+        "strictFunctionTypes": true,
+        "strictNullChecks": true,
+        "target": "es6",
+        "paths": {
+            "thrift": ["../../nodejs/lib/thrift"]
+        }
+    }
+}
diff --git a/package-lock.json b/package-lock.json
index ea49547f6d..e93b896412 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -24,6 +24,18 @@
         "js-tokens": "^4.0.0"
       }
     },
+    "@types/node": {
+      "version": "10.12.6",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.6.tgz";,
+      "integrity": 
"sha512-+ZWB5Ec1iki99xQFzBlivlKxSZQ+fuUKBott8StBOnLN4dWbRHlgdg1XknpW6g0tweniN5DcOqA64CJyOUPSAw==",
+      "dev": true
+    },
+    "@types/q": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.1.tgz";,
+      "integrity": 
"sha512-eqz8c/0kwNi/OEHQfvIuJVLTst3in0e7uTKeuY+WL/zfKn0xVujOTp42bS/vUUokhK5P2BppLd9JXMOMHcgbjA==",
+      "dev": true
+    },
     "abbrev": {
       "version": "1.0.9",
       "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz";,
@@ -2008,6 +2020,12 @@
         "prelude-ls": "~1.1.2"
       }
     },
+    "typescript": {
+      "version": "3.1.6",
+      "resolved": 
"https://registry.npmjs.org/typescript/-/typescript-3.1.6.tgz";,
+      "integrity": 
"sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA==",
+      "dev": true
+    },
     "uglify-js": {
       "version": "3.4.9",
       "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz";,
diff --git a/package.json b/package.json
index 07607cdb8a..d641979d82 100644
--- a/package.json
+++ b/package.json
@@ -50,11 +50,15 @@
     "jsdoc": "^3.5.5",
     "prettier": "^1.14.3",
     "tape": "^4.9.0",
-    "utf-8-validate": "^4.0.0"
+    "utf-8-validate": "^4.0.0",
+    "typescript": "^3.1.6",
+    "@types/node": "^10.12.6",
+    "@types/q": "^1.5.1"
   },
   "scripts": {
     "cover": "lib/nodejs/test/testAll.sh COVER",
     "test": "lib/nodejs/test/testAll.sh",
+    "test-ts": "lib/nodets/test/testAll.sh",
     "prettier": "prettier --write '**/*.js'",
     "lint": "eslint lib/nodejs/. --ext .js",
     "lint-tests": "eslint lib/nodejs/test/. --ext .js"
diff --git a/test/ThriftTest.thrift b/test/ThriftTest.thrift
index bff4e5221f..3499ab5f86 100644
--- a/test/ThriftTest.thrift
+++ b/test/ThriftTest.thrift
@@ -196,7 +196,7 @@ service ThriftTest
    * @return binary  - returns the binary 'thing'
    */
   binary       testBinary(1: binary thing),
-  
+
   /**
    * Prints 'testStruct("{%s}")' where thing has been formatted into a string 
of comma separated values
    * @param Xtruct thing - the Xtruct to print
diff --git a/test/known_failures_Linux.json b/test/known_failures_Linux.json
index 24ce997fb5..6d3a05e4c1 100644
--- a/test/known_failures_Linux.json
+++ b/test/known_failures_Linux.json
@@ -212,6 +212,7 @@
   "d-nodejs_json_framed-ip-ssl",
   "d-nodejs_json_http-ip",
   "d-nodejs_json_http-ip-ssl",
+  "d-nodets_binary_buffered-ip",
   "d-py3_binary-accel_buffered-ip",
   "d-py3_binary-accel_buffered-ip-ssl",
   "d-py3_binary-accel_framed-ip",
@@ -278,6 +279,7 @@
   "erl-csharp_compact_buffered-ip",
   "erl-nodejs_binary_buffered-ip",
   "erl-nodejs_compact_buffered-ip",
+  "erl-nodets_binary_buffered-ip",
   "erl-rb_binary-accel_buffered-ip",
   "erl-rb_binary-accel_buffered-ip-ssl",
   "erl-rb_binary-accel_framed-ip",
@@ -319,6 +321,7 @@
   "hs-csharp_binary_framed-ip",
   "hs-csharp_compact_buffered-ip",
   "hs-csharp_compact_framed-ip",
+  "hs-nodets_binary_buffered-ip",
   "nodejs-cpp_binary_http-domain",
   "nodejs-cpp_binary_http-ip",
   "nodejs-cpp_binary_http-ip-ssl",
diff --git a/test/tests.json b/test/tests.json
index 27e75cc218..b70dbd8563 100644
--- a/test/tests.json
+++ b/test/tests.json
@@ -718,5 +718,32 @@
       "multic"
     ],
     "workdir": "rs/bin"
+  },
+  {
+    "name": "nodets",
+    "env": {
+      "NODE_PATH": "../lib"
+    },
+    "server": {
+      "command": [
+        "runServer.sh"
+      ]
+    },
+    "client": {
+      "timeout": 5,
+      "command": [
+        "runClient.sh"
+      ]
+    },
+    "protocols": [
+      "binary"
+    ],
+    "sockets": [
+      "ip"
+    ],
+    "transports": [
+      "buffered"
+    ],
+    "workdir": "../lib/nodets/test"
   }
 ]


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


> add typescript directory support
> --------------------------------
>
>                 Key: THRIFT-3143
>                 URL: https://issues.apache.org/jira/browse/THRIFT-3143
>             Project: Thrift
>          Issue Type: New Feature
>          Components: Node.js - Compiler
>            Reporter: Kazuki Yasufuku
>            Priority: Major
>
> Current typescript support is only work for browser, and generated d.ts uses 
> internal module.
> So, it's hard to use for typescript in node.js.
> To solve probrem, I make a pull request that generate typescript code 
> directory.



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to