Skip to content

Commit

Permalink
THRIFT-3143: Add nodets support
Browse files Browse the repository at this point in the history
Co-authored-by: Mustafa Senol Cosar <[email protected]>
  • Loading branch information
2 people authored and jeking3 committed Nov 29, 2018
1 parent 7f0fa6c commit 2c69b5a
Show file tree
Hide file tree
Showing 21 changed files with 1,130 additions and 22 deletions.
2 changes: 1 addition & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
151 changes: 132 additions & 19 deletions compiler/cpp/src/thrift/generate/t_js_generator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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";
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);

/**
Expand All @@ -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.
Expand Down Expand Up @@ -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_) {
Expand Down Expand Up @@ -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
*/
Expand Down Expand Up @@ -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_) {
Expand Down Expand Up @@ -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_) {
Expand Down Expand Up @@ -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;
}

}
}

Expand Down Expand Up @@ -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_ << " {";
}
Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -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;
}
}

/**
Expand All @@ -1201,14 +1271,18 @@ 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 {
indent(f_service_) << js_namespace(tservice->get_program()) << service_name_
<< "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();

Expand Down Expand 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";
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}

Expand Down Expand Up @@ -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;
Expand All @@ -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()) +">;";
Expand Down
18 changes: 18 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -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]]),
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions lib/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ endif
if WITH_NODEJS
SUBDIRS += nodejs
PRECROSS_TARGET += precross-nodejs
SUBDIRS += nodets
endif

if WITH_LUA
Expand Down
1 change: 1 addition & 0 deletions lib/nodets/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test-compiled/
Loading

0 comments on commit 2c69b5a

Please sign in to comment.