Browse Source

add tars2node files

ruanshudong 4 years ago
parent
commit
8dd0fbfaed

+ 516 - 0
tools/tars2node/gen_proxy_ts.cpp

@@ -0,0 +1,516 @@
+/**
+ * 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<ParamDeclPtr> & 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()
+            << representArgument(vParamDecl[i]->getTypeIdPtr()->getTypePtr()) << ");" << 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(), true, true)
+                << representArgument(oPtr->getReturnPtr()->getTypePtr());
+        }
+        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(), true, true)
+                    << representArgument(vParamDecl[i]->getTypeIdPtr()->getTypePtr());
+            }
+            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()
+            << representArgument(vParamDecl[i]->getTypeIdPtr()->getTypePtr()) << ");" << 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, true)
+                << representArgument(oPtr->getReturnPtr()->getTypePtr());
+
+        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 << "Rpc.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<OperationPtr> & 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<InterfacePtr> &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<NamespacePtr> 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");
+    sstr << DISABLE_TSLINT << endl;
+    sstr << DISABLE_ESLINT << endl;
+    sstr << endl;
+    sstr << "/// <reference types=\"node\" />" << 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<string, ImportFile>::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<Ret, Arg>(data: SharedFunctionInfo<Ret, Arg>) { 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<Ret = any, Arg = any> 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<Ret, Arg>," << 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<Ret, Arg>," << 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);
+    makeUTF8File(sFileName, sstr.str());
+
+    return true;
+}

+ 404 - 0
tools/tars2node/gen_server_ts.cpp

@@ -0,0 +1,404 @@
+/**
+ * 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<ParamDeclPtr> & 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.TarsCurrent, " << 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"
+            << representArgument(oPtr->getReturnPtr()->getTypePtr()) << ");" << 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()
+            << representArgument(vParamDecl[i]->getTypeIdPtr()->getTypePtr()) << ");" << 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"
+            << representArgument(oPtr->getReturnPtr()->getTypePtr()) << ");" << 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()
+            << representArgument(vParamDecl[i]->getTypeIdPtr()->getTypePtr()) << ");" << 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<ParamDeclPtr> & vParamDecl = oPtr->getAllParamDeclPtr();
+
+    str << TAB << "protected __" << oPtr->getId() << "(current: " << IDL_NAMESPACE_STR << "Rpc.TarsCurrent";
+    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, true)
+                    << representArgument(vParamDecl[i]->getTypeIdPtr()->getTypePtr());
+        }
+
+        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(), true, true)
+                    << representArgument(vParamDecl[i]->getTypeIdPtr()->getTypePtr());
+        }
+        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<InterfacePtr> & 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<OperationPtr> & 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<any> | void {}" << endl << endl;
+
+    // generate the dispatch function
+    str << TAB << "onDispatch(current: " << IDL_NAMESPACE_STR << "Rpc.TarsCurrent, 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.TarsCurrent) { " << 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<ParamDeclPtr> &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 {" <<endl;
+        INC_TAB;
+        str << TAB;
+        if (oPtr->getReturnPtr()->getTypePtr())
+        {
+            str << "sendResponse(ret: " << getTsType(oPtr->getReturnPtr()->getTypePtr());
+
+            vector<ParamDeclPtr> &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<NamespacePtr> 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");
+    str << DISABLE_TSLINT << endl;
+    str << DISABLE_ESLINT << endl;
+    str << endl;
+    str << "/// <reference types=\"node\" />" << 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<string, ImportFile>::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);
+    makeUTF8File(sFileName, str.str());
+
+    return true;
+}

+ 110 - 0
tools/tars2node/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<NamespacePtr> namespaces = cPtr->getNamespaces();
+
+    // generate the server implementation class
+    ostringstream estr;
+    set<string> setInterface;
+    for(size_t i = 0; i < namespaces.size(); i++)
+    {
+        estr << "export namespace " << namespaces[i]->getId() << " {" << endl;
+        INC_TAB;
+
+        vector<InterfacePtr> & 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<OperationPtr> & 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<ParamDeclPtr> &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<string, ImportFile>::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);
+    makeUTF8File(sFileName, str.str());
+}

+ 446 - 0
tools/tars2node/gen_ts.cpp

@@ -0,0 +1,446 @@
+/**
+ * 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<TypeIdPtr>& 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<int>(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, true) << ";"
+        << 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<TypeIdPtr> &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, true, true) << ";" << 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.TarsOutputStream, tag: number, val: any) { os.writeStruct(tag, val); }" << endl;
+	s << TAB << "protected static _read(is: " << IDL_NAMESPACE_STR << "Stream.TarsInputStream, tag: number, def?: any) { return is.readStruct(tag, true, def); }" << endl;
+
+    // _readFrom
+    s << TAB << "protected static _readFrom(is: " << IDL_NAMESPACE_STR << "Stream.TarsInputStream) {" << 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, true, true)
+                << representArgument(member[i]->getTypePtr());
+        }
+        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.TarsOutputStream) {" << 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()
+            << representArgument(member[i]->getTypePtr()) << ");" << endl;
+    }
+    DEL_TAB;        // end of _writeTo
+    s << TAB << "}" << endl;
+
+    /*
+     *  Size Optimize:
+     *    Remove <mutil_map> support.
+     *    Remove toBinBuffer, readFromObject, toObject, new, create members.
+     */
+    if (_iOptimizeLevel != Os)
+    {
+        s << endl;
+
+        // _equal
+        vector<string> 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.TarsInputStream) {" << 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<StructPtr> ss(pPtr->getAllStructPtr());
+    for (size_t last = 0; last != ss.size() && ss.size() != 0;)
+    {
+        last = ss.size();
+        for (vector<StructPtr>::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<ConstPtr> &cs = pPtr->getAllConstPtr();
+    for (size_t i = 0; i < cs.size(); i++)
+    {
+        cstr << generateTS(cs[i], pPtr->getId(), bNeedStream);
+    }
+
+    // enum
+    ostringstream estr;
+    vector<EnumPtr> &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<NamespacePtr> 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<string, ImportFile>::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");
+    sstr << DISABLE_TSLINT << endl;
+    sstr << DISABLE_ESLINT << endl;
+    sstr << endl;
+    sstr << "/// <reference types=\"node\" />" << 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);
+    makeUTF8File(sFileName, sstr.str());
+}