diff options
author | Jose <jose@zeroc.com> | 2018-10-16 00:53:00 +0200 |
---|---|---|
committer | Jose <jose@zeroc.com> | 2018-10-16 00:53:00 +0200 |
commit | cf8292f9cdadcb6619287ada4f5273c25c5a3cfb (patch) | |
tree | 4a227f287d2a5e22e36b1f488f00a3c96add7a44 /cpp/src/slice2js/Gen.cpp | |
parent | Updated VS2017 requirement (diff) | |
download | ice-cf8292f9cdadcb6619287ada4f5273c25c5a3cfb.tar.bz2 ice-cf8292f9cdadcb6619287ada4f5273c25c5a3cfb.tar.xz ice-cf8292f9cdadcb6619287ada4f5273c25c5a3cfb.zip |
Typescript support
Diffstat (limited to 'cpp/src/slice2js/Gen.cpp')
-rw-r--r-- | cpp/src/slice2js/Gen.cpp | 1605 |
1 files changed, 1449 insertions, 156 deletions
diff --git a/cpp/src/slice2js/Gen.cpp b/cpp/src/slice2js/Gen.cpp index 7a4e61f3115..be159aa206b 100644 --- a/cpp/src/slice2js/Gen.cpp +++ b/cpp/src/slice2js/Gen.cpp @@ -11,19 +11,11 @@ #include <IceUtil/StringUtil.h> #include <IceUtil/InputUtil.h> #include <Gen.h> -#include <limits> -#include <sys/stat.h> -#ifndef _WIN32 -#include <unistd.h> -#else -#include <direct.h> -#endif #include <IceUtil/Iterator.h> #include <IceUtil/UUID.h> #include <Slice/Checksum.h> #include <Slice/FileTracker.h> #include <Slice/Util.h> -#include <string.h> using namespace std; using namespace Slice; @@ -86,9 +78,289 @@ getDeprecateReason(const ContainedPtr& p1, const ContainedPtr& p2, const string& return deprecateReason; } +void +printHeader(IceUtilInternal::Output& out) +{ + static const char* header = + "// **********************************************************************\n" + "//\n" + "// Copyright (c) 2003-2018 ZeroC, Inc. All rights reserved.\n" + "//\n" + "// This copy of Ice is licensed to you under the terms described in the\n" + "// ICE_LICENSE file included in this distribution.\n" + "//\n" + "// **********************************************************************\n" + ; + + out << header; + out << "//\n"; + out << "// Ice version " << ICE_STRING_VERSION << "\n"; + out << "//\n"; +} + +string +escapeParam(const ParamDeclList& params, const string& name) +{ + string r = name; + for(ParamDeclList::const_iterator p = params.begin(); p != params.end(); ++p) + { + if(Slice::JsGenerator::fixId((*p)->name()) == name) + { + r = name + "_"; + break; + } + } + return r; +} + +void +writeDocLines(Output& out, const StringList& lines, bool commentFirst, const string& space = " ") +{ + StringList l = lines; + if(!commentFirst) + { + out << l.front(); + l.pop_front(); + } + for(StringList::const_iterator i = l.begin(); i != l.end(); ++i) + { + out << nl << " *"; + if(!i->empty()) + { + out << space << *i; + } + } +} + +void +writeSeeAlso(Output& out, const StringList& lines, const string& space = " ") +{ + for(StringList::const_iterator i = lines.begin(); i != lines.end(); ++i) + { + out << nl << " *"; + if(!i->empty()) + { + out << space << "@see " << *i; + } + } +} + +string +getDocSentence(const StringList& lines) +{ + // + // Extract the first sentence. + // + ostringstream ostr; + for(StringList::const_iterator i = lines.begin(); i != lines.end(); ++i) + { + const string ws = " \t"; + + if(i->empty()) + { + break; + } + if(i != lines.begin() && i->find_first_not_of(ws) == 0) + { + ostr << " "; + } + string::size_type pos = i->find('.'); + if(pos == string::npos) + { + ostr << *i; + } + else if(pos == i->size() - 1) + { + ostr << *i; + break; + } + else + { + // + // Assume a period followed by whitespace indicates the end of the sentence. + // + while(pos != string::npos) + { + if(ws.find((*i)[pos + 1]) != string::npos) + { + break; + } + pos = i->find('.', pos + 1); + } + if(pos != string::npos) + { + ostr << i->substr(0, pos + 1); + break; + } + else + { + ostr << *i; + } + } + } + + return ostr.str(); +} + +void +writeDocSummary(Output& out, const ContainedPtr& p) +{ + if(p->comment().empty()) + { + return; + } + + CommentPtr doc = p->parseComment(false); + + out << nl << "/**"; + + if(!doc->overview().empty()) + { + writeDocLines(out, doc->overview(), true); + } + + if(!doc->misc().empty()) + { + writeDocLines(out, doc->misc(), true); + } + + if(!doc->seeAlso().empty()) + { + writeSeeAlso(out, doc->seeAlso()); + } + + if(!doc->deprecated().empty()) + { + out << nl << " *"; + out << nl << " * @deprecated "; + writeDocLines(out, doc->deprecated(), false); + } + else if(doc->isDeprecated()) + { + out << nl << " *"; + out << nl << " * @deprecated"; + } + + out << nl << " */"; +} + +enum OpDocParamType { OpDocInParams, OpDocOutParams, OpDocAllParams }; + +void +writeOpDocParams(Output& out, const OperationPtr& op, const CommentPtr& doc, OpDocParamType type, + const StringList& preParams = StringList(), const StringList& postParams = StringList()) +{ + ParamDeclList params; + switch (type) + { + case OpDocInParams: + params = op->inParameters(); + break; + case OpDocOutParams: + params = op->outParameters(); + break; + case OpDocAllParams: + params = op->parameters(); + break; + } + + if (!preParams.empty()) + { + writeDocLines(out, preParams, true); + } + + map<string, StringList> paramDoc = doc->parameters(); + for (ParamDeclList::iterator p = params.begin(); p != params.end(); ++p) + { + map<string, StringList>::iterator q = paramDoc.find((*p)->name()); + if(q != paramDoc.end()) + { + out << nl << " * @param " << Slice::JsGenerator::fixId(q->first) << " "; + writeDocLines(out, q->second, false); + } + } + + if(!postParams.empty()) + { + writeDocLines(out, postParams, true); + } +} + +void +writeOpDocExceptions(Output& out, const OperationPtr& op, const CommentPtr& doc) +{ + map<string, StringList> exDoc = doc->exceptions(); + for (map<string, StringList>::iterator p = exDoc.begin(); p != exDoc.end(); ++p) + { + // + // Try to locate the exception's definition using the name given in the comment. + // + string name = p->first; + ExceptionPtr ex = op->container()->lookupException(name, false); + if (ex) + { + name = ex->scoped().substr(2); + } + out << nl << " * @throws " << name << " "; + writeDocLines(out, p->second, false); + } } -Slice::JsVisitor::JsVisitor(Output& out) : _out(out) +void +writeOpDocSummary(Output& out, const OperationPtr& op, const CommentPtr& doc, OpDocParamType type, bool showExceptions, + const StringList& preParams = StringList(), const StringList& postParams = StringList(), + const StringList& returns = StringList()) +{ + out << nl << "/**"; + + if (!doc->overview().empty()) + { + writeDocLines(out, doc->overview(), true); + } + + writeOpDocParams(out, op, doc, type, preParams, postParams); + + if(!returns.empty()) + { + out << nl << " * @return "; + writeDocLines(out, returns, false); + } + + if(showExceptions) + { + writeOpDocExceptions(out, op, doc); + } + + if(!doc->misc().empty()) + { + writeDocLines(out, doc->misc(), true); + } + + if(!doc->seeAlso().empty()) + { + writeSeeAlso(out, doc->seeAlso()); + } + + if(!doc->deprecated().empty()) + { + out << nl << " *"; + out << nl << " * @deprecated "; + writeDocLines(out, doc->deprecated(), false); + } + else if(doc->isDeprecated()) + { + out << nl << " *"; + out << nl << " * @deprecated"; + } + + out << nl << " */"; +} + +} + +Slice::JsVisitor::JsVisitor(Output& out, const vector<pair<string, string>>& imports) : + _out(out), + _imports(imports) { } @@ -96,6 +368,12 @@ Slice::JsVisitor::~JsVisitor() { } +vector<pair<string, string>> +Slice::JsVisitor::imports() const +{ + return _imports; +} + void Slice::JsVisitor::writeMarshalDataMembers(const DataMemberList& dataMembers, const DataMemberList& optionalMembers) { @@ -131,7 +409,7 @@ Slice::JsVisitor::writeUnmarshalDataMembers(const DataMemberList& dataMembers, c } void -Slice::JsVisitor::writeInitDataMembers(const DataMemberList& dataMembers, const string& scope) +Slice::JsVisitor::writeInitDataMembers(const DataMemberList& dataMembers) { for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) { @@ -188,7 +466,7 @@ Slice::JsVisitor::getValue(const string& scope, const TypePtr& type) EnumPtr en = EnumPtr::dynamicCast(type); if(en) { - return getReference(scope, en->scoped()) + '.' + fixId((*en->enumerators().begin())->name()); + return fixId(en->scoped()) + '.' + fixId((*en->enumerators().begin())->name()); } StructPtr st = StructPtr::dynamicCast(type); @@ -208,7 +486,7 @@ Slice::JsVisitor::writeConstantValue(const string& scope, const TypePtr& type, c ConstPtr constant = ConstPtr::dynamicCast(valueType); if(constant) { - os << getReference(scope, constant->scoped()); + os << fixId(constant->scoped()); } else { @@ -243,7 +521,7 @@ Slice::JsVisitor::writeConstantValue(const string& scope, const TypePtr& type, c { EnumeratorPtr lte = EnumeratorPtr::dynamicCast(valueType); assert(lte); - os << getReference(scope, ep->scoped()) << '.' << fixId(lte->name()); + os << fixId(ep->scoped()) << '.' << fixId(lte->name()); } else { @@ -331,18 +609,20 @@ Slice::JsVisitor::writeDocComment(const ContainedPtr& p, const string& deprecate _out << nl << " **/"; } -Slice::Gen::Gen(const string& base, const vector<string>& includePaths, const string& dir) : +Slice::Gen::Gen(const string& base, const vector<string>& includePaths, const string& dir, bool typeScript) : _includePaths(includePaths), - _useStdout(false) + _useStdout(false), + _typeScript(typeScript) { _fileBase = base; + string::size_type pos = base.find_last_of("/\\"); if(pos != string::npos) { _fileBase = base.substr(pos + 1); } - string file = _fileBase + ".js"; + string file = _fileBase + (typeScript ? ".d.ts" : ".js"); if(!dir.empty()) { @@ -358,14 +638,16 @@ Slice::Gen::Gen(const string& base, const vector<string>& includePaths, const st } FileTracker::instance()->addFile(file); - printHeader(); + printHeader(_out); printGeneratedHeader(_out, _fileBase + ".ice"); } -Slice::Gen::Gen(const string& base, const vector<string>& includePaths, const string& dir, ostream& out) : +Slice::Gen::Gen(const string& base, const vector<string>& includePaths, const string& dir, bool typeScript, + ostream& out) : _out(out), _includePaths(includePaths), - _useStdout(true) + _useStdout(true), + _typeScript(typeScript) { _fileBase = base; string::size_type pos = base.find_last_of("/\\"); @@ -374,7 +656,7 @@ Slice::Gen::Gen(const string& base, const vector<string>& includePaths, const st _fileBase = base.substr(pos + 1); } - printHeader(); + printHeader(_out); printGeneratedHeader(_out, _fileBase + ".ice"); } @@ -390,70 +672,106 @@ void Slice::Gen::generate(const UnitPtr& p) { // - // Check for global "js:ice-build" and "js:es6-module" - // metadata. If this is set then we are building Ice. + // Check for "js:module:ice" metadata. If this + // is set then we are building Ice. + // + ModuleList modules = p->modules(); + bool icejs = false; + for(ModuleList::const_iterator i = modules.begin(); i != modules.end(); i++) + { + if(p->topLevelFile() == (*i)->definitionContext()->filename() && + getModuleMetadata(ContainedPtr::dynamicCast(*i)) == "ice") + { + icejs = true; + break; + } + } + + // + // Check for global "js:es6-module" metadata. // DefinitionContextPtr dc = p->findDefinitionContext(p->topLevelFile()); assert(dc); StringList globalMetaData = dc->getMetaData(); - bool icejs = find(globalMetaData.begin(), globalMetaData.end(), "js:ice-build") != globalMetaData.end(); bool es6module = find(globalMetaData.begin(), globalMetaData.end(), "js:es6-module") != globalMetaData.end(); - _out << nl << "/* eslint-disable */"; - _out << nl << "/* jshint ignore: start */"; - _out << nl; + if(_typeScript) + { + TypeScriptRequireVisitor requireVisitor(_out); + p->visit(&requireVisitor, false); + requireVisitor.writeRequires(p); + + // + // If at some point TypeScript adds an operator to refer to a type in the global scope + // we can get rid of the TypeScriptAliasVisitor and use this. For now we need to generate + // a type alias when there is an abiguity. + // see: https://github.com/Microsoft/TypeScript/issues/983 + // + TypeScriptAliasVisitor aliasVisitor(_out); + p->visit(&aliasVisitor, false); + aliasVisitor.writeAlias(p); - if(!es6module) + TypeScriptVisitor typeScriptVisitor(_out, requireVisitor.imports()); + p->visit(&typeScriptVisitor, false); + } + else { - if(icejs) - { - _out.zeroIndent(); - _out << nl << "/* slice2js browser-bundle-skip */"; - _out.restoreIndent(); - } - _out << nl << "(function(module, require, exports)"; - _out << sb; - if(icejs) + _out << nl << "/* eslint-disable */"; + _out << nl << "/* jshint ignore: start */"; + _out << nl; + + if(!es6module) { - _out.zeroIndent(); - _out << nl << "/* slice2js browser-bundle-skip-end */"; - _out.restoreIndent(); + if(icejs) + { + _out.zeroIndent(); + _out << nl << "/* slice2js browser-bundle-skip */"; + _out.restoreIndent(); + } + _out << nl << "(function(module, require, exports)"; + _out << sb; + if(icejs) + { + _out.zeroIndent(); + _out << nl << "/* slice2js browser-bundle-skip-end */"; + _out.restoreIndent(); + } } - } - RequireVisitor requireVisitor(_out, _includePaths, icejs, es6module); - p->visit(&requireVisitor, false); - vector<string> seenModules = requireVisitor.writeRequires(p); + RequireVisitor requireVisitor(_out, _includePaths, icejs, es6module); + p->visit(&requireVisitor, false); + vector<string> seenModules = requireVisitor.writeRequires(p); - TypesVisitor typesVisitor(_out, seenModules, icejs); - p->visit(&typesVisitor, false); + TypesVisitor typesVisitor(_out, seenModules, icejs); + p->visit(&typesVisitor, false); - // - // Export the top-level modules. - // - ExportVisitor exportVisitor(_out, icejs, es6module); - p->visit(&exportVisitor, false); + // + // Export the top-level modules. + // + ExportVisitor exportVisitor(_out, icejs, es6module); + p->visit(&exportVisitor, false); - if(!es6module) - { - if(icejs) + if(!es6module) { - _out.zeroIndent(); - _out << nl << "/* slice2js browser-bundle-skip */"; - _out.restoreIndent(); - } + if(icejs) + { + _out.zeroIndent(); + _out << nl << "/* slice2js browser-bundle-skip */"; + _out.restoreIndent(); + } - _out << eb; - _out << nl << "(typeof(global) !== \"undefined\" && typeof(global.process) !== \"undefined\" ? module : undefined," - << nl << " typeof(global) !== \"undefined\" && typeof(global.process) !== \"undefined\" ? require :" - << nl << " (typeof WorkerGlobalScope !== \"undefined\" && self instanceof WorkerGlobalScope) ? self.Ice._require : window.Ice._require," - << nl << " typeof(global) !== \"undefined\" && typeof(global.process) !== \"undefined\" ? exports :" - << nl << " (typeof WorkerGlobalScope !== \"undefined\" && self instanceof WorkerGlobalScope) ? self : window));"; + _out << eb; + _out << nl << "(typeof(global) !== \"undefined\" && typeof(global.process) !== \"undefined\" ? module : undefined," + << nl << " typeof(global) !== \"undefined\" && typeof(global.process) !== \"undefined\" ? require :" + << nl << " (typeof WorkerGlobalScope !== \"undefined\" && self instanceof WorkerGlobalScope) ? self.Ice._require : window.Ice._require," + << nl << " typeof(global) !== \"undefined\" && typeof(global.process) !== \"undefined\" ? exports :" + << nl << " (typeof WorkerGlobalScope !== \"undefined\" && self instanceof WorkerGlobalScope) ? self : window));"; - if(icejs) - { - _out.zeroIndent(); - _out << nl << "/* slice2js browser-bundle-skip-end */"; - _out.restoreIndent(); + if(icejs) + { + _out.zeroIndent(); + _out << nl << "/* slice2js browser-bundle-skip-end */"; + _out.restoreIndent(); + } } } } @@ -464,26 +782,6 @@ Slice::Gen::closeOutput() _out.close(); } -void -Slice::Gen::printHeader() -{ - static const char* header = -"// **********************************************************************\n" -"//\n" -"// Copyright (c) 2003-2018 ZeroC, Inc. All rights reserved.\n" -"//\n" -"// This copy of Ice is licensed to you under the terms described in the\n" -"// ICE_LICENSE file included in this distribution.\n" -"//\n" -"// **********************************************************************\n" - ; - - _out << header; - _out << "//\n"; - _out << "// Ice version " << ICE_STRING_VERSION << "\n"; - _out << "//\n"; -} - Slice::Gen::RequireVisitor::RequireVisitor(IceUtilInternal::Output& out, vector<string> includePaths, bool icejs, bool es6modules) : JsVisitor(out), @@ -549,9 +847,17 @@ void Slice::Gen::RequireVisitor::visitSequence(const SequencePtr& seq) { BuiltinPtr builtin = BuiltinPtr::dynamicCast(seq->type()); - if(builtin && builtin->kind() == Builtin::KindObject) + if(builtin) { - _seenObjectSeq = true; + switch(builtin->kind()) + { + case Builtin::KindObject: + _seenObjectSeq = true; + case Builtin::KindObjectProxy: + _seenObjectProxySeq = true; + default: + break; + } } } @@ -559,9 +865,17 @@ void Slice::Gen::RequireVisitor::visitDictionary(const DictionaryPtr& dict) { BuiltinPtr builtin = BuiltinPtr::dynamicCast(dict->valueType()); - if(builtin && builtin->kind() == Builtin::KindObject) + if(builtin) { - _seenObjectDict = true; + switch(builtin->kind()) + { + case Builtin::KindObject: + _seenObjectDict = true; + case Builtin::KindObjectProxy: + _seenObjectProxyDict = true; + default: + break; + } } } @@ -579,66 +893,12 @@ bool iceBuiltinModule(const string& name) return name == "Glacier2" || name == "Ice" || name == "IceGrid" || name == "IceMX" || name == "IceStorm"; } -string -relativePath(string p1, string p2) -{ - vector<string> tokens1; - vector<string> tokens2; - - splitString(p1, "/\\", tokens1); - splitString(p2, "/\\", tokens2); - - string f1 = tokens1.back(); - string f2 = tokens2.back(); - - tokens1.pop_back(); - tokens2.pop_back(); - - vector<string>::const_iterator i1 = tokens1.begin(); - vector<string>::const_iterator i2 = tokens2.begin(); - - while(i1 != tokens1.end() && i2 != tokens2.end() && *i1 == *i2) - { - i1++; - i2++; - } - - // - // Different volumes, relative path not possible. - // - if(i1 == tokens1.begin() && i2 == tokens2.begin()) - { - return p1; - } - - string newPath; - if(i2 == tokens2.end()) - { - newPath += "./"; - for(; i1 != tokens1.end(); ++i1) - { - newPath += *i1 + "/"; - } - } - else - { - for(;i2 != tokens2.end();++i2) - { - newPath += "../"; - } - } - newPath += f1; - - return newPath; -} - } vector<string> Slice::Gen::RequireVisitor::writeRequires(const UnitPtr& p) { vector<string> seenModules; - map<string, list<string> > requires; if(_icejs) { @@ -925,7 +1185,7 @@ Slice::Gen::TypesVisitor::visitClassDefStart(const ClassDefPtr& p) { base = bases.front(); bases.erase(bases.begin()); - baseRef = getReference(scope, base->scoped()); + baseRef = fixId(base->scoped()); } else { @@ -1040,7 +1300,7 @@ Slice::Gen::TypesVisitor::visitClassDefStart(const ClassDefPtr& p) { _out << nl << "super" << spar << baseParamNames << epar << ';'; } - writeInitDataMembers(dataMembers, scope); + writeInitDataMembers(dataMembers); _out << eb; if(!p->isLocal()) @@ -1091,12 +1351,12 @@ Slice::Gen::TypesVisitor::visitClassDefStart(const ClassDefPtr& p) // // Define servant an proxy types for non local classes // - if(!p->isLocal()) + if(!p->isLocal() && (p->isInterface() || !p->allOperations().empty())) { _out << sp; writeDocComment(p, getDeprecateReason(p, 0, "type")); _out << nl << localScope << "." << (p->isInterface() ? p->name() : p->name() + "Disp") << " = class extends "; - if(hasBaseClass) + if(hasBaseClass && !base->allOperations().empty()) { _out << getLocalScope(base->scope()) << "." << base->name() << "Disp"; } @@ -1140,7 +1400,7 @@ Slice::Gen::TypesVisitor::visitClassDefStart(const ClassDefPtr& p) // Generate a proxy class for interfaces or classes with operations. // string proxyType = "undefined"; - if(p->isInterface() || p->allOperations().size() > 0) + if(p->isInterface() || !p->allOperations().empty()) { proxyType = localScope + '.' + prxName; string baseProxy = "Ice.ObjectPrx"; @@ -1442,7 +1702,7 @@ Slice::Gen::TypesVisitor::visitExceptionStart(const ExceptionPtr& p) string baseRef; if(base) { - baseRef = getReference(scope, base->scoped()); + baseRef = fixId(base->scoped()); } else { @@ -1514,7 +1774,7 @@ Slice::Gen::TypesVisitor::visitExceptionStart(const ExceptionPtr& p) _out << "_cause = \"\"" << epar; _out << sb; _out << nl << "super" << spar << baseParamNames << "_cause" << epar << ';'; - writeInitDataMembers(dataMembers, scope); + writeInitDataMembers(dataMembers); _out << eb; _out << sp; @@ -1529,8 +1789,6 @@ Slice::Gen::TypesVisitor::visitExceptionStart(const ExceptionPtr& p) _out << nl << "return \"" << p->scoped() << "\";"; _out << eb; - // TODO: equals? - if(!p->isLocal()) { _out << sp; @@ -1630,7 +1888,7 @@ Slice::Gen::TypesVisitor::visitStructStart(const StructPtr& p) _out << epar; _out << sb; - writeInitDataMembers(dataMembers, scope); + writeInitDataMembers(dataMembers); _out << eb; if(!p->isLocal()) @@ -1900,3 +2158,1038 @@ Slice::Gen::ExportVisitor::visitModuleStart(const ModulePtr& p) } return false; } + +Slice::Gen::TypeScriptRequireVisitor::TypeScriptRequireVisitor(IceUtilInternal::Output& out) : + JsVisitor(out), + _nextImport(0) +{ +} + +string +Slice::Gen::TypeScriptRequireVisitor::nextImportPrefix() +{ + ostringstream ns; + ns << "iceNS" << _nextImport++; + return ns.str(); +} + +void +Slice::Gen::TypeScriptRequireVisitor::addImport(const TypePtr& definition, const ContainedPtr& toplevel) +{ + if(!BuiltinPtr::dynamicCast(definition)) + { + const string m1 = getModuleMetadata(definition); + const string m2 = getModuleMetadata(toplevel); + + const string p1 = definition->definitionContext()->filename(); + const string p2 = toplevel->definitionContext()->filename(); + + addImport(m1, m2, p1, p2); + } +} + +void +Slice::Gen::TypeScriptRequireVisitor::addImport(const ContainedPtr& definition, const ContainedPtr& toplevel) +{ + const string m1 = getModuleMetadata(definition); + const string m2 = getModuleMetadata(toplevel); + + const string p1 = definition->definitionContext()->filename(); + const string p2 = toplevel->definitionContext()->filename(); + + addImport(m1, m2, p1, p2); +} + +void +Slice::Gen::TypeScriptRequireVisitor::addImport(const string& m1, const string& m2, + const string& p1, const string& p2) +{ + // + // Generate an import for a definition that is outside a JS module and comes from + // a different definition context or for a definition defined in a module different + // than the current module. + // + if(m1.empty()) + { + if(p1 != p2) + { + string relpath = relativePath(p1, p2); + + string::size_type pos = relpath.rfind('.'); + if(pos != string::npos) + { + relpath.erase(pos); + } + + for(vector<pair<string, string>>::const_iterator i = _imports.begin(); i != _imports.end(); ++i) + { + if(i->first == relpath) + { + return; + } + } + _imports.push_back(make_pair(relpath, nextImportPrefix())); + } + } + else if(m1 != m2) + { + for(vector<pair<string, string>>::const_iterator i = _imports.begin(); i != _imports.end(); ++i) + { + if(i->first == m1) + { + return; + } + } + _imports.push_back(make_pair(m1, nextImportPrefix())); + } +} + +bool +Slice::Gen::TypeScriptRequireVisitor::visitModuleStart(const ModulePtr& p) +{ + // + // Import ice module if not building Ice + // + if(UnitPtr::dynamicCast(p->container())) + { + const string prefix = "js:module:"; + string m; + findMetaData(prefix, p->getMetaData(), m); + if(_imports.empty() && m != "ice") + { + _imports.push_back(make_pair("ice", nextImportPrefix())); + } + } + return true; +} + +bool +Slice::Gen::TypeScriptRequireVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + // + // Add imports required for base classes + // + ClassList bases = p->bases(); + for(ClassList::const_iterator i = bases.begin(); i != bases.end(); ++i) + { + addImport(ContainedPtr::dynamicCast(*i), p); + } + + // + // Add imports required for data members + // + const DataMemberList allDataMembers = p->allDataMembers(); + for(DataMemberList::const_iterator i = allDataMembers.begin(); i != allDataMembers.end(); ++i) + { + addImport((*i)->type(), p); + } + + // + // Add imports required for operation parameters and return type + // + const OperationList operationList = p->allOperations(); + for(OperationList::const_iterator i = operationList.begin(); i != operationList.end(); ++i) + { + const TypePtr ret = (*i)->returnType(); + if(ret && ret->definitionContext()) + { + addImport(ret, p); + } + + const ParamDeclList paramList = (*i)->parameters(); + for(ParamDeclList::const_iterator j = paramList.begin(); j != paramList.end(); ++j) + { + addImport((*j)->type(), p); + } + } + return false; +} + +bool +Slice::Gen::TypeScriptRequireVisitor::visitStructStart(const StructPtr& p) +{ + // + // Add imports required for data members + // + const DataMemberList dataMembers = p->dataMembers(); + for(DataMemberList::const_iterator i = dataMembers.begin(); i != dataMembers.end(); ++i) + { + addImport((*i)->type(), p); + } + return false; +} + +bool +Slice::Gen::TypeScriptRequireVisitor::visitExceptionStart(const ExceptionPtr& p) +{ + // + // Add imports required for base exceptions + // + ExceptionPtr base = p->base(); + if(base) + { + addImport(ContainedPtr::dynamicCast(base), p); + } + + // + // Add imports required for data members + // + const DataMemberList allDataMembers = p->allDataMembers(); + for(DataMemberList::const_iterator i = allDataMembers.begin(); i != allDataMembers.end(); ++i) + { + addImport((*i)->type(), p); + } + return false; +} + +void +Slice::Gen::TypeScriptRequireVisitor::visitSequence(const SequencePtr& seq) +{ + // + // Add import required for the sequence element type + // + addImport(seq->type(), seq); +} + +void +Slice::Gen::TypeScriptRequireVisitor::visitDictionary(const DictionaryPtr& dict) +{ + // + // Add imports required for the dictionary key and value types + // + addImport(dict->keyType(), dict); + addImport(dict->valueType(), dict); +} + +void +Slice::Gen::TypeScriptRequireVisitor::writeRequires(const UnitPtr& p) +{ + for(vector<pair<string, string>>::const_iterator i = _imports.begin(); i != _imports.end(); ++i) + { + _out << nl << "import * as " << i->second << " from \"" << i->first << "\""; + } +} + +Slice::Gen::TypeScriptAliasVisitor::TypeScriptAliasVisitor(IceUtilInternal::Output& out) : + JsVisitor(out) +{ +} + +void +Slice::Gen::TypeScriptAliasVisitor::addAlias(const ExceptionPtr& type, const ContainedPtr& toplevel) +{ + string m1 = getModuleMetadata(ContainedPtr::dynamicCast(type)); + string m2 = getModuleMetadata(toplevel); + + // + // Do not add alias for a type defined in the current module + // + if(!m1.empty() && m1 == m2) + { + return; + } + + const string prefix = importPrefix(ContainedPtr::dynamicCast(type), toplevel, imports()); + const string typeS = prefix + getUnqualified(fixId(type->scoped()), toplevel->scope(), prefix); + + addAlias(typeS, prefix, toplevel); +} + +void +Slice::Gen::TypeScriptAliasVisitor::addAlias(const TypePtr& type, const ContainedPtr& toplevel) +{ + string m1 = getModuleMetadata(type); + string m2 = getModuleMetadata(toplevel); + + // + // Do not add alias for a type defined in the current module + // + if(!m1.empty() && m1 == m2) + { + return; + } + + addAlias(typeToString(type, toplevel, imports(), true), + importPrefix(type, toplevel, imports()), + toplevel); +} + +void +Slice::Gen::TypeScriptAliasVisitor::addAlias(const string& type, const string& prefix, + const ContainedPtr& toplevel) +{ + const string scope = fixId(toplevel->scoped()) + "."; + // + // When using an import prefix we don't need an alias, prefixes use iceNSXX that is reserved + // name prefix + // + string::size_type i = type.find("."); + if(prefix.empty() && i != string::npos) + { + if(scope.find("." + type.substr(0, i + 1)) != string::npos) + { + for(vector<pair<string, string>>::const_iterator j = _aliases.begin(); j != _aliases.end(); ++j) + { + if(j->first == type) + { + return; + } + } + string alias = type; + replace(alias.begin(), alias.end(), '.', '_'); + // + // We prefix alias with iceA this avoid conflict with iceNSX used for + // import prefixes + // + _aliases.push_back(make_pair(type, "iceA_" + alias)); + } + } +} + +bool +Slice::Gen::TypeScriptAliasVisitor::visitModuleStart(const ModulePtr& p) +{ + return true; +} + +bool +Slice::Gen::TypeScriptAliasVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + ModulePtr module = ModulePtr::dynamicCast(p->container()); + // + // Add alias required for base classes + // + ClassList bases = p->bases(); + for(ClassList::const_iterator i = bases.begin(); i != bases.end(); ++i) + { + addAlias(TypePtr::dynamicCast((*i)->declaration()), module); + } + + // + // Add alias required for data members + // + const DataMemberList allDataMembers = p->allDataMembers(); + for(DataMemberList::const_iterator i = allDataMembers.begin(); i != allDataMembers.end(); ++i) + { + addAlias((*i)->type(), module); + } + + // + // Add alias required for operation parameters + // + const OperationList operationList = p->allOperations(); + for(OperationList::const_iterator i = operationList.begin(); i != operationList.end(); ++i) + { + const TypePtr ret = (*i)->returnType(); + if(ret && ret->definitionContext()) + { + addAlias(ret, module); + } + + const ParamDeclList paramList = (*i)->parameters(); + for(ParamDeclList::const_iterator j = paramList.begin(); j != paramList.end(); ++j) + { + addAlias((*j)->type(), module); + } + } + return false; +} + +bool +Slice::Gen::TypeScriptAliasVisitor::visitStructStart(const StructPtr& p) +{ + ModulePtr module = ModulePtr::dynamicCast(p->container()); + // + // Add alias required for data members + // + const DataMemberList dataMembers = p->dataMembers(); + for(DataMemberList::const_iterator i = dataMembers.begin(); i != dataMembers.end(); ++i) + { + addAlias((*i)->type(), module); + } + return false; +} + +bool +Slice::Gen::TypeScriptAliasVisitor::visitExceptionStart(const ExceptionPtr& p) +{ + ModulePtr module = ModulePtr::dynamicCast(p->container()); + // + // Add alias required for base exception + // + ExceptionPtr base = p->base(); + if(base) + { + addAlias(base, module); + } + + // + // Add alias required for data members + // + const DataMemberList allDataMembers = p->allDataMembers(); + for(DataMemberList::const_iterator i = allDataMembers.begin(); i != allDataMembers.end(); ++i) + { + addAlias((*i)->type(), module); + } + return false; +} + +void +Slice::Gen::TypeScriptAliasVisitor::visitSequence(const SequencePtr& seq) +{ + addAlias(seq->type(), ModulePtr::dynamicCast(seq->container())); +} + +void +Slice::Gen::TypeScriptAliasVisitor::visitDictionary(const DictionaryPtr& dict) +{ + ModulePtr module = ModulePtr::dynamicCast(dict->container()); + addAlias(dict->keyType(), module); + addAlias(dict->valueType(), module); +} + +void +Slice::Gen::TypeScriptAliasVisitor::writeAlias(const UnitPtr& p) +{ + if(!_aliases.empty()) + { + _out << sp; + for(vector<pair<string, string>>::const_iterator i = _aliases.begin(); i != _aliases.end(); ++i) + { + _out << nl << "type " << i->second << " = " << i->first << ";"; + } + } +} + +Slice::Gen::TypeScriptVisitor::TypeScriptVisitor(::IceUtilInternal::Output& out, + const vector<pair<string, string>>& imports) : + JsVisitor(out, imports) +{ +} + +bool +Slice::Gen::TypeScriptVisitor::visitModuleStart(const ModulePtr& p) +{ + UnitPtr unit = UnitPtr::dynamicCast(p->container()); + if(unit) + { + string module = getModuleMetadata(ContainedPtr::dynamicCast(p)); + + _out << sp; + if(module.empty()) + { + _out << nl << "export namespace " << fixId(p->name()) << sb; + } + else + { + _out << nl << "declare module \"" << fixId(module) << "\"" << sb; + _out << nl << "namespace " << fixId(p->name()) << sb; + } + } + else + { + _out << nl << "namespace " << fixId(p->name()) << sb; + } + return true; +} + +void +Slice::Gen::TypeScriptVisitor::visitModuleEnd(const ModulePtr& p) +{ + _out << eb; // namespace end + + if(UnitPtr::dynamicCast(p->container())) + { + string module = getModuleMetadata(ContainedPtr::dynamicCast(p)); + if(!module.empty()) + { + _out << eb; // module end + } + } +} + +bool +Slice::Gen::TypeScriptVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + const string toplevelModule = getModuleMetadata(ContainedPtr::dynamicCast(p)); + const string icePrefix = importPrefix("Ice.", p); + if(p->isDelegate()) + { + // A delegate only has one operation + OperationPtr op = p->allOperations().front(); + CommentPtr comment = op->parseComment(false); + if(comment) + { + writeOpDocSummary(_out, op, comment, OpDocAllParams, true, StringList(), StringList(), comment->returns()); + } + _out << nl << "type " << fixId(p->name()) << " = " << spar; + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::iterator q = paramList.begin(); q != paramList.end(); ++q) + { + ostringstream os; + os << fixId((*q)->name()) << ":"; + if((*q)->isOutParam()) + { + os << icePrefix << getUnqualified("Ice.Holder", p->scope(), icePrefix) << "<"; + } + os << typeToString((*q)->type(), p, imports(), true, false, true); + if((*q)->isOutParam()) + { + os << ">"; + } + _out << os.str(); + } + _out << epar << " => "; + TypePtr ret = op->returnType(); + if(ret) + { + _out << typeToString(ret, p, imports(), true, false, true) << ";"; + } + else + { + _out << "void;"; + } + } + else if(p->isLocal()) + { + const ClassList bases = p->bases(); + const DataMemberList dataMembers = p->dataMembers(); + const DataMemberList allDataMembers = p->allDataMembers(); + + _out << sp; + writeDocSummary(_out, p); + _out << nl; + _out << (p->isInterface() ? "interface" : "class") << " " << fixId(p->name()); + if(!bases.empty() && !bases.front()->isInterface()) + { + const string prefix = importPrefix(ContainedPtr::dynamicCast(bases.front()), p, imports()); + _out << " extends " << prefix << getUnqualified(fixId(bases.front()->scoped()), p->scope(), prefix); + } + _out << sb; + if(!p->isInterface()) + { + _out << nl << "/**"; + _out << nl << " * One-shot constructor to initialize all data members."; + for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q) + { + CommentPtr comment = (*q)->parseComment(false); + if(comment) + { + _out << nl << " * @param " << fixId((*q)->name()) << " " << getDocSentence(comment->overview()); + } + } + _out << nl << " */"; + _out << nl << "constructor" << spar; + for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q) + { + _out << (fixId((*q)->name()) + "?:" + typeToString((*q)->type(), p, imports(), true, false, true)); + } + _out << epar << ";"; + + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + writeDocSummary(_out, *q); + _out << nl << fixId((*q)->name()) << ":" << typeToString((*q)->type(), p, imports(), true, false, true) + << ";"; + } + } + + OperationList allOperations = p->allOperations(); + for(OperationList::const_iterator q = allOperations.begin(); q != allOperations.end(); ++q) + { + OperationPtr op = *q; + ParamDeclList params = op->parameters(); + ParamDeclList inParams, outParams; + for(ParamDeclList::const_iterator r = params.begin(); r != params.end(); ++r) + { + if((*r)->isOutParam()) + { + outParams.push_back(*r); + } + else + { + inParams.push_back(*r); + } + } + + TypePtr ret = op->returnType(); + bool async = op->hasMetaData("js:async") || op->hasMetaData("async-oneway"); + CommentPtr comment = op->parseComment(false); + if(comment) + { + StringList returns; + if(async) + { + returns.push_back("@returns The asynchronous result object for the invocation."); + } + else if(ret) + { + returns = comment->returns(); + } + writeOpDocSummary(_out, op, comment, OpDocAllParams, true, StringList(), StringList(), returns); + } + + _out << nl << fixId((*q)->name()) << spar; + for(ParamDeclList::const_iterator r = inParams.begin(); r != inParams.end(); r++) + { + _out << (fixId((*r)->name()) + ":" + typeToString((*r)->type(), p, imports(), true, false, true)); + } + + for(ParamDeclList::const_iterator r = outParams.begin(); r != outParams.end(); r++) + { + const string prefix = importPrefix("Ice.Holder", p); + _out << (fixId((*r)->name()) + ":" + prefix + + getUnqualified("Ice.Holder", p->scope(), prefix) + "<" + + typeToString((*r)->type(), p, imports(), true, false, true) + ">"); + } + + _out << epar; + + _out << ":"; + if(async) + { + _out << icePrefix << getUnqualified("Ice.AsyncResultBase", p->scope(), icePrefix) << "<"; + } + + if(ret) + { + _out << typeToString(ret, p, imports(), true, false, true); + } + else + { + _out << "void"; + } + + if (async) + { + _out << ">"; + } + _out << ";"; + } + + if(p->hasMetaData("js:comparable")) + { + _out << nl << "equals(rhs:any):boolean"; + } + _out << eb; + } + else + { + // + // Define servant an proxy types for non local classes + // + _out << sp; + _out << nl << "abstract class " << fixId(p->name() + "Prx") + << " extends " << icePrefix << getUnqualified("Ice.ObjectPrx", p->scope(), icePrefix); + _out << sb; + const OperationList ops = p->allOperations(); + for(OperationList::const_iterator q = ops.begin(); q != ops.end(); ++q) + { + const OperationPtr op = *q; + const ParamDeclList paramList = op->parameters(); + const TypePtr ret = op->returnType(); + ParamDeclList inParams, outParams; + for(ParamDeclList::const_iterator r = paramList.begin(); r != paramList.end(); ++r) + { + if((*r)->isOutParam()) + { + outParams.push_back(*r); + } + else + { + inParams.push_back(*r); + } + } + + const string contextParam = escapeParam(paramList, "context"); + CommentPtr comment = op->parseComment(false); + const string contextDoc = "@param " + contextParam + " The Context map to send with the invocation."; + const string asyncDoc = "The asynchronous result object for the invocation."; + if(comment) + { + StringList postParams, returns; + postParams.push_back(contextDoc); + returns.push_back(asyncDoc); + writeOpDocSummary(_out, op, comment, OpDocInParams, false, StringList(), postParams, returns); + } + _out << nl << fixId((*q)->name()) << spar; + for(ParamDeclList::const_iterator r = inParams.begin(); r != inParams.end(); ++r) + { + _out << (fixId((*r)->name()) + + ((*r)->optional() ? "?" : "") + + ":" + + typeToString((*r)->type(), p, imports(), true, false, true)); + } + _out << "context?:Map<string, string>"; + _out << epar; + + _out << ":" << icePrefix << getUnqualified("Ice.AsyncResult", p->scope(), icePrefix); + if(!ret && outParams.empty()) + { + _out << "<void>"; + } + else if((ret && outParams.empty()) || (!ret && outParams.size() == 1)) + { + TypePtr t = ret ? ret : outParams.front()->type(); + _out << "<" << typeToString(t, p, imports(), true, false, true) << ">"; + } + else + { + _out << "<["; + if(ret) + { + _out << typeToString(ret, p, imports(), true, false, true) << ", "; + } + + for(ParamDeclList::const_iterator i = outParams.begin(); i != outParams.end();) + { + _out << typeToString((*i)->type(), p, imports(), true, false, true); + if(++i != outParams.end()) + { + _out << ", "; + } + } + + _out << "]>"; + } + + _out << ";"; + } + + const string icePrefix = importPrefix("Ice.ObjectPrx", p); + _out << sp; + _out << nl << "/**"; + _out << nl << " * Downcasts a proxy without confirming the target object's type via a remote invocation."; + _out << nl << " * @param prx The target proxy."; + _out << nl << " * @return A proxy with the requested type."; + _out << nl << " */"; + _out << nl << "static uncheckedCast(prx:" << icePrefix + << getUnqualified("Ice.ObjectPrx", p->scope(), icePrefix) << ", " + << "facet?:string):" + << fixId(p->name() + "Prx") << ";"; + _out << nl << "/**"; + _out << nl << " * Downcasts a proxy after confirming the target object's type via a remote invocation."; + _out << nl << " * @param prx The target proxy."; + _out << nl << " * @param facet A facet name."; + _out << nl << " * @param context The context map for the invocation."; + _out << nl << " * @return A proxy with the requested type and facet, or nil if the target proxy is nil or the target"; + _out << nl << " * object does not support the requested type."; + _out << nl << " */"; + _out << nl << "static checkedCast(prx:" << icePrefix + << getUnqualified("Ice.ObjectPrx", p->scope(), icePrefix) << ", " + << "facet?:string, contex?:Map<string, string>):" << icePrefix + << getUnqualified("Ice.AsyncResult", p->scope(), icePrefix) << "<" << fixId(p->name() + "Prx") << ">;"; + _out << eb; + + if(p->isInterface() || !ops.empty()) + { + _out << sp; + _out << nl << "abstract class " << fixId(p->name() + (p->isInterface() ? "" : "Disp")) + << " extends " << icePrefix << getUnqualified("Ice.Object", p->scope(), icePrefix); + _out << sb; + for(OperationList::const_iterator q = ops.begin(); q != ops.end(); ++q) + { + const OperationPtr op = *q; + const ParamDeclList paramList = op->parameters(); + const TypePtr ret = op->returnType(); + ParamDeclList inParams, outParams; + for(ParamDeclList::const_iterator r = paramList.begin(); r != paramList.end(); ++r) + { + if((*r)->isOutParam()) + { + outParams.push_back(*r); + } + else + { + inParams.push_back(*r); + } + } + + const string currentParam = escapeParam(inParams, "current"); + CommentPtr comment = p->parseComment(false); + const string currentDoc = "@param " + currentParam + " The Current object for the invocation."; + const string resultDoc = "The result or a promise like object that will " + "be resolved with the result of the invocation."; + if(comment) + { + StringList postParams, returns; + postParams.push_back(currentDoc); + returns.push_back(resultDoc); + writeOpDocSummary(_out, op, comment, OpDocInParams, false, StringList(), postParams, returns); + } + _out << nl << "abstract " << fixId((*q)->name()) << spar; + for(ParamDeclList::const_iterator r = inParams.begin(); r != inParams.end(); ++r) + { + _out << (fixId((*r)->name()) + ":" + typeToString((*r)->type(), p, imports(), true, false, true)); + } + _out << ("current:" + icePrefix + getUnqualified("Ice.Current", p->scope(), icePrefix)); + _out << epar << ":"; + + if(!ret && outParams.empty()) + { + _out << "PromiseLike<void>|void"; + } + else if((ret && outParams.empty()) || (!ret && outParams.size() == 1)) + { + TypePtr t = ret ? ret : outParams.front()->type(); + string returnType = typeToString(t, p, imports(), true, false, true); + _out << "PromiseLike<" << returnType << ">|" << returnType; + } + else + { + ostringstream os; + if(ret) + { + os << typeToString(ret, p, imports(), true, false, true) << ", "; + } + + for(ParamDeclList::const_iterator i = outParams.begin(); i != outParams.end();) + { + os << typeToString((*i)->type(), p, imports(), true, false, true); + if(++i != outParams.end()) + { + os << ", "; + } + } + _out << "PromiseLike<[" << os.str() << "]>|[" << os.str() << "]"; + } + _out << ";"; + } + _out << nl << "/**"; + _out << nl << " * Obtains the Slice type ID of this type."; + _out << nl << " * @return The return value is always \"" + p->scoped() + "\"."; + _out << nl << " */"; + _out << nl << "static ice_staticId():string;"; + _out << eb; + } + + if(!p->isInterface()) + { + const DataMemberList dataMembers = p->dataMembers(); + const DataMemberList allDataMembers = p->allDataMembers(); + _out << sp; + writeDocSummary(_out, p); + _out << nl << "class " << fixId(p->name()) << " extends "; + const string scope = p->scope(); + const string scoped = p->scoped(); + ClassList bases = p->bases(); + if(!bases.empty() && !bases.front()->isInterface()) + { + ClassDefPtr base = bases.front(); + const string prefix = importPrefix(ContainedPtr::dynamicCast(base), p, imports()); + _out << prefix << getUnqualified(fixId(base->scoped()), p->scope(), prefix); + } + else + { + _out << icePrefix << getUnqualified("Ice.Value", p->scope(), icePrefix); + } + _out << sb; + _out << nl << "/**"; + _out << nl << " * One-shot constructor to initialize all data members."; + for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q) + { + CommentPtr comment = (*q)->parseComment(false); + if(comment) + { + _out << nl << " * @param " << fixId((*q)->name()) << " " << getDocSentence(comment->overview()); + } + } + _out << nl << " */"; + _out << nl << "constructor" << spar; + for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q) + { + _out << (fixId((*q)->name()) + "?:" + typeToString((*q)->type(), p, imports(), true, false, true)); + } + _out << epar << ";"; + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + writeDocSummary(_out, *q); + _out << nl << fixId((*q)->name()) << ":" << typeToString((*q)->type(), p, imports(), true, false, true) + << ";"; + } + _out << eb; + } + } + return false; +} + +bool +Slice::Gen::TypeScriptVisitor::visitExceptionStart(const ExceptionPtr& p) +{ + const string name = fixId(p->name()); + const DataMemberList dataMembers = p->dataMembers(); + const DataMemberList allDataMembers = p->allDataMembers(); + const string toplevelModule = getModuleMetadata(ContainedPtr::dynamicCast(p)); + const string icePrefix = importPrefix("Ice.", p); + + ExceptionPtr base = p->base(); + string baseRef; + if(base) + { + const string prefix = importPrefix(ContainedPtr::dynamicCast(base), p, imports()); + baseRef = prefix + getUnqualified(fixId(base->scoped()), p->scope(), prefix); + } + else + { + baseRef = p->isLocal() ? + icePrefix + getUnqualified("Ice.LocalException", p->scope(), icePrefix) : + icePrefix + getUnqualified("Ice.UserException", p->scope(), icePrefix); + } + + _out << sp; + writeDocSummary(_out, p); + _out << nl << "class " << name << " extends " << baseRef << sb; + if(!allDataMembers.empty()) + { + _out << nl << "/**"; + _out << nl << " * One-shot constructor to initialize all data members."; + for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q) + { + CommentPtr comment = (*q)->parseComment(false); + if(comment) + { + _out << nl << " * @param " << fixId((*q)->name()) << " " << getDocSentence(comment->overview()); + } + } + _out << nl << " */"; + _out << nl << "constructor" << spar; + for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q) + { + _out << (fixId((*q)->name()) + "?:" + typeToString((*q)->type(), p, imports(), true, false, true)); + } + _out << epar << ";"; + } + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + _out << nl << fixId((*q)->name()) << ":" << typeToString((*q)->type(), p, imports(), true, false, true) << ";"; + } + _out << eb; + return false; +} + +bool +Slice::Gen::TypeScriptVisitor::visitStructStart(const StructPtr& p) +{ + const string icePrefix = importPrefix("Ice.", p); + const string name = fixId(p->name()); + const DataMemberList dataMembers = p->dataMembers(); + const string toplevelModule = getModuleMetadata(ContainedPtr::dynamicCast(p)); + _out << sp; + writeDocSummary(_out, p); + _out << nl << "class " << name << sb; + _out << nl << "constructor" << spar; + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + _out << (fixId((*q)->name()) + "?:" + typeToString((*q)->type(), p, imports(), true, false, true)); + } + _out << epar << ";"; + + _out << nl << "clone():" << name << ";"; + _out << nl << "equals(rhs:any):boolean;"; + + // + // Only generate hashCode if this structure type is a legal dictionary key type. + // + bool containsSequence = false; + bool legalKeyType = Dictionary::legalKeyType(p, containsSequence); + if(legalKeyType) + { + _out << nl << "hashCode():number;"; + } + + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + _out << nl << fixId((*q)->name()) << ":" << typeToString((*q)->type(), p, imports(), true, false, true) << ";"; + } + + // + // Streaming API + // + _out << nl << "static write(outs:" << icePrefix << getUnqualified("Ice.OutputStream", p->scope(), icePrefix) + << ", value:" << name << "):void;"; + _out << nl << "static read(ins:" << icePrefix << getUnqualified("Ice.InputStream", p->scope(), icePrefix) << "):" + << name << ";"; + _out << eb; + return false; +} + +void +Slice::Gen::TypeScriptVisitor::visitSequence(const SequencePtr& p) +{ + const string icePrefix = importPrefix("Ice.", p); + const string toplevelModule = getModuleMetadata(ContainedPtr::dynamicCast(p)); + const string name = fixId(p->name()); + _out << sp; + writeDocSummary(_out, p); + _out << nl << "type " << name << " = " << typeToString(p, p, imports(), true, true) << ";"; + + _out << sp; + _out << nl << "class " << fixId(p->name() + "Helper"); + _out << sb; + // + // Streaming API + // + _out << nl << "static write(outs:" << icePrefix << getUnqualified("Ice.OutputStream", p->scope(), icePrefix) + << ", value:" << name << "):void;"; + _out << nl << "static read(ins:" << icePrefix << getUnqualified("Ice.InputStream", p->scope(), icePrefix) << "):" + << name << ";"; + _out << eb; +} + +void +Slice::Gen::TypeScriptVisitor::visitDictionary(const DictionaryPtr& p) +{ + const string icePrefix = importPrefix("Ice.", p); + const string toplevelModule = getModuleMetadata(ContainedPtr::dynamicCast(p)); + const string name = fixId(p->name()); + _out << sp; + writeDocSummary(_out, p); + _out << nl << "class " << name << " extends " << typeToString(p, p, imports(), true, true); + _out << sb; + _out << eb; + + _out << sp; + _out << nl << "class " << fixId(p->name() + "Helper"); + _out << sb; + // + // Streaming API + // + _out << nl << "static write(outs:" << icePrefix << getUnqualified("Ice.OutputStream", p->scope(), icePrefix) + << ", value:" << name << "):void;"; + _out << nl << "static read(ins:" << icePrefix << getUnqualified("Ice.InputStream", p->scope(), icePrefix) << "):" + << name << ";"; + _out << eb; +} + +void +Slice::Gen::TypeScriptVisitor::visitEnum(const EnumPtr& p) +{ + _out << sp; + writeDocSummary(_out, p); + _out << nl << "class " << fixId(p->name()); + _out << sb; + const EnumeratorList enumerators = p->enumerators(); + for(EnumeratorList::const_iterator en = enumerators.begin(); en != enumerators.end(); ++en) + { + writeDocSummary(_out, *en); + _out << nl << "static readonly " << fixId((*en)->name()) << ":" << fixId(p->name()) << ";"; + } + _out << nl; + _out << nl << "static valueOf(value:number):" << fixId(p->name()) << ";"; + _out << nl << "equals(other:any):boolean;"; + _out << nl << "hashCode():number;"; + _out << nl << "toString():string;"; + _out << nl; + _out << nl << "readonly name:string;"; + _out << nl << "readonly value:number;"; + _out << eb; +} + +void +Slice::Gen::TypeScriptVisitor::visitConst(const ConstPtr& p) +{ + const string toplevelModule = getModuleMetadata(p->type()); + _out << sp; + writeDocSummary(_out, p); + _out << nl << "const " << fixId(p->name()) << ":" << typeToString(p->type(), p, imports(), true) << ";"; +} |