diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c769a5..c021bdf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ set(CMAKE_VERBOSE_MAKEFILE off) # version set(TARS_VERSION "1.1.0") set(PARSER_VERSION "${TARS_VERSION}") -set(GENERATOR_VERSION "20190109") +set(GENERATOR_VERSION "20190320") # namespace set(IDL_NAMESPACE Tars) @@ -21,8 +21,8 @@ set(IDL_TYPE "Tars") set(PROTOCOL_NAME "Tup") # flag -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g -O2 -Wall -Wno-sign-compare -Wno-unused-result") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O2 -Wall") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g -O2 -Wall -Wno-sign-compare -Wno-unused-result -static") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O2 -Wall -static") # define add_definitions(-DTARS_VERSION="${TARS_VERSION}") diff --git a/README.md b/README.md index 0c58c32..848e439 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ tars2node [OPTIONS] tarsfile | --r-reserved | 精简依赖文件时需保留的成员。| | --client | 生成客户端的调用类代码。| | --server | 生成服务端的框架代码。| +| --ts | 打开此选项将后将只生成 TypeScript (.ts) 代码。| | --dts | 生成时附加 TypeScript 描述文件(.d.ts)。| | --use-string-represent | 当需要保持 类型的精度时,打开此选项使用 \ 存储 \。| | --string-binary-encoding | 遇到字符编码问题或需对原始数据进行存取时,打开此选项使用 \ 存储 \。| diff --git a/build/tars2node b/build/tars2node index ea9f489..a5ef43a 100755 Binary files a/build/tars2node and b/build/tars2node differ diff --git a/src/code_generator.cpp b/src/code_generator.cpp index adf8dec..7fbf163 100644 --- a/src/code_generator.cpp +++ b/src/code_generator.cpp @@ -22,7 +22,7 @@ string CodeGenerator::printHeaderRemark(const string &sTypeName) s << "// **********************************************************************" << endl; s << "// Parsed By " << IDL_NAMESPACE_STR << "Parser(" << PARSER_VERSION << "), Generated By " << EXECUTE_FILENAME << "(" << GENERATOR_VERSION << ")" << endl; s << "// " << IDL_NAMESPACE_STR << "Parser Maintained By <" << TC_Common::upper(IDL_NAMESPACE_STR) << "> and " << EXECUTE_FILENAME << " Maintained By " << endl; - s << "// Generated from \"" << TC_File::extractFileName(_sIdlFile) << "\" by " << + s << "// Generated from \"" << TC_File::extractFileName(_sIdlFile) << "\" by " << (_bEntry ? sTypeName : (_bMinimalMembers ? "Minimal" : "Relation")) << " Mode" << endl; s << "// **********************************************************************" << endl; s << endl; @@ -53,26 +53,47 @@ void CodeGenerator::createFile(const string &file, const bool bEntry) { if (_sIdlFile == contexts[i]->getFileName()) { - scan(_sIdlFile, true); //分析枚举值、结构体所在的文件 + scan(_sIdlFile, true); // collect idl symbols - if (!_bClient && !_bServer) + if (!_bClient && !_bServer) { - generateJS(contexts[i]); //生成当前文件的编解码文件 - if(_bDTS) generateDTS(contexts[i]); //生成 typescript 描述文件 + if (_bTS) + { + generateTS(contexts[i]); // generate .ts + } + else + { + generateJS(contexts[i]); // generate .js + if (_bDTS) generateDTS(contexts[i]); // generate .d.ts + } } - if (_bClient) + if (_bClient) { - if(!generateJSProxy(contexts[i])) return; //生成当前文件的客户端代理类文件 - if(_bDTS) generateDTSProxy(contexts[i]); //生成客户端 typescript 描述文件 + if (_bTS) + { + if (!generateTSProxy(contexts[i])) return; // generate .ts for proxy classes + } + else + { + if (!generateJSProxy(contexts[i])) return; // generate .js for proxy classes + if (_bDTS) generateDTSProxy(contexts[i]); // generate .d.ts for proxy classes + } } if (_bServer) { - if(!generateJSServer(contexts[i])) return; //生成当前文件的服务端代理类文件 - if(_bDTS) generateDTSServer(contexts[i]); //生成服务端 typescript 描述文件 - - generateJSServerImp(contexts[i]); //生成当前文件的服务端实现类文件 + if (_bTS) + { + if (!generateTSServer(contexts[i])) return; // generate .ts for server classes + generateTSServerImp(contexts[i]); // generate .ts for server implementations + } + else + { + if (!generateJSServer(contexts[i])) return; // generate .js for server classes + if (_bDTS) generateDTSServer(contexts[i]); // generate .d.ts for server classes + generateJSServerImp(contexts[i]); // generate .js for server implementations + } } vector files = contexts[i]->getIncludes(); @@ -88,10 +109,11 @@ void CodeGenerator::createFile(const string &file, const bool bEntry) node.setStringBinaryEncoding(_bStringBinaryEncoding); node.setMinimalMembers(_bMinimalMembers); node.setDependent(_depMembers); + node.setEnableTS(_bTS); node.setEnableDTS(_bDTS); node.createFile(files[ii], false); } } } -} \ No newline at end of file +} diff --git a/src/code_generator.h b/src/code_generator.h new file mode 100644 index 0000000..a37d42d --- /dev/null +++ b/src/code_generator.h @@ -0,0 +1,322 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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. + */ + +#ifndef _CODEGENERATOR_H +#define _CODEGENERATOR_H + +#include "parse.h" +#include "util/tc_file.h" +#include "util/tc_encoder.h" +#include + +#ifndef TAB + #define TAB g_parse->getTab() +#endif + +#ifndef INC_TAB + #define INC_TAB g_parse->incTab() +#endif + +#ifndef DEL_TAB + #define DEL_TAB g_parse->delTab() +#endif + +#define TO_LOWER_STRING(str) TC_Common::lower(str) + +#define DEFINE_STRING(str) string(CSTR(str)) +#define CSTR(str) #str +#define IDL_NAMESPACE_STR DEFINE_STRING(IDL_NAMESPACE) + +#define GET_CONST_GRAMMAR_PTR_V(name, ptr) \ + ptr->getConst##name##Ptr() +#define GET_CONST_GRAMMAR_PTR_BASE(name, ptr) \ + GET_CONST_GRAMMAR_PTR_V(name, ptr) +#define GET_CONST_GRAMMAR_PTR(ptr) \ + GET_CONST_GRAMMAR_PTR_BASE(GRAMMAR_NAME, ptr) + +#define CONST_GRAMMAR_V(name, val) \ + Const##name::val +#define CONST_GRAMMAR_BASE(name, val) \ + CONST_GRAMMAR_V(name, val) +#define CONST_GRAMMAR(val) \ + CONST_GRAMMAR_BASE(GRAMMAR_NAME, val) + +#define PROTOCOL_V(space, protocol, type) \ + space + "Stream." + protocol + "." + TC_Common::upper(protocol) + "_" + type +#define PROTOCOL_SIMPLE PROTOCOL_V(IDL_NAMESPACE_STR, PROTOCOL_NAME, "SIMPLE") +#define PROTOCOL_COMPLEX PROTOCOL_V(IDL_NAMESPACE_STR, PROTOCOL_NAME, "COMPLEX") +#define PROTOCOL_VAR TO_LOWER_STRING(PROTOCOL_NAME) + +#define DISABLE_ESLINT "/* eslint-disable */" +#define DISABLE_TSLINT "/* tslint:disable */" + +using namespace TC_NAMESPACE; + +class CodeGenerator +{ +public: + CodeGenerator() + : uiNameIndex(0), + _sRpcPath(RPC_MODULE_PATH), + _sStreamPath(STREAM_MODULE_PATH), + _sToPath("./"), + _bClient(false), + _bServer(false), + _bRecursive(false), + _bUseSpecialPath(false), + _bUseStringRepresent(false), + _bStringBinaryEncoding(false), + _bEnumReverseMappings(false), + _bMinimalMembers(false), + _bTS(false), + _bDTS(false), + _iOptimizeLevel(O0) {} + + void createFile(const string& file, const bool bEntry = true); + + void setRpcPath(const string& sPath) { _sRpcPath = sPath; } + + void setStreamPath(const string& sPath) { _sStreamPath = sPath; } + + void setEnableClient(bool bEnable) { _bClient = bEnable; } + + void setEnableServer(bool bEnable) { _bServer = bEnable; } + + void setTargetPath(const string& sPath) { _sToPath = sPath + "/"; } + + void setRecursive(bool bEnable) { _bRecursive = bEnable; } + + void setUseSpecialPath(bool bEnable) { _bUseSpecialPath = bEnable; } + + void setUseStringRepresent(bool bEnable) { _bUseStringRepresent = bEnable; } + + void setStringBinaryEncoding(bool bEnable) { _bStringBinaryEncoding = bEnable; } + + void setEnumReverseMappings(bool bEnable) { _bEnumReverseMappings = bEnable; } + + void setMinimalMembers(bool bEnable) { _bMinimalMembers = bEnable; } + + void setDependent(set& deps) { _depMembers = deps; } + + void setEnableTS(bool bEnable) { _bTS = bEnable; } + + void setEnableDTS(bool bEnable) { _bDTS = bEnable; } + + void setOptimize(int iLevel) { _iOptimizeLevel = iLevel; } + + enum OPTIMIZE_LEVEL {O0 = 0, Os}; + +private: + struct ImportFileType + { + enum TYPE_T {EN_ENUM = 10000, EN_ENUM_VALUE, EN_STRUCT}; + int iType; + string sNamespace; + string sTypeName; + string sName; + }; + + struct ImportFile + { + string sFile; + string sModule; + map mapVars; + }; + + uint32_t uiNameIndex; + + map _mapFiles; + + set _depMembers; + + void scan(const string & sFile, bool bNotPrefix); + + string makeName(); + + string findName(const string & sNamespace, const string & sName, const bool &bBase = false); + +private: + string toFunctionName(const TypeIdPtr & pPtr, const string &sAction); + + string getDataType(const TypePtr& pPtr, const bool &bCastEnumAsAny = false); + + string getClassName(const TypePtr& pPtr); + + string getTsType(const TypePtr &pPtr, const bool bStream = true, const bool bBase = false); + + string getDefault(const TypeIdPtr & pPtr, const string &sDefault, const string & sNamespace); + + string getDefault(const TypeIdPtr & pPtr, const string &sDefault, const string & sNamespace, const bool bGlobal); + +private: + string generateJS(const StructPtr &pPtr, const string &sNamespace, bool &bNeedAssert, bool &bQuickFunc); + + string generateJS(const ConstPtr &pPtr, const string &sNamespace, bool &bNeedStream); + + string generateJS(const EnumPtr &pPtr, const string &sNamespace); + + string generateJS(const NamespacePtr &pPtr, bool &bNeedStream, bool &bNeedAssert, bool &bQuickFunc); + + bool generateJS(const ContextPtr &pPtr); + +private: + string generateTS(const StructPtr &pPtr, const string &sNamespace, bool &bNeedAssert, bool &bQuickFunc); + + string generateTS(const ConstPtr &pPtr, const string &sNamespace, bool &bNeedStream); + + string generateTS(const EnumPtr &pPtr, const string &sNamespace); + + string generateTS(const NamespacePtr &pPtr, bool &bNeedStream, bool &bNeedAssert, bool &bQuickFunc); + + string generateTS(const NamespacePtr &pPtr, const string &sContent); + + void generateTS(const ContextPtr &cPtr); + +private: + string generateJSProxy(const NamespacePtr &nPtr, bool &bNeedRpc, bool &bNeedStream); + + string generateJSProxy(const NamespacePtr &nPtr, const InterfacePtr &pPtr); + + string generateJSProxy(const NamespacePtr &nPtr, const InterfacePtr &pPtr, const OperationPtr &oPtr); + + bool generateJSProxy(const ContextPtr &pPtr); + +private: + string generateTSProxy(const NamespacePtr &pPtr, bool &bNeedStream, bool &bNeedRpc); + + string generateTSProxy(const NamespacePtr &nPtr, const InterfacePtr &pPtr); + + string generateTSProxy(const NamespacePtr &nPtr, const InterfacePtr &pPtr, const OperationPtr &oPtr); + + bool generateTSProxy(const ContextPtr &pPtr); + +private: + string generateJSServer(const NamespacePtr &pPtr, bool &bNeedStream, bool &bNeedRpc, bool &bNeedAssert); + + string generatePing(const NamespacePtr &nPtr, const InterfacePtr &pPtr); + + string generateAsync(const NamespacePtr &nPtr, const InterfacePtr &pPtr, const OperationPtr &oPtr); + + string generateDispatch(const NamespacePtr &nPtr, const InterfacePtr &pPtr, const OperationPtr &oPtr); + + string generateJSServer(const NamespacePtr &nPtr, const InterfacePtr &pPtr, const OperationPtr &oPtr); + + string generateJSServer(const InterfacePtr &pPtr, const NamespacePtr &nPtr); + + bool generateJSServer(const ContextPtr &pPtr); + +private: + string generateTSServerAsync(const NamespacePtr &nPtr, const InterfacePtr &pPtr, const OperationPtr &oPtr); + + string generateTSServerDispatch(const NamespacePtr &nPtr, const InterfacePtr &pPtr, const OperationPtr &oPtr); + + string generateTSServer(const NamespacePtr &pPtr, bool &bNeedStream, bool &bNeedRpc, bool &bNeedAssert); + + string generateTSServer(const InterfacePtr &pPtr, const NamespacePtr &nPtr); + + bool generateTSServer(const ContextPtr &pPtr); + +private: + string generateJSServerImp(const NamespacePtr &nPtr, const InterfacePtr &pPtr, const OperationPtr &oPtr); + + string generateJSServerImp(const NamespacePtr &nPtr, const InterfacePtr &pPtr); + + string generateJSServerImp(const ContextPtr &cPtr, const NamespacePtr &nPtr); + + void generateJSServerImp(const ContextPtr &cPtr); + +private: + void generateTSServerImp(const ContextPtr &cPtr); + +private: + string generateDTS(const StructPtr &pPtr, const string &sNamespace); + + string generateDTS(const ConstPtr &pPtr, const string &sNamespace, bool &bNeedStream); + + string generateDTS(const EnumPtr &pPtr, const string &sNamespace); + + string generateDTS(const NamespacePtr &pPtr, bool &bNeedStream); + + string generateDTS(const NamespacePtr &pPtr, const string &sContent); + + void generateDTS(const ContextPtr &cPtr); + +private: + string generateDTSServer(const NamespacePtr &pPtr, bool &bNeedStream, bool &bNeedRpc); + + string generateDTSServer(const NamespacePtr &nPtr, const InterfacePtr &pPtr); + + void generateDTSServer(const ContextPtr &cPtr); + +private: + string generateDTSProxy(const InterfacePtr &pPtr); + + string generateDTSProxy(const NamespacePtr &pPtr, bool &bNeedStream, bool &bNeedRpc); + + void generateDTSProxy(const ContextPtr &pPtr); + +private: + void makeUTF8File(const string & sFileName, const string & sFileContent); + + bool isSimple(const TypePtr & pPtr) const; + + bool isBinBuffer(const TypePtr & pPtr) const; + + bool isRawOrString(const TypePtr & pPtr) const; + + bool isDependent(const string & sNamespace, const string & sName) const; + + string getRealFileInfo(const string & sPath); + + string printHeaderRemark(const string &sTypeName); + + string printHeaderRemark(const string &sTypeName, const string &sSuffix); + +private: + string _sRpcPath; + + string _sStreamPath; + + string _sToPath; + + bool _bClient; + + bool _bServer; + + bool _bRecursive; + + bool _bUseSpecialPath; + + bool _bUseStringRepresent; + + bool _bStringBinaryEncoding; + + bool _bEnumReverseMappings; + + bool _bMinimalMembers; + + bool _bEntry; + + string _sIdlFile; + + bool _bTS; + + bool _bDTS; + + int _iOptimizeLevel; +}; + +#endif diff --git a/src/gen_js.cpp b/src/gen_js.cpp index c0aec9c..55519bd 100644 --- a/src/gen_js.cpp +++ b/src/gen_js.cpp @@ -73,7 +73,6 @@ string CodeGenerator::generateJS(const EnumPtr &pPtr, const string &sNamespace) s << TAB << "};" << endl; } - //函数 s << TAB << sNamespace << "." << pPtr->getId() << "._classname = \"" << sNamespace << "." << pPtr->getId() << "\";" << endl; s << TAB << sNamespace << "." << pPtr->getId() << "._write = function(os, tag, val) { return os.writeInt32(tag, val); };" << endl; s << TAB << sNamespace << "." << pPtr->getId() << "._read = function(is, tag, def) { return is.readInt32(tag, true, def); };" << endl; @@ -390,7 +389,7 @@ bool CodeGenerator::generateJS(const ContextPtr &pPtr) } } - //先生成编解码体 + // generate encoders and decoders ostringstream estr; bool bNeedAssert = false; bool bNeedStream = false; @@ -404,7 +403,7 @@ bool CodeGenerator::generateJS(const ContextPtr &pPtr) return false; } - //再生成导入模块 + // generate module imports ostringstream ostr; for (map::iterator it = _mapFiles.begin(); it != _mapFiles.end(); it++) { @@ -415,7 +414,7 @@ bool CodeGenerator::generateJS(const ContextPtr &pPtr) ostr << "var " << it->second.sModule << " = require(\"" << it->second.sFile << "\");" << endl; } - //生成文件内容 + // concat generated code ostringstream sstr; sstr << printHeaderRemark("Structure", DISABLE_ESLINT); sstr << "\"use strict\";" << endl << endl; diff --git a/src/gen_js_dts.cpp b/src/gen_js_dts.cpp index 7201f7f..b3ce118 100644 --- a/src/gen_js_dts.cpp +++ b/src/gen_js_dts.cpp @@ -24,7 +24,6 @@ string CodeGenerator::generateDTS(const EnumPtr &pPtr, const string &sNamespace) s << TAB << (_bEnumReverseMappings ? "enum " : "const enum ") << pPtr->getId() << " {" << endl; INC_TAB; - //成员变量 int nenum = -1; bool bDependent = false; vector& member = pPtr->getAllMemberPtr(); @@ -39,7 +38,7 @@ string CodeGenerator::generateDTS(const EnumPtr &pPtr, const string &sNamespace) { nenum++; } - s << TAB << "\"" << member[i]->getId() << "\" = " << TC_Common::tostr(nenum) << ((i < member.size() - 1) ? "," : "") << endl; + s << TAB << member[i]->getId() << " = " << TC_Common::tostr(nenum) << ((i < member.size() - 1) ? "," : "") << endl; } DEL_TAB; @@ -67,8 +66,8 @@ string CodeGenerator::generateDTS(const ConstPtr &pPtr, const string &sNamespace } INC_TAB; - s << TAB << "const " << pPtr->getTypeIdPtr()->getId() << ":" - << getDtsType(pPtr->getTypeIdPtr()->getTypePtr()) << ";" + s << TAB << "const " << pPtr->getTypeIdPtr()->getId() << ":" + << getTsType(pPtr->getTypeIdPtr()->getTypePtr()) << ";" << endl; DEL_TAB; return s.str(); @@ -81,37 +80,17 @@ string CodeGenerator::generateDTS(const StructPtr &pPtr, const string &sNamespac return ""; } - string sStructName = pPtr->getId() + "$OBJ"; vector &member = pPtr->getAllMemberPtr(); INC_TAB; - ostringstream istr; - bool bNever = false; - istr << TAB << "interface " << sStructName << " {" << endl; - INC_TAB; - for (size_t i = 0; i < member.size(); i++) - { - const string &sType = getDtsType(member[i]->getTypePtr(), false); - if (!sType.empty()) - { - istr << TAB << (member[i]->getId()) << (member[i]->isRequire()?": ":"?: ") << sType << ";" << endl; - } - else - { - bNever = true; - } - } - DEL_TAB; - istr << TAB << "}" << endl; - ostringstream s; s << TAB << "class " << pPtr->getId() << " {" << endl; INC_TAB; - + for (size_t i = 0; i < member.size(); i++) { - s << TAB << (member[i]->getId()) << (member[i]->isRequire()?": ":"?: ") << getDtsType(member[i]->getTypePtr()) << ";" << endl; + s << TAB << (member[i]->getId()) << ": " << getTsType(member[i]->getTypePtr()) << ";" << endl; } if (member.size() > 0) { @@ -122,19 +101,31 @@ string CodeGenerator::generateDTS(const StructPtr &pPtr, const string &sNamespac * Size Optimize: * Remove support. * Remove toBinBuffer, readFromObject, toObject, new, create members. - */ + */ if (_iOptimizeLevel != Os) { - s << TAB << "toObject(): " << (bNever ? "never" : sStructName) << ";" << endl; - s << TAB << "readFromObject(json: " << sStructName << "): " << pPtr->getId() << ";" << endl; + s << TAB << "toObject(): " << pPtr->getId() << ".Object;" << endl; + s << TAB << "readFromObject(json: " << pPtr->getId() << ".Object): " << pPtr->getId() << ";" << endl; s << TAB << "toBinBuffer(): " << IDL_NAMESPACE_STR << "Stream.BinBuffer;" << endl; s << TAB << "static new(): " << pPtr->getId() << ";" << endl; s << TAB << "static create(is: " << IDL_NAMESPACE_STR << "Stream." << IDL_TYPE << "InputStream): " << pPtr->getId() << ";" << endl; } DEL_TAB; - s << TAB << "}" << endl; + s << TAB << "}" << endl << endl; - s << istr.str(); + s << TAB << "namespace " << pPtr->getId() << " {" << endl; + INC_TAB; + s << TAB << "interface Object {" << endl; + INC_TAB; + for (size_t i = 0; i < member.size(); i++) + { + const string &sType = getTsType(member[i]->getTypePtr(), false); + s << TAB << (member[i]->getId()) << (member[i]->isRequire() ? ": " : "?: ") << (!sType.empty() ? sType : "never") << ";" << endl; + } + DEL_TAB; + s << TAB << "}" << endl; + DEL_TAB; + s << TAB << "}" << endl; DEL_TAB; @@ -143,7 +134,7 @@ string CodeGenerator::generateDTS(const StructPtr &pPtr, const string &sNamespac string CodeGenerator::generateDTS(const NamespacePtr &pPtr, bool &bNeedStream) { - //结构 + // struct ostringstream sstr; vector ss(pPtr->getAllStructPtr()); for (size_t last = 0; last != ss.size() && ss.size() != 0;) @@ -152,19 +143,19 @@ string CodeGenerator::generateDTS(const NamespacePtr &pPtr, bool &bNeedStream) for (vector::iterator iter=ss.begin(); iter!=ss.end();) { string str = generateDTS(*iter, pPtr->getId()); - if (!str.empty()) + if (!str.empty()) { sstr << str << endl; iter = ss.erase(iter); - } - else + } + else { iter++; } } } - //常量 + // const ostringstream cstr; vector &cs = pPtr->getAllConstPtr(); for (size_t i = 0; i < cs.size(); i++) @@ -172,7 +163,7 @@ string CodeGenerator::generateDTS(const NamespacePtr &pPtr, bool &bNeedStream) cstr << generateDTS(cs[i], pPtr->getId(), bNeedStream); } - //枚举 + // enum ostringstream estr; vector &es = pPtr->getAllEnumPtr(); for (size_t i = 0; i < es.size(); i++) @@ -207,8 +198,8 @@ string CodeGenerator::generateDTS(const NamespacePtr &pPtr, const string &sConte void CodeGenerator::generateDTS(const ContextPtr &pPtr) { vector namespaces = pPtr->getNamespaces(); - - //先生成编解码体 + + // generate encoders and decoders ostringstream estr; bool bNeedStream = false; for (size_t i = 0; i < namespaces.size(); i++) @@ -220,7 +211,7 @@ void CodeGenerator::generateDTS(const ContextPtr &pPtr) return; } - //再生成导入模块 + // generate module imports ostringstream ostr; if (bNeedStream) { @@ -230,13 +221,13 @@ void CodeGenerator::generateDTS(const ContextPtr &pPtr) for (map::iterator it = _mapFiles.begin(); it != _mapFiles.end(); it++) { if (it->second.sModule.empty()) continue; - + if (estr.str().find(it->second.sModule + ".") == string::npos) continue; ostr << "import * as " << it->second.sModule << " from \"" << TC_File::excludeFileExt(it->second.sFile) << "\";" << endl; } - //生成文件内容 + // concat generated code ostringstream sstr; sstr << printHeaderRemark("Structure", DISABLE_TSLINT); sstr << ostr.str() << endl; @@ -246,4 +237,4 @@ void CodeGenerator::generateDTS(const ContextPtr &pPtr) TC_File::makeDirRecursive(_sToPath, 0755); makeUTF8File(sFileName, sstr.str()); -} \ No newline at end of file +} diff --git a/src/gen_proxy.cpp b/src/gen_proxy.cpp index 7b1c37e..f4f8dc0 100644 --- a/src/gen_proxy.cpp +++ b/src/gen_proxy.cpp @@ -51,7 +51,7 @@ string CodeGenerator::generateJSProxy(const NamespacePtr &nPtr, const InterfaceP sParams += (sParams.empty()?"":", ") + vParamDecl[i]->getTypeIdPtr()->getId(); } - //SETP01 生成函数声明(Interface = IF) + // generate function metadata (SharedFunctionInfo) str << TAB << "var __" << nPtr->getId() << "_" << pPtr->getId() << "$" << oPtr->getId() << "$IF = {" << endl; INC_TAB; @@ -88,7 +88,7 @@ string CodeGenerator::generateJSProxy(const NamespacePtr &nPtr, const InterfaceP str << TAB << "};" << endl << endl; - //SETP02 生成 IDL 编码接口(IDL Encoder = IE) + // generate IDL Encoder ($IE) str << TAB << "var __" << nPtr->getId() << "_" << pPtr->getId() << "$" << oPtr->getId() << "$IE = function (" << sParams << ") {" << endl; INC_TAB; @@ -103,7 +103,7 @@ string CodeGenerator::generateJSProxy(const NamespacePtr &nPtr, const InterfaceP << (i + 1) << ", " << vParamDecl[i]->getTypeIdPtr()->getId() << (isRawOrString(vParamDecl[i]->getTypeIdPtr()->getTypePtr()) ? ", 1" : "") << ");" << endl; - // 写入 Dependent 列表 + // push the symbol into dependent list getDataType(vParamDecl[i]->getTypeIdPtr()->getTypePtr()); } @@ -113,7 +113,7 @@ string CodeGenerator::generateJSProxy(const NamespacePtr &nPtr, const InterfaceP str << TAB << "};" << endl << endl; - //STEP03 生成 IDL 解码函数(IDL Decoder = ID) + // generate IDL Decoder ($ID) str << TAB << "var __" << nPtr->getId() << "_" << pPtr->getId() << "$" << oPtr->getId() << "$ID = function (data) {" << endl; INC_TAB; str << TAB << "try {" << endl; @@ -205,7 +205,7 @@ string CodeGenerator::generateJSProxy(const NamespacePtr &nPtr, const InterfaceP DEL_TAB; str << TAB << "};" << endl << endl; - //SETP04 生成 Protocol 编码接口(Protocol Encoder = PE) + // generate Protocol Encoder ($PE) str << TAB << "var __" << nPtr->getId() << "_" << pPtr->getId() << "$" << oPtr->getId() << "$PE = function (" << sParams << (sParams.empty() ? "" : ", ") << "__$PROTOCOL$VERSION) {" << endl; @@ -223,7 +223,7 @@ string CodeGenerator::generateJSProxy(const NamespacePtr &nPtr, const InterfaceP << vParamDecl[i]->getTypeIdPtr()->getId() << "\", " << vParamDecl[i]->getTypeIdPtr()->getId() << (isRawOrString(vParamDecl[i]->getTypeIdPtr()->getTypePtr()) ? ", 1" : "") << ");" << endl; - // 写入 Dependent 列表 + // push the symbol into dependent list getDataType(vParamDecl[i]->getTypeIdPtr()->getTypePtr()); } @@ -231,7 +231,7 @@ string CodeGenerator::generateJSProxy(const NamespacePtr &nPtr, const InterfaceP DEL_TAB; str << TAB << "};" << endl << endl; - // STEP05 生成 Protocol 解码函数(Protocol Decoder = PD) + // generate Protocol Decoder ($PD) str << TAB << "var __" << nPtr->getId() << "_" << pPtr->getId() << "$" << oPtr->getId() << "$PD = function (data) {" << endl; INC_TAB; str << TAB << "try {" << endl; @@ -314,7 +314,7 @@ string CodeGenerator::generateJSProxy(const NamespacePtr &nPtr, const InterfaceP str << TAB << "};" << endl << endl; - //STEP03 生成框架调用错误处理函数(Error Response = ER) + // generate error handler ($ER) str << TAB << "var __" << nPtr->getId() << "_" << pPtr->getId() << "$" << oPtr->getId() << "$ER = function (data) {" << endl; INC_TAB; str << TAB << "throw _makeError(data, \"Call " << pPtr->getId() << "::" << oPtr->getId() << " failed\");" << endl; @@ -322,7 +322,7 @@ string CodeGenerator::generateJSProxy(const NamespacePtr &nPtr, const InterfaceP str << TAB << "};" << endl << endl; - //SETP04 生成函数接口 + // generate function body str << TAB << nPtr->getId() << "." << pPtr->getId() << "Proxy.prototype." << oPtr->getId() << " = function (" << sParams << ") {" << endl; @@ -344,7 +344,7 @@ string CodeGenerator::generateJSProxy(const NamespacePtr &nPtr, const InterfaceP str << TAB << "};" << endl; - //SETP05 绑定函数声明 + // add the function into the prototype of the proxy class str << TAB << nPtr->getId() << "." << pPtr->getId() << "Proxy." << oPtr->getId() << " = " << "__" << nPtr->getId() << "_" << pPtr->getId() << "$" << oPtr->getId() << "$IF;" << endl; @@ -445,7 +445,7 @@ bool CodeGenerator::generateJSProxy(const ContextPtr &cPtr) } } - //先生成编解码 + 代理类 + // generate proxy classes with encoders and decoders ostringstream estr; bool bNeedAssert = false; bool bNeedStream = false; @@ -466,7 +466,7 @@ bool CodeGenerator::generateJSProxy(const ContextPtr &cPtr) return false; } - //再生成导入模块 + // generate module imports ostringstream ostr; for (map::iterator it = _mapFiles.begin(); it != _mapFiles.end(); it++) { @@ -477,7 +477,7 @@ bool CodeGenerator::generateJSProxy(const ContextPtr &cPtr) ostr << "var " << it->second.sModule << " = require(\"" << it->second.sFile << "\");" << endl; } - //生成文件内容 + // concat generated code ostringstream sstr; sstr << printHeaderRemark("Client", DISABLE_ESLINT); sstr << "\"use strict\";" << endl << endl; @@ -496,7 +496,7 @@ bool CodeGenerator::generateJSProxy(const ContextPtr &cPtr) sstr << ostr.str() << endl; - //生成帮助函数 + // generate helper functions if (bQuickFunc) { sstr << "var _hasOwnProperty = Object.prototype.hasOwnProperty;" << endl; diff --git a/src/gen_proxy_dts.cpp b/src/gen_proxy_dts.cpp index 82f0696..9b54d22 100644 --- a/src/gen_proxy_dts.cpp +++ b/src/gen_proxy_dts.cpp @@ -16,35 +16,6 @@ #include "code_generator.h" -string CodeGenerator::generateDTSProxyInfo() -{ - ostringstream str; - - INC_TAB; - - // Argument - str << TAB << "interface SharedArgumentInfo {" << endl; - INC_TAB; - str << TAB << "name: string;" << endl; - str << TAB << "class: string;" << endl; - str << TAB << "direction: 'in' | 'out';" << endl; - DEL_TAB; - str << TAB << "}" << endl; - - // Function - str << TAB << "interface SharedFunctionInfo {" << endl; - INC_TAB; - str << TAB << "name: string;" << endl; - str << TAB << "return: string;" << endl; - str << TAB << "arguments: SharedArgumentInfo[];" << endl; - DEL_TAB; - str << TAB << "}" << endl; - - DEL_TAB; - - return str.str(); -} - string CodeGenerator::generateDTSProxy(const InterfacePtr &pPtr) { vector &vOperation = pPtr->getAllOperationPtr(); @@ -62,75 +33,47 @@ string CodeGenerator::generateDTSProxy(const InterfacePtr &pPtr) { OperationPtr &oPtr = vOperation[i]; + string funcReturnGeneric = "<"; + if (oPtr->getReturnPtr()->getTypePtr()) + { + funcReturnGeneric += getTsType(oPtr->getReturnPtr()->getTypePtr()) + ", "; + } + else + { + funcReturnGeneric += "undefined, "; + } + str << TAB << oPtr->getId() << "("; + string argType = ""; vector &vParamDecl = oPtr->getAllParamDeclPtr(); - for (size_t j = 0; j < vParamDecl.size(); j++) + for (size_t j = 0; j < vParamDecl.size(); j++) { - if(vParamDecl[j]->isOut()) + if(vParamDecl[j]->isOut()) { + argType += (argType.empty() ? "" : ", ") + vParamDecl[j]->getTypeIdPtr()->getId() + ": " + getTsType(vParamDecl[j]->getTypeIdPtr()->getTypePtr()); continue; } - str << vParamDecl[j]->getTypeIdPtr()->getId() << ": " << getDtsType(vParamDecl[j]->getTypeIdPtr()->getTypePtr()); + str << vParamDecl[j]->getTypeIdPtr()->getId() << ": " << getTsType(vParamDecl[j]->getTypeIdPtr()->getTypePtr()); str << ", "; } - str << "property?: " << IDL_NAMESPACE_STR << "Rpc.InvokeProperty): Promise<" << pPtr->getId() << "$" << oPtr->getId() << "$DE>;" << endl; - str << TAB << "static " << oPtr->getId() << ": SharedFunctionInfo;" << endl; + if (!argType.empty()) + { + funcReturnGeneric += "{ " + argType + " }>"; + } + else + { + funcReturnGeneric += "undefined>"; + } + + str << "options?: " << IDL_NAMESPACE_STR << "Rpc.InvokeProperty): Promise<" << IDL_NAMESPACE_STR << "Rpc.ProxyResponse" << funcReturnGeneric << ">;" << endl; + + str << TAB << "static " << oPtr->getId() << ": " << IDL_NAMESPACE_STR << "Rpc.SharedFunctionInfo" << ";" << endl; } DEL_TAB; str << TAB << "}" << endl; - //interface - for (size_t i = 0; i < vOperation.size(); i++) - { - OperationPtr &oPtr = vOperation[i]; - - str << TAB << "interface " << pPtr->getId() << "$" << oPtr->getId() << "$DE {" << endl; - INC_TAB; - str << TAB << "request: object;" << endl; - str << TAB << "response: {" << endl; - INC_TAB; - str << TAB << "costtime: number;" << endl; - if (oPtr->getReturnPtr()->getTypePtr()) - { - str << TAB << "return: " << getDtsType(oPtr->getReturnPtr()->getTypePtr()) << ";" << endl; - } - else - { - str << TAB << "return: void;" << endl; - } - - vector &vParamDecl = oPtr->getAllParamDeclPtr(); - bool hasArgs = false; - for (size_t j = 0; j < vParamDecl.size(); j++) - { - if(vParamDecl[j]->isOut()) { - hasArgs = true; - break; - } - } - - if(hasArgs) - { - str << TAB << "arguments: {" << endl; - INC_TAB; - for (size_t j = 0; j < vParamDecl.size(); j++) - { - if(!vParamDecl[j]->isOut()) { - continue; - } - str << TAB << vParamDecl[j]->getTypeIdPtr()->getId() << ": " << getDtsType(vParamDecl[j]->getTypeIdPtr()->getTypePtr()) << ";" << endl; - } - DEL_TAB; - str << TAB << "}" << endl; - } - - DEL_TAB; - str << TAB << "}" << endl; - DEL_TAB; - str << TAB << "}" << endl; - } DEL_TAB; return str.str(); @@ -144,8 +87,6 @@ string CodeGenerator::generateDTSProxy(const NamespacePtr &nPtr, bool &bNeedStre { bNeedStream = true; bNeedRpc = true; - - str << generateDTSProxyInfo() << endl; } for (size_t i = 0; i < is.size(); i++) { @@ -158,7 +99,7 @@ void CodeGenerator::generateDTSProxy(const ContextPtr &cPtr) { vector namespaces = cPtr->getNamespaces(); - //先生成编解码 + 代理类 + // generate proxy classes with encoders and decoders ostringstream estr; bool bNeedStream = false; bool bNeedRpc = false; @@ -176,18 +117,18 @@ void CodeGenerator::generateDTSProxy(const ContextPtr &cPtr) return; } - //再生成导入模块 + // generate module imports ostringstream ostr; for (map::iterator it = _mapFiles.begin(); it != _mapFiles.end(); it++) { if (it->second.sModule.empty()) continue; - + if (estr.str().find(it->second.sModule + ".") == string::npos) continue; ostr << "import * as " << it->second.sModule << " from \"" << TC_File::excludeFileExt(it->second.sFile) << "\";" << endl; } - //生成文件内容 + // concat generated code ostringstream sstr; sstr << printHeaderRemark("Client", DISABLE_TSLINT); if (bNeedStream) @@ -205,4 +146,4 @@ void CodeGenerator::generateDTSProxy(const ContextPtr &cPtr) string sFileName = TC_File::excludeFileExt(_sToPath + TC_File::extractFileName(cPtr->getFileName())) + "Proxy.d.ts"; TC_File::makeDirRecursive(_sToPath, 0755); makeUTF8File(sFileName, sstr.str()); -} \ No newline at end of file +} diff --git a/src/gen_proxy_ts.cpp b/src/gen_proxy_ts.cpp new file mode 100644 index 0000000..1d6af8a --- /dev/null +++ b/src/gen_proxy_ts.cpp @@ -0,0 +1,513 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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. + */ + +#include "code_generator.h" + +#define INVOKE_RETURN(protocol, prefix, params) \ + str << TAB << "return this._worker." << TC_Common::lower(protocol) << "_invoke(\"" << oPtr->getId() << "\", "; \ + str << prefix << "." << TC_Common::lower(protocol) << "Encoder"; \ + str << "(" << sParams << params << "), options, " << prefix << ").then("; \ + str << prefix << "." << TC_Common::lower(protocol) << "Decoder, "; \ + str << prefix << ".errorResponser);" << endl; +#define PROTOCOL_PARAMS (sParams.empty() ? "" : ", ") << "version" + +struct SortOperation +{ + bool operator()(const OperationPtr &o1, const OperationPtr &o2) + { + return o1->getId() < o2->getId(); + } +}; + +string CodeGenerator::generateTSProxy(const NamespacePtr &nPtr, const InterfacePtr &pPtr, const OperationPtr &oPtr) +{ + ostringstream str; + + vector & vParamDecl = oPtr->getAllParamDeclPtr(); + bool bHasParamOut = false; + string sParams = ""; + string sParamsWithType = ""; + + for (size_t i = 0; i < vParamDecl.size(); i++) + { + if (vParamDecl[i]->isOut()) + { + continue; + } + + sParams += (sParams.empty() ? "" : ", ") + + vParamDecl[i]->getTypeIdPtr()->getId(); + + sParamsWithType += (sParamsWithType.empty() ? "" : ", ") + + vParamDecl[i]->getTypeIdPtr()->getId() + + ": " + + getTsType(vParamDecl[i]->getTypeIdPtr()->getTypePtr()); + } + + // generate function metadata (SharedFunctionInfo) + str << TAB << "static " << oPtr->getId() << " = _castFunctionInfo({" << endl; + INC_TAB; + + str << TAB << "name: \"" << oPtr->getId() << "\"," << endl; + str << TAB << "return: \"" << getClassName(oPtr->getReturnPtr()->getTypePtr()) << "\"," << endl; + str << TAB << "arguments: ["; + for (size_t i = 0; i < vParamDecl.size(); i++) + { + str << (i > 0 ? ", {" : "{") << endl; + INC_TAB; + + str << TAB << "name: \"" << vParamDecl[i]->getTypeIdPtr()->getId() << "\"," << endl; + str << TAB << "class: \"" << getClassName(vParamDecl[i]->getTypeIdPtr()->getTypePtr()) << "\"," << endl; + + if (vParamDecl[i]->isOut()) + { + bHasParamOut = true; + str << TAB << "direction: \"out\"" << endl; + } + else + { + str << TAB << "direction: \"in\"" << endl; + } + + DEL_TAB; + str << TAB << "}"; + } + str << "]," << endl; + + // generate IDL Encoder ($IE) + str << TAB << TC_Common::lower(IDL_NAMESPACE_STR) << "Encoder(" << sParamsWithType << ") {" << endl; + INC_TAB; + + str << TAB << "const os = new " << IDL_NAMESPACE_STR << "Stream." << IDL_TYPE << "OutputStream();" << endl; + + for (size_t i = 0; i < vParamDecl.size(); i++) + { + if (vParamDecl[i]->isOut()) continue; + + str << TAB << "os." << toFunctionName(vParamDecl[i]->getTypeIdPtr(), "write") << "(" + << (i + 1) << ", " << vParamDecl[i]->getTypeIdPtr()->getId() + << (isRawOrString(vParamDecl[i]->getTypeIdPtr()->getTypePtr()) ? ", 1" : "") << ");" << endl; + + // push the symbol into dependent list + getDataType(vParamDecl[i]->getTypeIdPtr()->getTypePtr()); + } + + str << TAB << "return os.getBinBuffer();" << endl; + + DEL_TAB; + str << TAB << "}," << endl; + + // generate IDL Decoder ($ID) + str << TAB << TC_Common::lower(IDL_NAMESPACE_STR) << "Decoder(data: " << IDL_NAMESPACE_STR << "Rpc.RpcResponse) {" << endl; + INC_TAB; + + str << TAB << "try {" << endl; + INC_TAB; + + if (oPtr->getReturnPtr()->getTypePtr() || bHasParamOut) + { + str << TAB << "var is = new " << IDL_NAMESPACE_STR << "Stream." << IDL_TYPE << "InputStream(data.response.sBuffer);" << endl; + } + + str << TAB << "return {" << endl; + INC_TAB; + str << TAB << "request: data.request," << endl; + str << TAB << "response: {" << endl; + INC_TAB; + str << TAB << "costtime: data.request.costtime," << endl; + + str << TAB << "return: "; + if (oPtr->getReturnPtr()->getTypePtr()) + { + str << "is." << toFunctionName(oPtr->getReturnPtr(), "read") << "(0, true, "; + + if (isSimple(oPtr->getReturnPtr()->getTypePtr())) + { + str << getDefault(oPtr->getReturnPtr(), oPtr->getReturnPtr()->def(), nPtr->getId()) + << (isRawOrString(oPtr->getReturnPtr()->getTypePtr()) ? ", 1" : ""); + } + else + { + str << getDataType(oPtr->getReturnPtr()->getTypePtr(), true); + } + + str << ")," << endl; + } + else + { + str << "undefined as undefined," << endl; + } + + str << TAB << "arguments: "; + if (bHasParamOut) + { + str << "{" << endl; + INC_TAB; + + for (size_t i = 0; i < vParamDecl.size(); i++) + { + if (!vParamDecl[i]->isOut()) continue; + + str << TAB << vParamDecl[i]->getTypeIdPtr()->getId() + << ": is." << toFunctionName(vParamDecl[i]->getTypeIdPtr(), "read") << "(" << (i + 1) << ", true, "; + + if (isSimple(vParamDecl[i]->getTypeIdPtr()->getTypePtr())) + { + str << getDefault(vParamDecl[i]->getTypeIdPtr(), vParamDecl[i]->getTypeIdPtr()->def(), nPtr->getId()) + << (isRawOrString(vParamDecl[i]->getTypeIdPtr()->getTypePtr()) ? ", 1" : ""); + } + else + { + str << getDataType(vParamDecl[i]->getTypeIdPtr()->getTypePtr(), true); + } + + str << ")"; + + if (i == vParamDecl.size() - 1) + { + str << endl; + } + else + { + str << "," << endl; + } + } + + DEL_TAB; + str << TAB << "}" << endl; + } + else + { + str << "undefined as undefined" << endl; + } + + DEL_TAB; + str << TAB << "}" << endl; + DEL_TAB; + str << TAB << "};" << endl; + DEL_TAB; + str << TAB << "} catch (e) {" << endl; + INC_TAB; + str << TAB << "throw _makeError(data, e.message, " << IDL_NAMESPACE_STR << "Rpc.error.CLIENT.DECODE_ERROR);" << endl; + DEL_TAB; + str << TAB << "}" << endl; + DEL_TAB; + str << TAB << "}," << endl; + + // generate Protocol Encoder ($PE) + str << TAB << TC_Common::lower(PROTOCOL_VAR) << "Encoder(" << sParamsWithType << (sParamsWithType.empty() ? "" : ", ") << "__$PROTOCOL$VERSION: number) {" << endl; + INC_TAB; + + str << TAB << "const " << PROTOCOL_VAR << " = new " << IDL_NAMESPACE_STR << "Stream.UniAttribute();" << endl; + + str << TAB << PROTOCOL_VAR << "." << PROTOCOL_VAR << "Version = __$PROTOCOL$VERSION;" << endl; + + for (size_t i = 0; i < vParamDecl.size(); i++) + { + if (vParamDecl[i]->isOut()) continue; + + str << TAB << PROTOCOL_VAR << "." << toFunctionName(vParamDecl[i]->getTypeIdPtr(), "write") << "(\"" + << vParamDecl[i]->getTypeIdPtr()->getId() << "\", " << vParamDecl[i]->getTypeIdPtr()->getId() + << (isRawOrString(vParamDecl[i]->getTypeIdPtr()->getTypePtr()) ? ", 1" : "") << ");" << endl; + + // push the symbol into dependent list + getDataType(vParamDecl[i]->getTypeIdPtr()->getTypePtr()); + } + + str << TAB << "return " << PROTOCOL_VAR << ";" << endl; + DEL_TAB; + str << TAB << "}," << endl; + + // generate Protocol Decoder ($PD) + str << TAB << TC_Common::lower(PROTOCOL_VAR) << "Decoder(data: " << IDL_NAMESPACE_STR << "Rpc.RpcResponse) {" << endl; + INC_TAB; + + str << TAB << "try {" << endl; + INC_TAB; + if (oPtr->getReturnPtr()->getTypePtr() || bHasParamOut) { + str << TAB << "const " << PROTOCOL_VAR << ": " << IDL_NAMESPACE_STR << "Stream.UniAttribute = (data.response as any)." << PROTOCOL_VAR << ";" << endl; + } + str << TAB << "return {" << endl; + INC_TAB; + str << TAB << "request: data.request," << endl; + str << TAB << "response: {" << endl; + INC_TAB; + str << TAB << "costtime: data.request.costtime," << endl; + + str << TAB << "return: "; + if (oPtr->getReturnPtr()->getTypePtr()) + { + str << PROTOCOL_VAR << "." << toFunctionName(oPtr->getReturnPtr(), "read") << "(\"\""; + + if (!isSimple(oPtr->getReturnPtr()->getTypePtr()) && !isBinBuffer(oPtr->getReturnPtr()->getTypePtr())) + { + str << ", " << getDataType(oPtr->getReturnPtr()->getTypePtr(), true); + } + + str << ", " << getDefault(oPtr->getReturnPtr(), "", nPtr->getId(), true) + << (isRawOrString(oPtr->getReturnPtr()->getTypePtr()) ? ", 1" : ""); + + str << ")," << endl; + } + else + { + str << "undefined as undefined," << endl; + } + + str << TAB << "arguments: "; + if (bHasParamOut) + { + str << "{" << endl; + INC_TAB; + + for (size_t i = 0; i < vParamDecl.size(); i++) + { + if (!vParamDecl[i]->isOut()) continue; + + str << TAB << vParamDecl[i]->getTypeIdPtr()->getId() << ": " + << PROTOCOL_VAR << "." << toFunctionName(vParamDecl[i]->getTypeIdPtr(), "read") + << "(\"" << vParamDecl[i]->getTypeIdPtr()->getId() << "\""; + + if (!isSimple(vParamDecl[i]->getTypeIdPtr()->getTypePtr()) && !isBinBuffer(vParamDecl[i]->getTypeIdPtr()->getTypePtr())) + { + str << ", " << getDataType(vParamDecl[i]->getTypeIdPtr()->getTypePtr(), true); + } + + str << ")"; + + if (i == vParamDecl.size() - 1) + { + str << endl; + } + else + { + str << "," << endl; + } + } + + DEL_TAB; + str << TAB << "}" << endl; + } + else + { + str << "undefined as undefined" << endl; + } + + DEL_TAB; + str << TAB << "}" << endl; + DEL_TAB; + str << TAB << "};" << endl; + DEL_TAB; + str << TAB << "} catch (e) {" << endl; + INC_TAB; + str << TAB << "throw _makeError(data, e.message, " << IDL_NAMESPACE_STR << "Rpc.error.CLIENT.DECODE_ERROR);" << endl; + DEL_TAB; + str << TAB << "}" << endl; + DEL_TAB; + str << TAB << "}," << endl; + + // generate error handler ($ER) + str << TAB << "errorResponser(data: " << IDL_NAMESPACE_STR << "Rpc.RpcResponse) {" << endl; + INC_TAB; + str << TAB << "throw _makeError(data, \"Call " << pPtr->getId() << "::" << oPtr->getId() << " failed\");" << endl; + DEL_TAB; + str << TAB << "}" << endl; + + DEL_TAB; + str << TAB << "})" << endl << endl; // end of metadata + + // generate function body + str << TAB << oPtr->getId() << "(" << sParamsWithType << (sParamsWithType.empty() ? "" : ", ") << "options?: " << IDL_NAMESPACE_STR << ".InvokeProperty) {" << endl; + INC_TAB; + + string sFuncFullName = pPtr->getId() + "Proxy." + oPtr->getId(); + str << TAB << "const version = this._worker.version;" << endl; + + str << TAB << "if (version === " << PROTOCOL_SIMPLE << " || version === " << PROTOCOL_COMPLEX << ") {" << endl; + INC_TAB; + INVOKE_RETURN(PROTOCOL_VAR, sFuncFullName, PROTOCOL_PARAMS); + DEL_TAB; + str << TAB << "} else {" << endl; + INC_TAB; + INVOKE_RETURN(IDL_NAMESPACE_STR, sFuncFullName, ""); + DEL_TAB; + str << TAB << "}" << endl; + + DEL_TAB; + str << TAB << "}" << endl << endl; + + return str.str(); +} + +string CodeGenerator::generateTSProxy(const NamespacePtr &nPtr, const InterfacePtr &pPtr) +{ + ostringstream str; + + vector & vOperation = pPtr->getAllOperationPtr(); + sort(vOperation.begin(), vOperation.end(), SortOperation()); + for (size_t i = 0; i < vOperation.size(); i++) + { + str << generateTSProxy(nPtr, pPtr, vOperation[i]); + } + + return str.str(); +} + +string CodeGenerator::generateTSProxy(const NamespacePtr &nPtr, bool &bNeedStream, bool &bNeedRpc) +{ + ostringstream str; + vector &is = nPtr->getAllInterfacePtr(); + if (is.size() > 0) + { + bNeedStream = true; + bNeedRpc = true; + } + + for (size_t i = 0; i < is.size(); i++) + { + str << TAB << "export class " << is[i]->getId() << "Proxy {" << endl; + INC_TAB; + + str << TAB << "protected _name!: string" << endl; + str << TAB << "protected _worker!: " << IDL_NAMESPACE_STR << "Rpc.ObjectProxy" << endl << endl; + + str << TAB << "setTimeout (iTimeout: number) { this._worker.timeout = iTimeout; }" << endl; + str << TAB << "getTimeout () { return this._worker.timeout; }" << endl; + str << TAB << "setVersion (iVersion: number) { this._worker.version = iVersion; }" << endl; + str << TAB << "getVersion () { return this._worker.version; }" << endl << endl; + + str << generateTSProxy(nPtr, is[i]) << endl; + + DEL_TAB; + str << TAB << "}" << endl << endl; + } + + return str.str(); +} + +bool CodeGenerator::generateTSProxy(const ContextPtr &cPtr) +{ + vector namespaces = cPtr->getNamespaces(); + + // generate proxy classes with encoders and decoders + ostringstream estr; + bool bNeedStream = false; + bool bNeedRpc = false; + bool bNeedAssert = false; + bool bQuickFunc = false; + for(size_t i = 0; i < namespaces.size(); i++) + { + ostringstream kstr; + + kstr << generateTS(namespaces[i], bNeedStream, bNeedAssert, bQuickFunc); + + INC_TAB; + kstr << generateTSProxy(namespaces[i], bNeedStream, bNeedRpc); + DEL_TAB; + + estr << generateTS(namespaces[i], kstr.str()); + } + if (estr.str().empty()) + { + return false; + } + + // generate module imports + ostringstream sstr; + sstr << printHeaderRemark("Client", DISABLE_TSLINT); + sstr << "/// " << endl; + if (bNeedAssert) + { + sstr << TAB << "import assert = require(\"assert\");" << endl; + } + if (bNeedStream) + { + sstr << "import * as " << IDL_NAMESPACE_STR << "Stream from \"" << _sStreamPath << "\";" << endl; + } + if (bNeedRpc) + { + sstr << "import * as " << IDL_NAMESPACE_STR << "Rpc from \"" << _sRpcPath << "\";" << endl; + } + + for (map::iterator it = _mapFiles.begin(); it != _mapFiles.end(); it++) + { + if (it->second.sModule.empty()) continue; + + if (estr.str().find(it->second.sModule + ".") == string::npos) continue; + + sstr << "import * as " << it->second.sModule << " from \"" << TC_File::excludeFileExt(it->second.sFile) << "\";" << endl; + } + + // generate helper functions + if (bQuickFunc || bNeedRpc) + { + sstr << endl; + } + if (bQuickFunc) + { + sstr << "const _hasOwnProperty = Object.prototype.hasOwnProperty;" << endl; + } + if (bNeedRpc) + { + sstr << TAB << "function _castFunctionInfo(data: SharedFunctionInfo) { return data; }" << endl; + sstr << TAB << "function _makeError(data: " << IDL_NAMESPACE_STR << "Rpc.RpcResponse, message: string, type?: number): " << IDL_NAMESPACE_STR << "Rpc.RpcError {" << endl; + INC_TAB; + sstr << TAB << "var error: any = new Error(message || \"\");" << endl; + sstr << TAB << "error.request = data.request;" << endl; + sstr << TAB << "error.response = {" << endl; + INC_TAB; + sstr << TAB << "costtime: data.request.costtime" << endl; + DEL_TAB; + sstr << TAB << "};" << endl; + sstr << TAB << "if (type === " << IDL_NAMESPACE_STR << "Rpc.error.CLIENT.DECODE_ERROR) {" << endl; + INC_TAB; + sstr << TAB << "error.name = \"DECODE_ERROR\";" << endl; + sstr << TAB << "error.response.error = {" << endl; + INC_TAB; + sstr << TAB << "code: type," << endl; + sstr << TAB << "message: message" << endl; + DEL_TAB; + sstr << TAB << "};" << endl; + DEL_TAB; + sstr << TAB << "} else {" << endl; + INC_TAB; + sstr << TAB << "error.name = \"RPC_ERROR\";" << endl; + sstr << TAB << "error.response.error = data.error;" << endl; + DEL_TAB; + sstr << TAB << "}" << endl; + sstr << TAB << "return error;" << endl; + DEL_TAB; + sstr << TAB << "}" << endl << endl; + + sstr << "export interface SharedFunctionInfo extends " << IDL_NAMESPACE_STR << "Rpc.SharedFunctionInfo {" << endl; + INC_TAB; + sstr << TAB << TC_Common::lower(IDL_NAMESPACE_STR) << "Encoder (...args: any[]): " << IDL_NAMESPACE_STR << "Stream.BinBuffer," << endl; + sstr << TAB << TC_Common::lower(IDL_NAMESPACE_STR) << "Decoder (data: " << IDL_NAMESPACE_STR << "Rpc.RpcResponse): " << IDL_NAMESPACE_STR << "Rpc.ProxyResponse," << endl; + sstr << TAB << TC_Common::lower(PROTOCOL_VAR) << "Encoder (...args: any[]): " << IDL_NAMESPACE_STR << "Stream.UniAttribute," << endl; + sstr << TAB << TC_Common::lower(PROTOCOL_VAR) << "Decoder (data: " << IDL_NAMESPACE_STR << "Rpc.RpcResponse): " << IDL_NAMESPACE_STR << "Rpc.ProxyResponse," << endl; + sstr << TAB << "errorResponser (data: " << IDL_NAMESPACE_STR << "Rpc.RpcResponse): never" << endl; + DEL_TAB; + sstr << TAB << "}" << endl << endl; + } + + sstr << estr.str() << endl; + + string sFileName = TC_File::excludeFileExt(_sToPath + TC_File::extractFileName(cPtr->getFileName())) + "Proxy.ts"; + TC_File::makeDirRecursive(_sToPath, 0755); + makeUTF8File(sFileName, sstr.str()); + + return true; +} diff --git a/src/gen_server.cpp b/src/gen_server.cpp index ed31eea..bfa1c93 100644 --- a/src/gen_server.cpp +++ b/src/gen_server.cpp @@ -58,7 +58,7 @@ string CodeGenerator::generateAsync(const NamespacePtr &nPtr, const InterfacePtr { sParams += "_ret"; - // 写入 Dependent 列表 + // push the symbol into dependent list getDataType(oPtr->getReturnPtr()->getTypePtr()); } @@ -243,7 +243,7 @@ string CodeGenerator::generateJSServer(const InterfacePtr &pPtr, const Namespace ostringstream str; vector & vOperation = pPtr->getAllOperationPtr(); - //生成类 + // generate the implementation class str << TAB << nPtr->getId() << "." << pPtr->getId() << "Imp = function () { " << endl; INC_TAB; str << TAB << "this._name = undefined;" << endl; @@ -251,10 +251,10 @@ string CodeGenerator::generateJSServer(const InterfacePtr &pPtr, const Namespace DEL_TAB; str << TAB << "};" << endl << endl; - //生成初始化函数 + // generate the initialize function str << TAB << nPtr->getId() << "." << pPtr->getId() << "Imp.prototype.initialize = function () {};" << endl << endl; - //生成分发函数 + // generate the dispatch function str << TAB << nPtr->getId() << "." << pPtr->getId() << "Imp.prototype.onDispatch = function (current, funcName, binBuffer) { " << endl; INC_TAB; str << TAB << "if (\"__\" + funcName in this) {" << endl; @@ -269,10 +269,10 @@ string CodeGenerator::generateJSServer(const InterfacePtr &pPtr, const Namespace DEL_TAB; str << TAB << "};" << endl << endl; - //生成 PING 方法 + // generate the ping function str << generatePing(nPtr, pPtr) << endl; - //生成接口函数 + // generate functions for (size_t i = 0; i < vOperation.size(); i++) { str << generateJSServer(nPtr, pPtr, vOperation[i]) << endl; @@ -321,7 +321,7 @@ bool CodeGenerator::generateJSServer(const ContextPtr &pPtr) } } - //生成编解码 + 服务类 + // generate server classes with encoders and decoders ostringstream estr; bool bNeedAssert = false; bool bNeedStream = false; @@ -342,7 +342,7 @@ bool CodeGenerator::generateJSServer(const ContextPtr &pPtr) return false; } - //再生成导入模块 + // generate module imports ostringstream ostr; if (bNeedAssert) { diff --git a/src/gen_server_dts.cpp b/src/gen_server_dts.cpp index 7ba6f0f..16814df 100644 --- a/src/gen_server_dts.cpp +++ b/src/gen_server_dts.cpp @@ -25,34 +25,37 @@ string CodeGenerator::generateDTSServer(const NamespacePtr &nPtr, const Interfac INC_TAB; str << TAB << "class " << pPtr->getId() << "Imp {" << endl; INC_TAB; - str << TAB << "initialize(): Promise | void;" << endl; + str << TAB << "initialize(): PromiseLike | void;" << endl; str << TAB << "protected onDispatch(current: " << IDL_NAMESPACE_STR << "Rpc." << IDL_TYPE << "Current, funcName: string, binBuffer: " << IDL_NAMESPACE_STR << "Stream.BinBuffer): number" << endl; for (size_t i = 0; i < vOperation.size(); i++) { OperationPtr &oPtr = vOperation[i]; - str << TAB << oPtr->getId() << "(current: " << pPtr->getId() << "$" << oPtr->getId() << "$CUR"; + str << TAB << oPtr->getId() << "(current: " << pPtr->getId() << "Imp." << oPtr->getId() << "Current"; vector &vParamDecl = oPtr->getAllParamDeclPtr(); - for (size_t j = 0; j < vParamDecl.size(); j++) + for (size_t j = 0; j < vParamDecl.size(); j++) { - str << ", " << vParamDecl[j]->getTypeIdPtr()->getId() << ": " << getDtsType(vParamDecl[j]->getTypeIdPtr()->getTypePtr()); + str << ", " << vParamDecl[j]->getTypeIdPtr()->getId() << ": " << getTsType(vParamDecl[j]->getTypeIdPtr()->getTypePtr()); } - str << "): void;" << endl; + str << "): any;" << endl; } DEL_TAB; str << TAB << "}" << endl; - //interface + // Additional namespace + str << TAB << "namespace " << pPtr->getId() << "Imp {" << endl; + INC_TAB; + for (size_t i = 0; i < vOperation.size(); i++) { OperationPtr &oPtr = vOperation[i]; - str << TAB << "interface " << pPtr->getId() << "$" << oPtr->getId() << "$CUR extends " << IDL_NAMESPACE_STR << "Rpc." << IDL_TYPE << "Current {" <getId() << "Current extends " << IDL_NAMESPACE_STR << "Rpc." << IDL_TYPE << "Current {" <getReturnPtr()->getTypePtr()) { - str << "sendResponse(ret: " << getDtsType(oPtr->getReturnPtr()->getTypePtr()); + str << "sendResponse(ret: " << getTsType(oPtr->getReturnPtr()->getTypePtr()); vector &vParamDecl = oPtr->getAllParamDeclPtr(); for (size_t j = 0; j < vParamDecl.size(); j++) @@ -60,7 +63,7 @@ string CodeGenerator::generateDTSServer(const NamespacePtr &nPtr, const Interfac if(!vParamDecl[j]->isOut()) { continue; } - str << ", " << vParamDecl[j]->getTypeIdPtr()->getId() << ": " << getDtsType(vParamDecl[j]->getTypeIdPtr()->getTypePtr()) ; + str << ", " << vParamDecl[j]->getTypeIdPtr()->getId() << ": " << getTsType(vParamDecl[j]->getTypeIdPtr()->getTypePtr()) ; } str << "): void;" << endl; } @@ -72,8 +75,11 @@ string CodeGenerator::generateDTSServer(const NamespacePtr &nPtr, const Interfac DEL_TAB; str << TAB << "}" << endl; } - DEL_TAB; + DEL_TAB; + str << TAB << "}" << endl; + + DEL_TAB; return str.str(); } @@ -100,7 +106,7 @@ void CodeGenerator::generateDTSServer(const ContextPtr &pPtr) { vector namespaces = pPtr->getNamespaces(); - //生成编解码 + 服务类 + // generate server classes with encoders and decoders ostringstream estr; bool bNeedStream = false; bool bNeedRpc = false; @@ -110,7 +116,7 @@ void CodeGenerator::generateDTSServer(const ContextPtr &pPtr) kstr << generateDTS(namespaces[i], bNeedStream); kstr << generateDTSServer(namespaces[i], bNeedStream, bNeedRpc); - + estr << generateDTS(namespaces[i], kstr.str()); } if(estr.str().empty()) @@ -118,7 +124,7 @@ void CodeGenerator::generateDTSServer(const ContextPtr &pPtr) return; } - //再生成导入模块 + // generate module imports ostringstream ostr; if (bNeedStream) { @@ -131,7 +137,7 @@ void CodeGenerator::generateDTSServer(const ContextPtr &pPtr) for (map::iterator it = _mapFiles.begin(); it != _mapFiles.end(); it++) { if (it->second.sModule.empty()) continue; - + if (estr.str().find(it->second.sModule + ".") == string::npos) continue; ostr << "import * as " << it->second.sModule << " from \"" << TC_File::excludeFileExt(it->second.sFile) << "\";" << endl; @@ -146,4 +152,4 @@ void CodeGenerator::generateDTSServer(const ContextPtr &pPtr) TC_File::makeDirRecursive(_sToPath, 0755); makeUTF8File(sFileName, str.str()); -} \ No newline at end of file +} diff --git a/src/gen_server_ts.cpp b/src/gen_server_ts.cpp new file mode 100644 index 0000000..6032c49 --- /dev/null +++ b/src/gen_server_ts.cpp @@ -0,0 +1,401 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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. + */ + +#include "code_generator.h" + +string CodeGenerator::generateTSServerAsync(const NamespacePtr &nPtr, const InterfacePtr &pPtr, const OperationPtr &oPtr) +{ + ostringstream str; + + string sParams = ""; + if (oPtr->getReturnPtr()->getTypePtr()) + { + sParams += "_ret: " + getTsType(oPtr->getReturnPtr()->getTypePtr()); + + // push the symbol into dependent list + getDataType(oPtr->getReturnPtr()->getTypePtr()); + } + + vector & vParamDecl = oPtr->getAllParamDeclPtr(); + for (size_t i = 0; i < vParamDecl.size(); i++) + { + if (!vParamDecl[i]->isOut()) continue; + + sParams += (sParams.empty() ? "": ", ") + vParamDecl[i]->getTypeIdPtr()->getId(); + sParams += ": " + getTsType(vParamDecl[i]->getTypeIdPtr()->getTypePtr()); + } + + str << TAB << "protected static __" << oPtr->getId() << "_responser(this: " << IDL_NAMESPACE_STR << "Rpc.JceCurrent, " << sParams << ") {" << endl; + + INC_TAB; + + if (sParams.empty()) + { + str << TAB << "this.doResponse(new " << IDL_NAMESPACE_STR << "Stream.BinBuffer());" << endl; + DEL_TAB; + str << TAB << "}" << endl; + + return str.str(); + } + + str << TAB << "if (this.getRequestVersion() === " << PROTOCOL_SIMPLE << " || this.getRequestVersion() === " << PROTOCOL_COMPLEX << ") {" << endl; + INC_TAB; + str << TAB << "const " << PROTOCOL_VAR << " = new " << IDL_NAMESPACE_STR << "Stream.UniAttribute();" << endl; + str << TAB << PROTOCOL_VAR << "." << PROTOCOL_VAR << "Version = this.getRequestVersion();" << endl; + if (oPtr->getReturnPtr()->getTypePtr()) + { + str << TAB << PROTOCOL_VAR << "." << toFunctionName(oPtr->getReturnPtr(), "write") << "(\"\", _ret" + << (isRawOrString(oPtr->getReturnPtr()->getTypePtr()) ? ", 1" : "") << ");" << endl; + } + for (size_t i = 0; i < vParamDecl.size(); i++) + { + if (!vParamDecl[i]->isOut()) continue; + + str << TAB << PROTOCOL_VAR << "." << toFunctionName(vParamDecl[i]->getTypeIdPtr(), "write") << "(\"" + << vParamDecl[i]->getTypeIdPtr()->getId() << "\", " << vParamDecl[i]->getTypeIdPtr()->getId() + << (isRawOrString(vParamDecl[i]->getTypeIdPtr()->getTypePtr()) ? ", 1" : "") << ");" << endl; + } + str << endl; + str << TAB << "this.doResponse(" << PROTOCOL_VAR << ".encode());" << endl; + DEL_TAB; + str << TAB << "} else {" << endl; + + INC_TAB; + str << TAB << "const os = new " << IDL_NAMESPACE_STR << "Stream." << IDL_TYPE << "OutputStream();" << endl; + if (oPtr->getReturnPtr()->getTypePtr()) + { + str << TAB << "os." << toFunctionName(oPtr->getReturnPtr(), "write") << "(0, _ret" + << (isRawOrString(oPtr->getReturnPtr()->getTypePtr()) ? ", 1" : "") << ");" << endl; + } + for (size_t i = 0; i < vParamDecl.size(); i++) + { + if (!vParamDecl[i]->isOut()) continue; + + str << TAB << "os." << toFunctionName(vParamDecl[i]->getTypeIdPtr(), "write") << "(" + << (i + 1) << ", " << vParamDecl[i]->getTypeIdPtr()->getId() + << (isRawOrString(vParamDecl[i]->getTypeIdPtr()->getTypePtr()) ? ", 1" : "") << ");" << endl; + } + str << endl; + str << TAB << "this.doResponse(os.getBinBuffer());" << endl; + DEL_TAB; + str << TAB << "}" << endl; + + DEL_TAB; + + str << TAB << "}" << endl; + + return str.str(); +} + +string CodeGenerator::generateTSServerDispatch(const NamespacePtr &nPtr, const InterfacePtr &pPtr, const OperationPtr &oPtr) +{ + ostringstream str; + vector & vParamDecl = oPtr->getAllParamDeclPtr(); + + str << TAB << "protected __" << oPtr->getId() << "(current: " << IDL_NAMESPACE_STR << "Rpc.JceCurrent"; + if (vParamDecl.size() != 0) str << ", binBuffer: " << IDL_NAMESPACE_STR << "Stream.BinBuffer"; + str << ") {" << endl; + + INC_TAB; + + ostringstream dstr; + + for (size_t i = 0; i < vParamDecl.size(); i++) + { + dstr << TAB << "let " << vParamDecl[i]->getTypeIdPtr()->getId() << ": " << getTsType(vParamDecl[i]->getTypeIdPtr()->getTypePtr()) << ";" << endl; + } + if (vParamDecl.size() != 0) + { + dstr << endl; + } + + dstr << TAB << "if (current.getRequestVersion() === " << PROTOCOL_SIMPLE << " || current.getRequestVersion() === " << PROTOCOL_COMPLEX << ") {" << endl; + INC_TAB; + dstr << TAB << "const " << PROTOCOL_VAR << " = new " << IDL_NAMESPACE_STR << "Stream.UniAttribute();" << endl; + dstr << TAB << PROTOCOL_VAR << "." << PROTOCOL_VAR << "Version = current.getRequestVersion();" << endl; + dstr << TAB << PROTOCOL_VAR << ".decode(binBuffer);" << endl; + + for (size_t i = 0; i < vParamDecl.size(); i++) + { + dstr << TAB << vParamDecl[i]->getTypeIdPtr()->getId() + << " = " << PROTOCOL_VAR << "." << toFunctionName(vParamDecl[i]->getTypeIdPtr(), "read") + << "(\"" << vParamDecl[i]->getTypeIdPtr()->getId() << "\""; + + if (!isSimple(vParamDecl[i]->getTypeIdPtr()->getTypePtr()) && !isBinBuffer(vParamDecl[i]->getTypeIdPtr()->getTypePtr())) + { + dstr << ", " << getDataType(vParamDecl[i]->getTypeIdPtr()->getTypePtr(), true); + } + + if (vParamDecl[i]->isOut()) + { + dstr << ", " << getDefault(vParamDecl[i]->getTypeIdPtr(), "", nPtr->getId(), true) + << (isRawOrString(vParamDecl[i]->getTypeIdPtr()->getTypePtr()) ? ", 1" : ""); + } + + dstr << ");" << endl; + } + DEL_TAB; + dstr << TAB << "} else {" << endl; + + INC_TAB; + dstr << TAB << "const is = new " << IDL_NAMESPACE_STR << "Stream." << IDL_TYPE << "InputStream(binBuffer);" << endl; + string sParams = ""; + for (size_t i = 0; i < vParamDecl.size(); i++) + { + sParams += ", " + vParamDecl[i]->getTypeIdPtr()->getId(); + + dstr << TAB << vParamDecl[i]->getTypeIdPtr()->getId() + << " = is." << toFunctionName(vParamDecl[i]->getTypeIdPtr(), "read") << "(" + << (i + 1) << ", " << (vParamDecl[i]->isOut() ? "false" : "true") << ", "; + + if (isSimple(vParamDecl[i]->getTypeIdPtr()->getTypePtr())) + { + dstr << getDefault(vParamDecl[i]->getTypeIdPtr(), vParamDecl[i]->getTypeIdPtr()->def(), nPtr->getId()) + << (isRawOrString(vParamDecl[i]->getTypeIdPtr()->getTypePtr()) ? ", 1" : ""); + } + else + { + dstr << getDataType(vParamDecl[i]->getTypeIdPtr()->getTypePtr(), true); + } + + dstr << ");" << endl; + } + DEL_TAB; + dstr << TAB << "}" << endl << endl; + + if (!sParams.empty()) + { + str << dstr.str(); + } + + str << TAB << "current.sendResponse = " << pPtr->getId() << "Imp.__" << oPtr->getId() << "_responser;" << endl << endl; + + str << TAB << "this." << oPtr->getId() << "(current" << sParams << ");" << endl << endl; + + str << TAB << "return " << IDL_NAMESPACE_STR << "Rpc.error.SUCCESS;" << endl; + + DEL_TAB; + + str << TAB << "}" << endl; + + return str.str(); +} + +string CodeGenerator::generateTSServer(const NamespacePtr &pPtr, bool &bNeedStream, bool &bNeedRpc, bool &bNeedAssert) +{ + ostringstream str; + + vector & is = pPtr->getAllInterfacePtr(); + for (size_t i = 0; i < is.size(); i++) + { + str << generateTSServer(is[i], pPtr) << endl; + } + if (is.size() != 0) + { + bNeedRpc = true; + bNeedStream = true; + bNeedAssert = true; + } + + return str.str(); +} + +string CodeGenerator::generateTSServer(const InterfacePtr &pPtr, const NamespacePtr &nPtr) +{ + ostringstream str; + vector & vOperation = pPtr->getAllOperationPtr(); + + // generate the implementation class + str << TAB << "export abstract class " << pPtr->getId() << "Imp { " << endl; + INC_TAB; + str << TAB << "_name!: string" << endl; + str << TAB << "_worker!: any" << endl << endl; + + // generate the initialize function + str << TAB << "initialize(): PromiseLike | void {}" << endl << endl; + + // generate the dispatch function + str << TAB << "onDispatch(current: " << IDL_NAMESPACE_STR << "Rpc.JceCurrent, funcName: string, binBuffer: " << IDL_NAMESPACE_STR << "Stream.BinBuffer) { " << endl; + INC_TAB; + str << TAB << "if (\"__\" + funcName in this) {" << endl; + INC_TAB; + str << TAB << "return (this as any)[\"__\" + funcName](current, binBuffer);" << endl; + DEL_TAB; + str << TAB << "} else {" << endl; + INC_TAB; + str << TAB << "return " << IDL_NAMESPACE_STR << "Rpc.error.SERVER.FUNC_NOT_FOUND;" << endl; + DEL_TAB; + str << TAB << "}" << endl; + DEL_TAB; + str << TAB << "}" << endl << endl; + + // generate the ping function + str << TAB << "__" << TC_Common::lower(IDL_NAMESPACE_STR) << "_ping(current: " << IDL_NAMESPACE_STR << "Rpc.JceCurrent) { " << endl; + INC_TAB; + str << TAB << "const _ret = 0;" << endl; + str << TAB << "if (current.getRequestVersion() === " << PROTOCOL_SIMPLE << " || current.getRequestVersion() === " << PROTOCOL_COMPLEX << ") {" << endl; + INC_TAB; + str << TAB << "const " << PROTOCOL_VAR << " = new " << IDL_NAMESPACE_STR << "Stream.UniAttribute();" << endl; + str << TAB << PROTOCOL_VAR << "." << PROTOCOL_VAR << "Version = current.getRequestVersion();" << endl; + str << TAB << PROTOCOL_VAR << ".writeInt32(\"\", _ret);" << endl << endl; + str << TAB << "current.doResponse(" << PROTOCOL_VAR << ".encode());" << endl; + DEL_TAB; + str << TAB << "} else {" << endl; + INC_TAB; + str << TAB << "const os = new " << IDL_NAMESPACE_STR << "Stream." << IDL_TYPE << "OutputStream();" << endl; + str << TAB << "os.writeInt32(0, _ret);" << endl << endl; + str << TAB << "current.doResponse(os.getBinBuffer());" << endl; + DEL_TAB; + str << TAB << "}" << endl << endl; + str << TAB << "return " << IDL_NAMESPACE_STR << "Rpc.error.SUCCESS;" << endl; + DEL_TAB; + str << TAB << "}" << endl << endl; + + // generate functions + for (size_t i = 0; i < vOperation.size(); i++) + { + const OperationPtr &oPtr = vOperation[i]; + + // generate function definition + str << TAB << oPtr->getId() << "(current: " << pPtr->getId() << "Imp." << oPtr->getId() << "Current"; + + vector &vParamDecl = oPtr->getAllParamDeclPtr(); + for (size_t j = 0; j < vParamDecl.size(); j++) + { + str << ", " << vParamDecl[j]->getTypeIdPtr()->getId() << ": " << getTsType(vParamDecl[j]->getTypeIdPtr()->getTypePtr()); + } + str << "): any { " << endl; + + INC_TAB; + str << TAB << "assert.fail(\"" << oPtr->getId() << " function not implemented\");" << endl; + DEL_TAB; + str << TAB << "}" << endl << endl; + + // generate encoder and decoder + str << generateTSServerAsync(nPtr, pPtr, vOperation[i]) << endl; + str << generateTSServerDispatch(nPtr, pPtr, vOperation[i]) << endl; + } + + DEL_TAB; + str << TAB << "}" << endl << endl; // end of class + + // generate additional namespaces + str << TAB << "export namespace " << pPtr->getId() << "Imp {" << endl; + INC_TAB; + + for (size_t i = 0; i < vOperation.size(); i++) + { + OperationPtr &oPtr = vOperation[i]; + + str << TAB << "export interface " << oPtr->getId() << "Current extends " << IDL_NAMESPACE_STR << "Rpc." << IDL_TYPE << "Current {" <getReturnPtr()->getTypePtr()) + { + str << "sendResponse(ret: " << getTsType(oPtr->getReturnPtr()->getTypePtr()); + + vector &vParamDecl = oPtr->getAllParamDeclPtr(); + for (size_t j = 0; j < vParamDecl.size(); j++) + { + if(!vParamDecl[j]->isOut()) { + continue; + } + str << ", " << vParamDecl[j]->getTypeIdPtr()->getId() << ": " << getTsType(vParamDecl[j]->getTypeIdPtr()->getTypePtr()) ; + } + str << "): void;" << endl; + } + else + { + str << "sendResponse(): void;" << endl; + } + + DEL_TAB; + str << TAB << "}" << endl; + } + + DEL_TAB; + str << TAB << "}" << endl; + + return str.str(); +} + +bool CodeGenerator::generateTSServer(const ContextPtr &pPtr) +{ + vector namespaces = pPtr->getNamespaces(); + + // generate server classes with encoders and decoders + ostringstream estr; + bool bNeedStream = false; + bool bNeedRpc = false; + bool bNeedAssert = false; + bool bQuickFunc = false; + for(size_t i = 0; i < namespaces.size(); i++) + { + ostringstream kstr; + kstr << generateTS(namespaces[i], bNeedStream, bNeedAssert, bQuickFunc); + + INC_TAB; + kstr << generateTSServer(namespaces[i], bNeedStream, bNeedRpc, bNeedAssert); + DEL_TAB; + + estr << generateTS(namespaces[i], kstr.str()); + } + if (estr.str().empty()) + { + return false; + } + + ostringstream str; + + // generate the source file + str << printHeaderRemark("Server", DISABLE_TSLINT); + str << "/// " << endl; + if (bNeedAssert) + { + str << TAB << "import assert = require(\"assert\");" << endl; + } + if (bNeedStream) + { + str << "import * as " << IDL_NAMESPACE_STR << "Stream from \"" << _sStreamPath << "\";" << endl; + } + if (bNeedRpc) + { + str << "import * as " << IDL_NAMESPACE_STR << "Rpc from \"" << _sRpcPath << "\";" << endl; + } + + for (map::iterator it = _mapFiles.begin(); it != _mapFiles.end(); it++) + { + if (it->second.sModule.empty()) continue; + + if (estr.str().find(it->second.sModule + ".") == string::npos) continue; + + str << "import * as " << it->second.sModule << " from \"" << TC_File::excludeFileExt(it->second.sFile) << "\";" << endl; + } + if (bQuickFunc) + { + str << endl; + str << TAB << "const _hasOwnProperty = Object.prototype.hasOwnProperty;" << endl; + } + + str << endl << estr.str() << endl; + + string sFileName = TC_File::excludeFileExt(_sToPath + TC_File::extractFileName(pPtr->getFileName())) + ".ts"; + + TC_File::makeDirRecursive(_sToPath, 0755); + makeUTF8File(sFileName, str.str()); + + return true; +} diff --git a/src/gen_server_ts_imp.cpp b/src/gen_server_ts_imp.cpp new file mode 100644 index 0000000..777a647 --- /dev/null +++ b/src/gen_server_ts_imp.cpp @@ -0,0 +1,110 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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. + */ + +#include "code_generator.h" + +void CodeGenerator::generateTSServerImp(const ContextPtr &cPtr) +{ + string sFileName = TC_File::excludeFileExt(_sToPath + TC_File::extractFileName(cPtr->getFileName())) + "Imp.ts"; + if (TC_File::isFileExist(sFileName)) + { + return ; + } + + ostringstream str; + str << printHeaderRemark("Imp"); + + vector namespaces = cPtr->getNamespaces(); + + // generate the server implementation class + ostringstream estr; + set setInterface; + for(size_t i = 0; i < namespaces.size(); i++) + { + estr << "export namespace " << namespaces[i]->getId() << " {" << endl; + INC_TAB; + + vector & is = namespaces[i]->getAllInterfacePtr(); + for (size_t ii = 0; ii < is.size(); ii++) + { + if (setInterface.count(namespaces[i]->getId() + "::" + is[ii]->getId()) != 0) + { + continue; + } + setInterface.insert(namespaces[i]->getId() + "::" + is[ii]->getId()); + + estr << TAB << "export class " << is[ii]->getId() << "Imp extends base." << namespaces[i]->getId() << "." << is[ii]->getId() << "Imp { " << endl; + INC_TAB; + + estr << TAB << "initialize() {" << endl; + INC_TAB; + estr << TAB << "// TODO: implement initialize" << endl; + DEL_TAB; + estr << TAB << "}" << endl << endl; + + vector & vOperation = is[ii]->getAllOperationPtr(); + for (size_t iii = 0; iii < vOperation.size(); iii++) + { + const OperationPtr &oPtr = vOperation[iii]; + + // generate function entries + estr << TAB << oPtr->getId() << "(current: base." << namespaces[i]->getId() << "." << is[ii]->getId() << "Imp." << oPtr->getId() << "Current"; + + vector &vParamDecl = oPtr->getAllParamDeclPtr(); + for (size_t j = 0; j < vParamDecl.size(); j++) + { + estr << ", " << vParamDecl[j]->getTypeIdPtr()->getId() << ": " << getTsType(vParamDecl[j]->getTypeIdPtr()->getTypePtr(), true, true); + } + estr << ") { " << endl; + + INC_TAB; + estr << TAB << "// TODO: implement " << oPtr->getId() << "" << endl; + + DEL_TAB; + estr << TAB << "}" << endl; + if (iii != vOperation.size() - 1) estr << endl; + } + + DEL_TAB; + estr << TAB << "}" << endl; + if (ii != is.size() - 1) estr << endl; + } + + DEL_TAB; + estr << "}" << endl; + if (i != namespaces.size() - 1) estr << endl; + } + + // generate module imports + str << "import * as " << IDL_NAMESPACE_STR << "Stream from \"" << _sStreamPath << "\";" << endl; + str << "import * as base from \"./" + << TC_File::excludeFileExt(TC_File::extractFileName(cPtr->getFileName())) << "\";" << endl; + + for (map::iterator it = _mapFiles.begin(); it != _mapFiles.end(); it++) + { + if (it->second.sModule.empty()) continue; + + if (estr.str().find(it->second.sModule + ".") == string::npos) continue; + + str << "import * as " << it->second.sModule << " from \"" << TC_File::excludeFileExt(it->second.sFile) << "\";" << endl; + } + + str << endl; + str << estr.str(); + + TC_File::makeDirRecursive(_sToPath, 0755); + makeUTF8File(sFileName, str.str()); +} diff --git a/src/gen_ts.cpp b/src/gen_ts.cpp new file mode 100644 index 0000000..67e7e68 --- /dev/null +++ b/src/gen_ts.cpp @@ -0,0 +1,443 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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. + */ + +#include "code_generator.h" + +string CodeGenerator::generateTS(const EnumPtr &pPtr, const string &sNamespace) +{ + ostringstream s; + + INC_TAB; + s << TAB << "export enum " << pPtr->getId() << " {" << endl; + + INC_TAB; + int nenum = -1; + bool bDependent = false; + vector& member = pPtr->getAllMemberPtr(); + for (size_t i = 0; i < member.size(); i++) + { + bDependent |= isDependent(sNamespace, member[i]->getId()); + if (member[i]->hasDefault()) + { + nenum = TC_Common::strto(member[i]->def()); + } + else + { + nenum++; + } + s << TAB << member[i]->getId() << " = " << TC_Common::tostr(nenum) << ((i < member.size() - 1) ? "," : "") << endl; + } + + DEL_TAB; + s << TAB << "}" << endl << endl; + + s << TAB << "export namespace " << pPtr->getId() << " {" << endl; + INC_TAB; + s << TAB << "export const _classname = \"" << sNamespace << "." << pPtr->getId() << "\";" << endl; + s << TAB << "export function _write(os: " << IDL_NAMESPACE_STR << "Stream." << IDL_TYPE << "OutputStream, tag: number, val: number) { return os.writeInt32(tag, val); }" << endl; + s << TAB << "export function _read(is: " << IDL_NAMESPACE_STR << "Stream." << IDL_TYPE << "InputStream, tag: number, def?: number) { return is.readInt32(tag, true, def); }" << endl; + DEL_TAB; + s << TAB << "}" << endl << endl; + + DEL_TAB; + + if (!_bMinimalMembers || _bEntry || bDependent || isDependent(sNamespace, pPtr->getId())) { + return s.str(); + } else { + return ""; + } +} + +string CodeGenerator::generateTS(const ConstPtr &pPtr, const string &sNamespace, bool &bNeedStream) +{ + if (_bMinimalMembers && !_bEntry && !isDependent(sNamespace, pPtr->getTypeIdPtr()->getId())) + { + return ""; + } + + ostringstream s; + if (_bStringBinaryEncoding && GET_CONST_GRAMMAR_PTR(pPtr)->t == CONST_GRAMMAR(STRING)) + { + bNeedStream = true; + } + + INC_TAB; + s << TAB << "export const " << pPtr->getTypeIdPtr()->getId() << ": " + << getTsType(pPtr->getTypeIdPtr()->getTypePtr()) << " = " + << getDefault(pPtr->getTypeIdPtr(), GET_CONST_GRAMMAR_PTR(pPtr)->v, sNamespace, false) << ";" + << endl; + DEL_TAB; + return s.str(); +} + +string CodeGenerator::generateTS(const StructPtr &pPtr, const string &sNamespace, bool &bNeedAssert, bool &bQuickFunc) +{ + if (_bMinimalMembers && !_bEntry && !isDependent(sNamespace, pPtr->getId())) + { + return ""; + } + + string sStructName = pPtr->getId() + "$OBJ"; + vector &member = pPtr->getAllMemberPtr(); + INC_TAB; + + // Struct + ostringstream s; + s << TAB << "export class " << pPtr->getId() << " {" << endl; + INC_TAB; + + // class members + for (size_t i = 0; i < member.size(); i++) + { + s << TAB << (member[i]->getId()) << ": " + << getTsType(member[i]->getTypePtr()) << " = " + << getDefault(member[i], member[i]->def(), sNamespace) << ";" << endl; + } + if (member.size() > 0) + { + s << endl; + } + + // _classname, _proto_struct_name_ + s << TAB << "protected _proto_struct_name_ = \"\";" << endl; + s << TAB << "protected _classname = \"" << sNamespace << "." << pPtr->getId() << "\";" << endl; + s << TAB << "protected static _classname = \"" << sNamespace << "." << pPtr->getId() << "\";" << endl; + + // _write, _read + s << TAB << "protected static _write(os: " << IDL_NAMESPACE_STR << "Stream.JceOutputStream, tag: number, val: any) { os.writeStruct(tag, val); }" << endl; + s << TAB << "protected static _read(is: " << IDL_NAMESPACE_STR << "Stream.JceInputStream, tag: number, def?: any) { return is.readStruct(tag, true, def); }" << endl; + + // _readFrom + s << TAB << "protected static _readFrom(is: " << IDL_NAMESPACE_STR << "Stream.JceInputStream) {" << endl; + INC_TAB; + + s << TAB << "const tmp = new " << pPtr->getId() << ";" << endl; + for (size_t i = 0; i < member.size(); i++) + { + string sFuncName = toFunctionName(member[i], "read"); + s << TAB << "tmp." << member[i]->getId() << " = is." << sFuncName << "(" << member[i]->getTag() + << ", " << (member[i]->isRequire() ? "true" : "false") << ", "; + + if (isSimple(member[i]->getTypePtr())) + { + s << getDefault(member[i], member[i]->def(), sNamespace) + << (isRawOrString(member[i]->getTypePtr()) ? ", 1" : ""); + } + else + { + s << getDataType(member[i]->getTypePtr(), true); + } + + s << ");" << endl; + } + s << TAB << "return tmp;" << endl; + DEL_TAB; // end of _readFrom + s << TAB << "}" << endl << endl; + + // _writeTo + s << TAB << "protected _writeTo(os: " << IDL_NAMESPACE_STR << "Stream.JceOutputStream) {" << endl; + INC_TAB; + for (size_t i = 0; i < member.size(); i++) + { + string sFuncName = toFunctionName(member[i], "write"); + + s << TAB << "os." << sFuncName << "(" << member[i]->getTag() << ", this." << member[i]->getId() + << (isRawOrString(member[i]->getTypePtr()) ? ", 1" : "") << ");" << endl; + } + DEL_TAB; // end of _writeTo + s << TAB << "}" << endl; + + /* + * Size Optimize: + * Remove support. + * Remove toBinBuffer, readFromObject, toObject, new, create members. + */ + if (_iOptimizeLevel != Os) + { + s << endl; + + // _equal + vector key = pPtr->getKey(); + + s << TAB << "protected _equal(" << (key.size() > 0 ? "anItem: any" : "") << ")" << (key.size() > 0 ? ": boolean" : "") << " {" << endl; + INC_TAB; + + if (key.size() > 0) + { + s << TAB << "return "; + + for (size_t i = 0; i < key.size(); i++) + { + for (size_t ii = 0; ii < member.size(); ii++) + { + if (key[i] != member[ii]->getId()) + { + continue; + } + + if (isSimple(member[i]->getTypePtr())) + { + s << (i==0?"":TAB + TAB) << "this." << key[i] << " === " << "anItem." << key[i]; + } + else + { + s << (i==0?"":TAB + TAB) << "this._equal(" << "anItem)"; + } + } + + if (i != key.size() - 1) + { + s << " && " << endl; + } + } + + s << ";" << endl; + } + else + { + bNeedAssert = true; + s << TAB << "assert.fail(\"this structure not define key operation\");" << endl; + } + + DEL_TAB; + s << TAB << "}" << endl << endl; + + // _genKey + s << TAB << "protected _genKey() {" << endl; + INC_TAB; + s << TAB << "if (!this._proto_struct_name_) {" << endl; + INC_TAB; + s << TAB << "this._proto_struct_name_ = \"STRUCT\" + Math.random();" << endl; + DEL_TAB; + s << TAB << "}" << endl; + s << TAB << "return this._proto_struct_name_;" << endl; + DEL_TAB; + s << TAB << "}" << endl << endl; + + // toObject + s << TAB << "toObject(): " << pPtr->getId() << ".Object { "<< endl; + INC_TAB; + s << TAB << "return {" << endl; + + for (size_t i = 0; i < member.size(); i++) + { + INC_TAB; + if (i > 0 && i < member.size()) { + s << "," << endl; + } + + if (isSimple(member[i]->getTypePtr())) { + s << TAB << member[i]->getId() << ": this." << member[i]->getId(); + } + else { + s << TAB << member[i]->getId() << ": this." << member[i]->getId() << ".toObject()"; + } + DEL_TAB; + } + + s << endl; + s << TAB << "};" << endl; + DEL_TAB; + s << TAB << "}" << endl << endl; + + // readFromObject + s << TAB << "readFromObject(json: " << pPtr->getId() << ".Object) { "<< endl; + INC_TAB; + + for (size_t i = 0; i < member.size(); i++) + { + if (isSimple(member[i]->getTypePtr())) { + s << TAB << "_hasOwnProperty.call(json, \"" << member[i]->getId() << "\") && (this." << member[i]->getId() << " = json." << member[i]->getId() << (member[i]->isRequire() ? "" : "!") << ");" << endl; + } else { + s << TAB << "_hasOwnProperty.call(json, \"" << member[i]->getId() << "\") && (this." << member[i]->getId() << ".readFromObject(json." << member[i]->getId() << (member[i]->isRequire() ? "" : "!") << "));" << endl; + } + bQuickFunc = true; + } + + s << TAB << "return this;" << endl; + + DEL_TAB; + s << TAB << "}" << endl << endl; + + // toBinBuffer + s << TAB << "toBinBuffer() {" << endl; + INC_TAB; + s << TAB << "const os = new " << IDL_NAMESPACE_STR << "Stream." << IDL_TYPE << "OutputStream();" << endl; + s << TAB << "this._writeTo(os);" << endl; + s << TAB << "return os.getBinBuffer();" << endl; + DEL_TAB; + s << TAB << "}" << endl << endl; + + // new + s << TAB << "static new() {" << endl; + INC_TAB; + s << TAB << "return new " << pPtr->getId() << "();" << endl; + DEL_TAB; + s << TAB << "}" << endl << endl; + + // create + s << TAB << "static create(is: " << IDL_NAMESPACE_STR << "Stream.JceInputStream) {" << endl; + INC_TAB; + s << TAB << "return " << sNamespace << "." << pPtr->getId() << "._readFrom(is);" << endl; + DEL_TAB; + s << TAB << "}" << endl; + } + + DEL_TAB; // end of Struct + s << TAB << "}" << endl << endl; + + // Additional namespace + s << TAB << "export namespace " << pPtr->getId() << " {" << endl; + INC_TAB; + s << TAB << "export interface Object {" << endl; + INC_TAB; + for (size_t i = 0; i < member.size(); i++) + { + const string &sType = getTsType(member[i]->getTypePtr(), false); + s << TAB << (member[i]->getId()) << (member[i]->isRequire() ? ": " : "?: ") << (!sType.empty() ? sType : "never") << ";" << endl; + } + DEL_TAB; + s << TAB << "}" << endl; + DEL_TAB; + s << TAB << "}" << endl; + + DEL_TAB; + return s.str(); +} + +string CodeGenerator::generateTS(const NamespacePtr &pPtr, bool &bNeedStream, bool &bNeedAssert, bool &bQuickFunc) +{ + // struct + ostringstream sstr; + vector ss(pPtr->getAllStructPtr()); + for (size_t last = 0; last != ss.size() && ss.size() != 0;) + { + last = ss.size(); + for (vector::iterator iter=ss.begin(); iter!=ss.end();) + { + string str = generateTS(*iter, pPtr->getId(), bNeedAssert, bQuickFunc); + if (!str.empty()) + { + sstr << str << endl; + iter = ss.erase(iter); + } + else + { + iter++; + } + } + } + + // const + ostringstream cstr; + vector &cs = pPtr->getAllConstPtr(); + for (size_t i = 0; i < cs.size(); i++) + { + cstr << generateTS(cs[i], pPtr->getId(), bNeedStream); + } + + // enum + ostringstream estr; + vector &es = pPtr->getAllEnumPtr(); + for (size_t i = 0; i < es.size(); i++) + { + estr << generateTS(es[i], pPtr->getId()); + } + + ostringstream kstr; + if (!estr.str().empty()) + { + bNeedStream = true; + kstr << estr.str() << endl; + } + if (!cstr.str().empty()) kstr << cstr.str() << endl; + if (!sstr.str().empty()) + { + bNeedStream = true; + kstr << sstr.str(); + } + + return kstr.str(); +} + +string CodeGenerator::generateTS(const NamespacePtr &pPtr, const string &sContent) +{ + ostringstream str; + if (!sContent.empty()) + { + str << "export namespace " << pPtr->getId() << " {" << endl; + str << sContent; + str << "}" << endl << endl; + } + return str.str(); +} + +void CodeGenerator::generateTS(const ContextPtr &pPtr) +{ + vector namespaces = pPtr->getNamespaces(); + + // generate encoders and decoders + ostringstream estr; + bool bNeedAssert = false; + bool bNeedStream = false; + bool bQuickFunc = false; + for (size_t i = 0; i < namespaces.size(); i++) + { + estr << generateTS(namespaces[i], generateTS(namespaces[i], bNeedStream, bNeedAssert, bQuickFunc)); + } + if (estr.str().empty()) + { + return; + } + + // generate module imports + ostringstream ostr; + if (bNeedAssert) + { + ostr << "import assert = require(\"assert\");" << endl; + } + if (bNeedStream) + { + ostr << "import * as " << IDL_NAMESPACE_STR << "Stream from \"" << _sStreamPath << "\";" << endl; + } + + for (map::iterator it = _mapFiles.begin(); it != _mapFiles.end(); it++) + { + if (it->second.sModule.empty()) continue; + + if (estr.str().find(it->second.sModule + ".") == string::npos) continue; + + ostr << "import * as " << it->second.sModule << " from \"" << TC_File::excludeFileExt(it->second.sFile) << "\";" << endl; + } + + if (bQuickFunc) + { + ostr << endl; + ostr << "const _hasOwnProperty = Object.prototype.hasOwnProperty;" << endl; + } + + // concat generated code + ostringstream sstr; + sstr << printHeaderRemark("Structure", DISABLE_TSLINT); + sstr << "/// " << endl; + sstr << ostr.str() << endl; + sstr << estr.str() << endl; + + string sFileName = TC_File::excludeFileExt(_sToPath + TC_File::extractFileName(pPtr->getFileName())) + IDL_TYPE + ".ts"; + + TC_File::makeDirRecursive(_sToPath, 0755); + makeUTF8File(sFileName, sstr.str()); +} diff --git a/src/idl_scan.cpp b/src/idl_scan.cpp index 94770f3..d9ccc08 100644 --- a/src/idl_scan.cpp +++ b/src/idl_scan.cpp @@ -29,7 +29,7 @@ string CodeGenerator::makeName() if (iHigh != 0) { - s << string(1, (char)(iHigh + 65)) << string(1, (char)(iLow + 65)); + s << string(1, (char)(iHigh + 65)) << string(1, (char)(iLow + 65)); } else { @@ -46,7 +46,7 @@ bool CodeGenerator::isDependent(const string& sNamespace, const string& sName) c return _depMembers.find(sNamespace + "::" + sName) != _depMembers.end(); } -string CodeGenerator::findName(const string& sNamespace, const string& sName) +string CodeGenerator::findName(const string& sNamespace, const string& sName, const bool &bBase) { #ifdef DUMP_FIND_NAME cout << "FINDNAME BEGIN:" << sNamespace << "|" << sName << endl; @@ -71,17 +71,24 @@ string CodeGenerator::findName(const string& sNamespace, const string& sName) cout << "DEPMEMBER:" << it->first << "|" << inIter->second.sNamespace << "::" << inIter->second.sName << endl; #endif _depMembers.insert(inIter->second.sNamespace + "::" + inIter->second.sName); + string prefix; + + if (bBase && it->second.sModule.empty()) { + prefix = "base."; + } else if (!it->second.sModule.empty()) { + prefix = it->second.sModule + "."; + } switch (inIter->second.iType) { case ImportFileType::EN_ENUM : // [[fallthrough]] case ImportFileType::EN_STRUCT : { - return it->second.sModule + (it->second.sModule.empty()?"":".") + inIter->second.sNamespace + "." + inIter->second.sName; + return prefix + inIter->second.sNamespace + "." + inIter->second.sName; } case ImportFileType::EN_ENUM_VALUE : { - return it->second.sModule + (it->second.sModule.empty()?"":".") + inIter->second.sNamespace + "." + inIter->second.sTypeName + "." + inIter->second.sName; + return prefix + inIter->second.sNamespace + "." + inIter->second.sTypeName + "." + inIter->second.sName; } default : { @@ -172,4 +179,4 @@ void CodeGenerator::scan(const string& sFile, bool bNotPrefix) } } } -} \ No newline at end of file +} diff --git a/src/idl_util.cpp b/src/idl_util.cpp index 70e35d6..ec25eb6 100644 --- a/src/idl_util.cpp +++ b/src/idl_util.cpp @@ -136,7 +136,7 @@ string CodeGenerator::getClassName(const TypePtr& pPtr) return "void"; } -string CodeGenerator::getDataType(const TypePtr& pPtr) +string CodeGenerator::getDataType(const TypePtr& pPtr, const bool &bCastEnumAsAny) { BuiltinPtr bPtr = BuiltinPtr::dynamicCast(pPtr); if (bPtr) @@ -164,7 +164,7 @@ string CodeGenerator::getDataType(const TypePtr& pPtr) return IDL_NAMESPACE_STR + "Stream.BinBuffer"; } - return IDL_NAMESPACE_STR + "Stream.List(" + getDataType(vPtr->getTypePtr()) + (isRawOrString(vPtr->getTypePtr()) ? ", 1" : "") + ")"; + return IDL_NAMESPACE_STR + "Stream.List(" + getDataType(vPtr->getTypePtr(), bCastEnumAsAny) + (isRawOrString(vPtr->getTypePtr()) ? ", 1" : "") + ")"; } StructPtr sPtr = StructPtr::dynamicCast(pPtr); @@ -183,13 +183,13 @@ string CodeGenerator::getDataType(const TypePtr& pPtr) bool bRight = isRawOrString(mPtr->getRightTypePtr()); if (!bRight && !bLeft) { - return IDL_NAMESPACE_STR + "Stream.Map(" + getDataType(mPtr->getLeftTypePtr()) + ", " + getDataType(mPtr->getRightTypePtr()) + ")"; + return IDL_NAMESPACE_STR + "Stream.Map(" + getDataType(mPtr->getLeftTypePtr(), bCastEnumAsAny) + ", " + getDataType(mPtr->getRightTypePtr(), bCastEnumAsAny) + ")"; } else if (bRight && bLeft) { - return IDL_NAMESPACE_STR + "Stream.Map(" + getDataType(mPtr->getLeftTypePtr()) + ", " + getDataType(mPtr->getRightTypePtr()) + ", 1, 1)"; + return IDL_NAMESPACE_STR + "Stream.Map(" + getDataType(mPtr->getLeftTypePtr(), bCastEnumAsAny) + ", " + getDataType(mPtr->getRightTypePtr(), bCastEnumAsAny) + ", 1, 1)"; } else if (bRight) { - return IDL_NAMESPACE_STR + "Stream.Map(" + getDataType(mPtr->getLeftTypePtr()) + ", " + getDataType(mPtr->getRightTypePtr()) + ", 0, 1)"; + return IDL_NAMESPACE_STR + "Stream.Map(" + getDataType(mPtr->getLeftTypePtr(), bCastEnumAsAny) + ", " + getDataType(mPtr->getRightTypePtr(), bCastEnumAsAny) + ", 0, 1)"; } else if (bLeft) { - return IDL_NAMESPACE_STR + "Stream.Map(" + getDataType(mPtr->getLeftTypePtr()) + ", " + getDataType(mPtr->getRightTypePtr()) + ", 1)"; + return IDL_NAMESPACE_STR + "Stream.Map(" + getDataType(mPtr->getLeftTypePtr(), bCastEnumAsAny) + ", " + getDataType(mPtr->getRightTypePtr(), bCastEnumAsAny) + ", 1)"; } else { assert(false); } @@ -200,15 +200,16 @@ string CodeGenerator::getDataType(const TypePtr& pPtr) { vector vecNames = TC_Common::sepstr(ePtr->getSid(), "::"); assert(vecNames.size() == 2); + string suffix = bCastEnumAsAny ? " as any" : ""; - return findName(vecNames[0], vecNames[1]); + return findName(vecNames[0], vecNames[1]) + suffix; } assert(false); return ""; } -string CodeGenerator::getDtsType(const TypePtr &pPtr, const bool bStream) +string CodeGenerator::getTsType(const TypePtr &pPtr, const bool bStream, const bool bBase) { BuiltinPtr bPtr = BuiltinPtr::dynamicCast(pPtr); if (bPtr) @@ -216,7 +217,7 @@ string CodeGenerator::getDtsType(const TypePtr &pPtr, const bool bStream) switch (bPtr->kind()) { case Builtin::KindBool : return "boolean"; - case Builtin::KindString : return _bStringBinaryEncoding ? (bStream ? (IDL_NAMESPACE_STR + "Stream.BinBuffer") : "Buffer") : "string"; + case Builtin::KindString : return _bStringBinaryEncoding ? "Buffer" : "string"; case Builtin::KindByte : return "number"; case Builtin::KindShort : return "number"; case Builtin::KindInt : return "number"; @@ -235,7 +236,7 @@ string CodeGenerator::getDtsType(const TypePtr &pPtr, const bool bStream) { return bStream ? (IDL_NAMESPACE_STR + "Stream.BinBuffer") : "Buffer"; } - return (bStream ? (IDL_NAMESPACE_STR + "Stream.List") : "Array") + string("<") + getDtsType(vPtr->getTypePtr(), bStream) + string(">"); + return (bStream ? (IDL_NAMESPACE_STR + "Stream.List") : "Array") + string("<") + getTsType(vPtr->getTypePtr(), bStream, bBase) + string(">"); } StructPtr sPtr = StructPtr::dynamicCast(pPtr); @@ -244,7 +245,7 @@ string CodeGenerator::getDtsType(const TypePtr &pPtr, const bool bStream) vector vecNames = TC_Common::sepstr(sPtr->getSid(), "::"); assert(vecNames.size() == 2); - return findName(vecNames[0], vecNames[1]) + (bStream ? "" : "$OBJ"); + return findName(vecNames[0], vecNames[1], bBase) + (bStream ? "" : ".Object"); } MapPtr mPtr = MapPtr::dynamicCast(pPtr); @@ -252,20 +253,24 @@ string CodeGenerator::getDtsType(const TypePtr &pPtr, const bool bStream) { if (bStream) { - return IDL_NAMESPACE_STR + "Stream.Map<" + getDtsType(mPtr->getLeftTypePtr(), bStream) + ", " + getDtsType(mPtr->getRightTypePtr(), bStream) + ">"; + // In current version (20190311) of the streaming library, + // TypeScript cannot infer enum type over conditional type correctly. + // So use `HeroMap` instead of `Map` to solve this problem. + EnumPtr keyTypePtr = EnumPtr::dynamicCast(mPtr->getLeftTypePtr()); + string mapName = keyTypePtr ? "HeroMap" : "Map"; + + return IDL_NAMESPACE_STR + "Stream." + mapName + "<" + getTsType(mPtr->getLeftTypePtr(), bStream) + ", " + getTsType(mPtr->getRightTypePtr(), bStream, bBase) + ">"; } else { - const string& sLeftType = getDtsType(mPtr->getLeftTypePtr(), bStream); - if (sLeftType == "number" || sLeftType == "string") + const string& sLeftType = getTsType(mPtr->getLeftTypePtr(), bStream, bBase); + const string& sRightType = getTsType(mPtr->getRightTypePtr(), bStream, bBase); + if (isSimple(mPtr->getLeftTypePtr())) { - return "{[key: " + getDtsType(mPtr->getLeftTypePtr(), bStream) + "]: " + getDtsType(mPtr->getRightTypePtr(), bStream) + "}"; + const string& recordKeyType = sLeftType == "number" ? "number" : "string"; + return "Record<" + recordKeyType + ", " + sRightType + ">"; } - else if (isSimple(mPtr->getLeftTypePtr()) && sLeftType != "Buffer") - { - return "object"; - } - else + else { return ""; } @@ -278,7 +283,7 @@ string CodeGenerator::getDtsType(const TypePtr &pPtr, const bool bStream) vector vecNames = TC_Common::sepstr(ePtr->getSid(), "::"); assert(vecNames.size() == 2); - return findName(vecNames[0], vecNames[1]); + return findName(vecNames[0], vecNames[1], bBase); } assert(false); @@ -330,9 +335,9 @@ string CodeGenerator::getDefault(const TypeIdPtr & pPtr, const string &sDefault, { switch (bPtr->kind()) { - case Builtin::KindBool : + case Builtin::KindBool : return sDefault.empty() ? "false" : sDefault; - case Builtin::KindString : + case Builtin::KindString : { if (_bStringBinaryEncoding) { @@ -357,13 +362,13 @@ string CodeGenerator::getDefault(const TypeIdPtr & pPtr, const string &sDefault, { if (TC_Common::tostr(TC_Common::strto(sTemp)) != sTemp) { - //有可能是枚举值,在枚举值中查找 + // lookup in the enum when it is a enum vector vecNames = TC_Common::sepstr(sDefault, "::"); if (vecNames.size() == 2) { sTemp = findName(vecNames[0], vecNames[1]); } - else + else { sTemp = findName(sNamespace, sDefault); } @@ -386,7 +391,7 @@ string CodeGenerator::getDefault(const TypeIdPtr & pPtr, const string &sDefault, return sTemp; } case Builtin::KindFloat : // [[fallthrough]] - case Builtin::KindDouble : + case Builtin::KindDouble : return sDefault.empty()?"0.0":sDefault; default : assert(false); @@ -433,8 +438,8 @@ string CodeGenerator::getDefault(const TypeIdPtr & pPtr, const string &sDefault, if (bGlobal) { - return "new " + getDataType(pPtr->getTypePtr()); + return "new " + getDataType(pPtr->getTypePtr(), true); } return sDefault; -} \ No newline at end of file +} diff --git a/src/main.cpp b/src/main.cpp index bc5d1cf..0489186 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -38,6 +38,7 @@ void usage() cout << " --r-reserved list of names(split by \",\") that should be keeped." << endl; cout << " --client just for client side source file." << endl; cout << " --server just for server side source file." << endl; + cout << " --ts generate typescript file." << endl; cout << " --dts generate d.ts file." << endl; cout << " --use-string-represent use represent type." << endl; cout << " --string-binary-encoding get string raw bytes ." << endl; @@ -119,7 +120,7 @@ int main(int argc, char* argv[]) #undef ALLOW_USE_RESERVED_NAMESPACE #undef ALLOW_USE_RESERVED_NAMESPACE_BASE #undef ALLOW_USE_RESERVED_NAMESPACE_V - + g_parse->setUseCurrentPath(option.hasParam("relative")); CodeGenerator generator; @@ -132,8 +133,9 @@ int main(int argc, char* argv[]) generator.setUseStringRepresent(option.hasParam("use-string-represent")); generator.setStringBinaryEncoding(option.hasParam("string-binary-encoding")); generator.setEnumReverseMappings(option.hasParam("enum-reverse-mappings")); + generator.setEnableTS(option.hasParam("ts")); generator.setEnableDTS(option.hasParam("dts")); - + if (option.hasParam("optimize")) { string level = TC_Common::lower(option.getValue("optimize")); @@ -197,4 +199,4 @@ int main(int argc, char* argv[]) } return 0; -} \ No newline at end of file +}