From a5386d1d00ffb73096128bf120c83f5dc40341c4 Mon Sep 17 00:00:00 2001 From: page Date: Thu, 6 Jun 2024 10:52:43 +0800 Subject: [PATCH] upgrade by darabonba v2 --- lib/builtin.js | 799 ++++++ lib/generator.js | 2145 +++++++++++++++++ lib/helper.js | 101 + package.json | 7 +- src/generator.js | 245 -- src/langs/common/combinator.js | 216 -- src/langs/common/config.js | 33 - src/langs/common/enum.js | 125 - src/langs/common/items.js | 652 ----- src/langs/common/package_info.js | 52 - src/langs/php/combinator.js | 1265 ---------- src/langs/php/config.js | 102 - src/langs/php/files/composer.json.tmpl | 24 - src/langs/php/modules.js | 118 - src/langs/php/package_info.js | 163 -- src/lib/debug.js | 60 - src/lib/emitter.js | 102 - src/lib/helper.js | 326 --- src/resolver/base.js | 272 --- src/resolver/client.js | 1067 -------- src/resolver/model.js | 133 - .../php/files => templates}/.gitignore.tmpl | 0 .../php/files => templates}/.php_cs.dist.tmpl | 0 .../php/files => templates}/autoload.php.tmpl | 0 .../files => templates}/bootstrap.php.tmpl | 0 tests/common.tests.js | 270 --- tests/expected/alias/Client.php | 24 +- tests/expected/annotation/Client.php | 127 +- tests/expected/annotation/Models/Test.php | 73 +- tests/expected/api/Client.php | 125 +- tests/expected/builtin/Client.php | 433 ++++ tests/expected/comment/Client.php | 354 +-- tests/expected/comment/Models/Test1.php | 107 +- tests/expected/comment/Models/Test2.php | 103 +- tests/expected/comment/Models/Test3.php | 109 +- tests/expected/complex/Client.php | 761 +++--- tests/expected/complex/Exceptions/Err1.php | 27 + tests/expected/complex/Exceptions/Err2.php | 27 + .../complex/Models/ComplexRequest.php | 323 +-- .../complex/Models/ComplexRequest/configs.php | 138 +- .../complex/Models/ComplexRequest/header.php | 71 +- .../complex/Models/ComplexRequest/part.php | 67 +- tests/expected/const/Client.php | 17 +- tests/expected/empty/Client.php | 5 +- tests/expected/exec/Client.php | 21 +- tests/expected/function/Client.php | 101 +- tests/expected/import/Client.php | 63 +- tests/expected/map/Client.php | 41 +- tests/expected/map/Models/A.php | 99 +- tests/expected/map/Models/B.php | 92 +- tests/expected/model/Client.php | 5 +- .../model/Exceptions/MainFileError.php | 52 + tests/expected/model/Models/Class_.php | 45 +- tests/expected/model/Models/M.php | 72 +- tests/expected/model/Models/M/subM.php | 45 +- .../Models/MainFileError/model/model_.php | 49 + .../model/Models/MainFileError/model_.php | 66 + tests/expected/model/Models/MyModel.php | 1353 +++++++---- .../model/Models/MyModel/model/model_.php | 66 +- .../expected/model/Models/MyModel/model_.php | 91 +- .../model/Models/MyModel/subarraymodel.php | 45 +- .../model/Models/MyModel/submodel.php | 92 +- .../model/Models/MyModel/submodel/model_.php | 66 +- tests/expected/model/Models/model_.php | 66 +- tests/expected/multi/Client.php | 46 + tests/expected/multi/api.php | 74 + tests/expected/multi/lib/util.php | 25 + tests/expected/multi/model/Models/Info.php | 81 + tests/expected/multi/model/user.php | 32 + tests/expected/number/Client.php | 38 +- tests/expected/package/composer.json | 12 +- tests/expected/package/src/Client.php | 3 + tests/expected/statements/Client.php | 151 +- tests/expected/super/Client.php | 17 +- tests/expected/typedef/composer.json | 20 +- tests/expected/typedef/src/Client.php | 110 +- tests/expected/typedef/src/Models/M.php | 91 +- .../fixtures/alias/libraries/Import/Darafile | 3 + .../alias/libraries/Import/import.dara | 4 +- .../fixtures/alias/libraries/Source/Darafile | 3 + .../alias/libraries/Source/source.dara | 4 +- tests/fixtures/alias/main.dara | 6 +- tests/fixtures/annotation/main.dara | 2 +- tests/fixtures/builtin/Darafile | 6 + tests/fixtures/builtin/main.dara | 346 +++ tests/fixtures/comment/libraries/Darafile | 3 + tests/fixtures/comment/main.dara | 8 +- tests/fixtures/complex/libraries/Darafile | 3 + tests/fixtures/complex/main.dara | 49 +- tests/fixtures/function/main.dara | 2 +- tests/fixtures/import/libraries/Darafile | 3 + tests/fixtures/map/libraries/Darafile | 3 + tests/fixtures/map/main.dara | 6 +- tests/fixtures/model/libraries/Darafile | 6 +- tests/fixtures/model/main.dara | 15 + tests/fixtures/multi/.libraries.json | 3 + tests/fixtures/multi/Darafile | 9 + tests/fixtures/multi/api.dara | 21 + tests/fixtures/multi/lib/util.dara | 3 + .../libraries/darabonba_Util_0.2.11/Teafile | 62 + .../libraries/darabonba_Util_0.2.11/main.tea | 244 ++ tests/fixtures/multi/model/user.dara | 24 + tests/fixtures/multi/sdk.dara | 25 + .../libraries/darabonba_Number_0.0.0/Darafile | 10 +- tests/fixtures/number/main.dara | 14 +- tests/fixtures/super/libraries/Darafile | 3 + tests/fixtures/super/main.dara | 2 +- tests/fixtures/typedef/.libraries.json | 2 +- tests/fixtures/typedef/Darafile | 2 +- .../{alibabacloud-OSS-0.0.1 => }/Darafile | 3 + .../{alibabacloud-OSS-0.0.1 => }/oss.dara | 2 +- tests/fixtures/typedef/main.dara | 7 +- tests/lib.tests.js | 256 -- tests/main.test.js | 255 ++ tests/php.tests.js | 170 -- tests/resolver.tests.js | 408 ---- 116 files changed, 8151 insertions(+), 8244 deletions(-) create mode 100644 lib/builtin.js create mode 100644 lib/generator.js create mode 100644 lib/helper.js delete mode 100644 src/generator.js delete mode 100644 src/langs/common/combinator.js delete mode 100644 src/langs/common/config.js delete mode 100644 src/langs/common/enum.js delete mode 100644 src/langs/common/items.js delete mode 100644 src/langs/common/package_info.js delete mode 100644 src/langs/php/combinator.js delete mode 100644 src/langs/php/config.js delete mode 100644 src/langs/php/files/composer.json.tmpl delete mode 100644 src/langs/php/modules.js delete mode 100644 src/langs/php/package_info.js delete mode 100644 src/lib/debug.js delete mode 100644 src/lib/emitter.js delete mode 100644 src/lib/helper.js delete mode 100644 src/resolver/base.js delete mode 100644 src/resolver/client.js delete mode 100644 src/resolver/model.js rename {src/langs/php/files => templates}/.gitignore.tmpl (100%) rename {src/langs/php/files => templates}/.php_cs.dist.tmpl (100%) rename {src/langs/php/files => templates}/autoload.php.tmpl (100%) rename {src/langs/php/files => templates}/bootstrap.php.tmpl (100%) delete mode 100644 tests/common.tests.js create mode 100644 tests/expected/builtin/Client.php create mode 100644 tests/expected/complex/Exceptions/Err1.php create mode 100644 tests/expected/complex/Exceptions/Err2.php create mode 100644 tests/expected/model/Exceptions/MainFileError.php create mode 100644 tests/expected/model/Models/MainFileError/model/model_.php create mode 100644 tests/expected/model/Models/MainFileError/model_.php create mode 100644 tests/expected/multi/Client.php create mode 100644 tests/expected/multi/api.php create mode 100644 tests/expected/multi/lib/util.php create mode 100644 tests/expected/multi/model/Models/Info.php create mode 100644 tests/expected/multi/model/user.php create mode 100644 tests/fixtures/builtin/Darafile create mode 100644 tests/fixtures/builtin/main.dara create mode 100644 tests/fixtures/multi/.libraries.json create mode 100644 tests/fixtures/multi/Darafile create mode 100644 tests/fixtures/multi/api.dara create mode 100644 tests/fixtures/multi/lib/util.dara create mode 100644 tests/fixtures/multi/libraries/darabonba_Util_0.2.11/Teafile create mode 100644 tests/fixtures/multi/libraries/darabonba_Util_0.2.11/main.tea create mode 100644 tests/fixtures/multi/model/user.dara create mode 100644 tests/fixtures/multi/sdk.dara rename tests/fixtures/typedef/libraries/{alibabacloud-OSS-0.0.1 => }/Darafile (88%) rename tests/fixtures/typedef/libraries/{alibabacloud-OSS-0.0.1 => }/oss.dara (69%) delete mode 100644 tests/lib.tests.js create mode 100644 tests/main.test.js delete mode 100644 tests/php.tests.js delete mode 100644 tests/resolver.tests.js diff --git a/lib/builtin.js b/lib/builtin.js new file mode 100644 index 0000000..b0ed508 --- /dev/null +++ b/lib/builtin.js @@ -0,0 +1,799 @@ +'use strict'; +const DSL = require('@darabonba/parser'); +const { _vid, _name, _string } = require('./helper'); + +const types = [ + 'integer', 'int8', 'int16', 'int32', + 'int64', 'long', 'ulong', 'string', + 'uint8', 'uint16', 'uint32', 'uint64', + 'number', 'float', 'double', 'boolean', + 'bytes', 'readable', 'writable', 'object', 'any' +]; + +const integers = [ + 'integer', 'int8', 'int16', 'int32', + 'int64', 'long', 'ulong', + 'uint8', 'uint16', 'uint32', 'uint64' +]; + +const floats = ['float', 'double']; +const BuiltinModule = { + DaraBuiltin: { + namespace: 'AlibabaCloud\\Dara\\Util', + className: 'Utils', + }, + DaraString: { + namespace: 'AlibabaCloud\\Dara\\Util', + className: 'StringUtil', + }, + DaraMath: { + namespace: 'AlibabaCloud\\Dara\\Util', + className: 'MathUtil', + }, + DaraStream: { + namespace: 'AlibabaCloud\\Dara\\Util', + className: 'StreamUtil', + }, + DaraConsole: { + namespace: 'AlibabaCloud\\Dara\\Util', + className: 'Console', + }, + DaraXML: { + namespace: 'AlibabaCloud\\Dara\\Util', + className: 'XML', + }, + DaraURL: { + namespace: 'AlibabaCloud\\Dara', + className: 'URL', + }, + DaraForm: { + namespace: 'AlibabaCloud\\Dara\\Util', + className: 'FormUtil', + }, + DaraFile: { + namespace: 'AlibabaCloud\\Dara', + className: 'File', + }, + DaraBytes: { + namespace: 'AlibabaCloud\\Dara\\Util', + className: 'BytesUtil', + }, + DaraDate: { + namespace: 'AlibabaCloud\\Dara', + className: 'Date', + }, +}; +class Builtin { + constructor(generator, aliasId = 'DaraBuiltin', methods = []){ + this.generator = generator; + this.module = module; + this.aliasId = aliasId; + + + methods.forEach(method => { + this[method] = function(args, level) { + const clientName = this.getClientName(); + this.generator.emit(`${clientName}::${method}`); + this.generator.visitArgs(args, level); + }; + }); + } + + getInstanceName(ast) { + if (ast.left.id.tag === DSL.Tag.Tag.VID) { + this.generator.emit(`$this->${_vid(ast.left.id)}`); + } else { + this.generator.emit(`$${_name(ast.left.id)}`); + } + } + + getClientName() { + if(!this.generator.moduleClass.has(this.aliasId)) { + const { namespace, className } = BuiltinModule[this.aliasId]; + this.generator.moduleClass.set(this.aliasId, { + namespace, + className, + aliasName: this.generator.getAliasName(namespace, className, 'Dara') + }); + } + + return this.generator.getRealClientName(this.aliasId); + } +} + +class Env extends Builtin { + constructor(generator){ + super(generator); + } + + get(args){ + const key = args[0]; + this.generator.emit('getenv('); + this.generator.visitExpr(key); + this.generator.emit(')'); + } + + set(args){ + const key = args[0]; + this.generator.emit('putenv('); + if(key.type === 'string') { + this.generator.emit(`'${_string(key.value)}=`); + } else { + this.generator.visitExpr(key); + this.generator.emit('.\'='); + } + + const value = args[1]; + if(value.type === 'string') { + this.generator.emit(`${_string(value.value)}'`); + } else { + this.generator.emit('\'.'); + this.generator.visitExpr(value); + } + this.generator.emit(')'); + } +} + +class Logger extends Builtin { + constructor(generator){ + const methods = ['log', 'info', 'debug', 'error', 'warning']; + super(generator, 'DaraConsole', methods); + } +} + +class XML extends Builtin { + constructor(generator){ + const methods = ['parseXml', 'toXML']; + super(generator, 'DaraXML', methods); + } +} + +class URL extends Builtin { + constructor(generator){ + const methods = ['parse', 'urlEncode', 'percentEncode', 'pathEncode']; + super(generator, 'DaraURL', methods); + } +} + +class Stream extends Builtin { + constructor(generator){ + const methods = ['readAsBytes', 'readAsJSON', 'readAsString', 'readAsSSE', 'streamFor']; + super(generator, 'DaraStream', methods); + } +} + +class Number extends Builtin { + constructor(generator){ + const methods = ['random']; + super(generator, 'DaraMath', methods); + } + + floor(args) { + this.generator.emit('floor'); + this.generator.visitArgs(args); + } + + round(args) { + this.generator.emit('round'); + this.generator.visitArgs(args); + } + + min(args) { + this.generator.emit('min'); + this.generator.visitArgs(args); + } + + max(args) { + this.generator.emit('max'); + this.generator.visitArgs(args); + } + + parseInt(ast) { + this.generator.emit('intval(\'\'.'); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + parseLong(ast) { + this.generator.emit('intval(\'\'.'); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + parseFloat(ast) { + this.generator.emit('floatval(\'\'.'); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + parseDouble(ast) { + this.generator.emit('floatval(\'\'.'); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + itol(ast) { + this.getInstanceName(ast); + } + + ltoi(ast) { + this.getInstanceName(ast); + } +} + +class JSON extends Builtin { + stringify(args, level) { + const expr = args[0]; + this.generator.emit('json_encode('); + this.generator.visitExpr(expr, level); + if(expr.inferred && expr.inferred.type === 'model') { + this.generator.emit('->toArray()'); + } + this.generator.emit(', JSON_UNESCAPED_UNICODE + JSON_UNESCAPED_SLASHES)'); + } + + parseJSON(args, level){ + const expr = args[0]; + this.generator.emit('json_decode('); + this.generator.visitExpr(expr, level); + this.generator.emit(', true)'); + } +} + +class Form extends Builtin { + constructor(generator){ + const methods = ['toFormString', 'getBoundary', 'toFileForm']; + super(generator, 'DaraForm', methods); + } +} + +class File extends Builtin { + constructor(generator){ + const methods = ['createReadStream', 'createWriteStream', 'exists']; + super(generator, 'DaraFile', methods); + } +} + +class DaraDate extends Builtin { + constructor(generator){ + const methods = [ + 'format', 'unix', 'diff', 'UTC', 'add', 'sub', 'hour', + 'minute', 'second', 'dayOfYear', 'dayOfMonth', 'dayOfWeek', + 'weekOfYear', 'weekOfMonth', 'month', 'year' + ]; + super(generator, 'DaraDate', methods); + } +} + +class Bytes extends Builtin { + constructor(generator){ + super(generator, 'DaraBytes'); + } + + from(args) { + const clientName = this.getClientName(); + this.generator.emit(`${clientName}::from`); + this.generator.visitArgs(args); + } + + toString(ast) { + const clientName = this.getClientName(); + this.generator.emit(`${clientName}::toString(`); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + toHex(ast) { + const clientName = this.getClientName(); + this.generator.emit('bin2hex('); + this.generator.emit(`${clientName}::toString(`); + this.getInstanceName(ast); + this.generator.emit('))'); + } + + toBase64(ast) { + const clientName = this.getClientName(); + this.generator.emit('base64_encode('); + this.generator.emit(`${clientName}::toString(`); + this.getInstanceName(ast); + this.generator.emit('))'); + } + + toJSON(ast) { + const clientName = this.getClientName(); + this.generator.emit(`${clientName}::toString(`); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + length(ast){ + this.generator.emit('strlen('); + this.getInstanceName(ast); + this.generator.emit(')'); + } +} + + +class Converter { + constructor(generator){ + this.generator = generator; + this.stream = new Stream(generator); + integers.forEach(type => { + this[type] = function(args) { + const expr = args[0]; + generator.emit('intval('); + generator.visitExpr(expr); + generator.emit(')'); + }; + }); + + floats.forEach(type => { + this[type] = function(args) { + const expr = args[0]; + generator.emit('floatval('); + generator.visitExpr(expr); + generator.emit(')'); + }; + }); + } + + string(args) { + const expr = args[0]; + this.generator.emit('\'\'.'); + this.generator.visitExpr(expr); + } + + number(args) { + const expr = args[0]; + this.generator.emit('('); + this.generator.visitExpr(expr); + this.generator.emit(' + 0)'); + } + + boolean(args) { + const expr = args[0]; + this.generator.emit('boolval('); + this.generator.visitExpr(expr); + this.generator.emit(')'); + } + + bytes(args) { + const expr = args[0]; + this.generator.emit('unpack(\'C*\', '); + this.generator.visitExpr(expr); + this.generator.emit(')'); + } + + any(args){ + const expr = args[0]; + this.generator.visitExpr(expr); + } + + object(args){ + const expr = args[0]; + this.generator.visitExpr(expr); + } + + readable(args){ + this.stream.streamFor(args); + } + + writable(args){ + this.stream.streamFor(args); + } +} + +class Func { + constructor(generator){ + this.generator = generator; + } + + isNull(args) { + this.generator.emit('is_null'); + this.generator.visitArgs(args); + } + + sleep(args) { + this.generator.emit('usleep'); + this.generator.visitArgs(args); + } + + equal(args){ + this.generator.visitExpr(args[0]); + this.generator.emit(' === '); + this.generator.visitExpr(args[1]); + } + + default(args){ + this.generator.emit('('); + this.generator.visitExpr(args[0]); + this.generator.emit(' ? '); + this.generator.visitExpr(args[0]); + this.generator.emit(' : '); + this.generator.visitExpr(args[1]); + this.generator.emit(')'); + } +} + +class String extends Builtin { + + constructor(generator, methods = []){ + super(generator, 'DaraString', methods); + } + + split(ast, level) { + this.generator.emit('explode('); + this.getInstanceName(ast); + const args = ast.args; + this.generator.emit(', '); + const expr = args[0]; + this.generator.visitExpr(expr, level); + this.generator.emit(')'); + } + + replace(ast, level) { + const args = ast.args; + const regex = args[0]; + this.generator.emit('preg_replace('); + this.generator.visitExpr(regex, level); + this.generator.emit(', '); + this.generator.visitExpr(args[1], level); + this.generator.emit(', '); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + contains(ast, level) { + this.generator.emit('false !== strpos('); + + this.getInstanceName(ast); + const args = ast.args; + this.generator.emit(', '); + const expr = args[0]; + this.generator.visitExpr(expr, level); + this.generator.emit(')'); + } + + length(ast) { + this.generator.emit('strlen('); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + hasPrefix(ast, level) { + const clientName = this.getClientName(); + const args = ast.args; + this.generator.emit(`${clientName}::hasPrefix(`); + this.getInstanceName(ast); + this.generator.emit(', '); + const expr = args[0]; + this.generator.visitExpr(expr, level); + this.generator.emit(')'); + } + + hasSuffix(ast, level) { + const clientName = this.getClientName(); + const args = ast.args; + this.generator.emit(`${clientName}::hasSuffix(`); + this.getInstanceName(ast); + this.generator.emit(', '); + const expr = args[0]; + this.generator.visitExpr(expr, level); + this.generator.emit(')'); + } + + index(ast, level) { + this.generator.emit('strpos('); + + this.getInstanceName(ast); + const args = ast.args; + this.generator.emit(', '); + const expr = args[0]; + this.generator.visitExpr(expr, level); + this.generator.emit(')'); + } + + subString(ast, level) { + this.generator.emit('substr('); + + this.getInstanceName(ast); + const args = ast.args; + this.generator.emit(', '); + const start = args[0]; + this.generator.visitExpr(start, level); + this.generator.emit(', '); + const end = args[1]; + this.generator.visitExpr(end, level); + this.generator.emit(')'); + } + + toLower(ast) { + this.generator.emit('strtolower('); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + toUpper(ast) { + this.generator.emit('strtoupper('); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + equals(ast) { + this.getInstanceName(ast); + const args = ast.args; + const expr = args[0]; + this.generator.emit(' === '); + this.generator.visitExpr(expr); + + } + + trim(ast) { + this.generator.emit('trim('); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + empty_(ast) { + this.generator.emit('empty('); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + toBytes(ast) { + const clientName = this.getClientName(); + this.generator.emit(`${clientName}::toBytes(`); + this.getInstanceName(ast); + const args = ast.args; + const expr = args[0]; + this.generator.emit(', '); + this.generator.visitExpr(expr); + this.generator.emit(')'); + } + + parseInt(ast) { + this.generator.emit('intval('); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + parseLong(ast) { + this.generator.emit('intval('); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + parseFloat(ast) { + this.generator.emit('floatval('); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + parseDouble(ast) { + this.generator.emit('floatval('); + this.getInstanceName(ast); + this.generator.emit(')'); + } +} + +class Array extends Builtin { + join(ast ,level) { + const args = ast.args; + this.generator.emit('implode('); + const expr = args[0]; + this.generator.visitExpr(expr, level); + this.generator.emit(', '); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + full(ast, level) { + const args = ast.args; + const expr = args[0]; + this.generator.emit('array_map(function($item) {\n', level); + this.generator.emit('return ', level + 1); + this.generator.visitExpr(expr); + this.generator.emit('\n'); + this.generator.emit('}, ', level); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + shift(ast) { + this.generator.emit('array_shift('); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + pop(ast) { + this.generator.emit('array_pop('); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + push(ast) { + const args = ast.args; + const expr = args[0]; + this.generator.emit('array_pop('); + this.getInstanceName(ast); + this.generator.emit(', '); + this.generator.visitExpr(expr); + this.generator.emit(')'); + } + + unshift(ast) { + const args = ast.args; + const expr = args[0]; + this.generator.emit('array_unshift('); + this.getInstanceName(ast); + this.generator.emit(', '); + this.generator.visitExpr(expr); + this.generator.emit(')'); + } + + contains(ast, level) { + const args = ast.args; + this.generator.emit('\\in_array('); + const expr = args[0]; + this.generator.visitExpr(expr, level); + this.generator.emit(', '); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + concat(ast, level) { + const args = ast.args; + this.generator.emit('array_merge('); + const expr = args[0]; + this.generator.visitExpr(expr, level); + this.generator.emit(', '); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + length(ast) { + this.generator.emit('\\count('); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + index(ast, level) { + const args = ast.args; + this.generator.emit('array_search('); + const expr = args[0]; + this.generator.visitExpr(expr, level); + this.generator.emit(', '); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + get(ast, level) { + this.getInstanceName(ast); + const args = ast.args; + this.generator.emit('['); + const expr = args[0]; + this.generator.visitExpr(expr, level); + this.generator.emit(']'); + } + + sort(ast) { + const order = _string(ast.args[0].value); + if(order.toLowerCase() === 'asc') { + this.generator.emit('sort('); + } else if(order.toLowerCase() === 'desc'){ + this.generator.emit('rsort('); + } else { + throw Error('un-impelemented'); + } + + this.getInstanceName(ast); + this.generator.emit(')'); + } + + append(ast) { + const position = ast.args[1]; + const value = ast.args[0]; + this.generator.emit('array_splice('); + this.getInstanceName(ast); + this.generator.emit(', '); + this.generator.visitExpr(position); + this.generator.emit(', 0, '); + this.generator.visitExpr(value); + this.generator.emit(')'); + } + + remove(ast) { + const value = ast.args[0]; + this.generator.emit('array_splice('); + this.getInstanceName(ast); + this.generator.emit(', array_search('); + this.generator.visitExpr(value); + this.generator.emit(', '); + this.getInstanceName(ast); + this.generator.emit('), 1)'); + } +} + +class Map extends Builtin { + + length(ast) { + this.generator.emit('\\count('); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + keySet(ast) { + this.generator.emit('array_keys('); + this.getInstanceName(ast); + this.generator.emit(')'); + } + + entries(ast) { + this.generator.emit('array_map(null, '); + this.generator.emit('array_keys('); + this.getInstanceName(ast); + this.generator.emit('), '); + this.generator.emit('array_values('); + this.getInstanceName(ast); + this.generator.emit('))'); + } + + toJSON(ast) { + this.generator.emit('json_encode('); + this.getInstanceName(ast); + this.generator.emit(', JSON_UNESCAPED_UNICODE + JSON_UNESCAPED_SLASHES)'); + } + + merge(ast) { + this.generator.emit('array_merge('); + this.getInstanceName(ast); + this.generator.emit(' , '); + this.generator.visitExpr(ast.args[0]); + this.generator.emit(')'); + } +} + +class Entry extends Builtin { + + key(ast) { + this.getInstanceName(ast); + this.generator.emit('[0]'); + } + + value(ast) { + this.getInstanceName(ast); + this.generator.emit('[1]'); + } +} + +module.exports = (generator) => { + const builtin = {}; + builtin['$Env'] = new Env(generator); + builtin['$Logger'] = new Logger(generator); + builtin['$XML'] = new XML(generator); + builtin['$URL'] = new URL(generator); + builtin['$Stream'] = new Stream(generator); + builtin['$Number'] = new Number(generator); + builtin['$JSON'] = new JSON(generator); + builtin['$Form'] = new Form(generator); + builtin['$File'] = new File(generator); + builtin['$Bytes'] = new Bytes(generator); + const converter = new Converter(generator); + types.map(type => { + builtin[`$${type}`] = converter; + }); + + const func = new Func(generator); + builtin['$isNull'] = func; + builtin['$sleep'] = func; + builtin['$default'] = func; + builtin['$equal'] = func; + + builtin['$String'] = new String(generator); + builtin['$Array'] = new Array(generator); + builtin['$Date'] = new DaraDate(generator); + builtin['$Map'] = new Map(generator); + builtin['$Entry'] = new Entry(generator); + + return builtin; +}; \ No newline at end of file diff --git a/lib/generator.js b/lib/generator.js new file mode 100644 index 0000000..c823c11 --- /dev/null +++ b/lib/generator.js @@ -0,0 +1,2145 @@ +'use strict'; + +const assert = require('assert'); + +const path = require('path'); +const fs = require('fs'); + +const DSL = require('@darabonba/parser'); +const { + _name, _string, _subModelName, _vid, + _isBinaryOp, _modelName, _isBuiltinModel, + REQUEST, RESPONSE, CORE, _upperFirst, _avoidKeywords, + ERROR, MODEL, STREAM, UNRETRY_ERROR, RETRY_CONTEXT, SSE_EVENT, + RESP_ERROR +} = require('./helper'); +const getBuiltin = require('./builtin'); +const { Tag } = require('@darabonba/parser/lib/tag'); +const Annotation = require('@darabonba/annotation-parser'); + +class Visitor { + + static get supportGenerateTest() { + return true; + } + + constructor(option = {}) { + this.config = { + outputDir: '', + indent: ' ', + package: option.package, + clientName: option.clientName || 'Client', + ...option + }; + this.used = []; + this.output = ''; + this.outputDir = option.outputDir; + if(!this.outputDir) { + throw Error('`option.outputDir` should not empty'); + } + this.config.clientPath = path.join(this.outputDir, 'src', `${this.config.clientName}.php`); + this.typedef = this.config.typedef; + this.__module = {}; + this.innerModuleClassName = new Map(); + this.__externModule = new Map(); + this.classNamespace = new Map(); + this.usedClass = new Map(); + + if (!this.outputDir) { + throw new Error('`option.outputDir` should not empty'); + } + + if (!fs.existsSync(this.outputDir)) { + fs.mkdirSync(this.outputDir, { + recursive: true + }); + } + this.composer = {}; + const composerPath = path.join(this.outputDir, 'composer.json'); + if (fs.existsSync(composerPath)) { + try { + this.composer = JSON.parse(fs.readFileSync(composerPath)); + } catch (err) { + throw new Error('invalid composer.json'); + } + } + } + + saveProjectFiles() { + const composerPath = path.join(this.outputDir, 'composer.json'); + fs.writeFileSync(composerPath, JSON.stringify(this.composer, null, 2)); + const projectFiles = ['.gitignore', '.php_cs.dist', 'autoload.php', 'bootstrap.php']; + projectFiles.map(file => { + const source = path.join(__dirname, '..', 'templates', `${file}.tmpl`); + const target = path.join(this.outputDir, file); + + if(file === 'autoload.php') { + const content = fs.readFileSync(source, 'utf8'); + fs.writeFileSync(target, content.replace(/\${namespace}/g, this.namespace.replace(/\\/, '\\\\'))); + } else { + fs.copyFileSync(source, target); + } + + }); + } + + initComposer() { + this.composer.name = this.composer.packageName || (this.config.packageInfo && this.config.packageInfo.name); + this.composer.type = 'library'; + this.composer.description = this.composer.description || (this.config.packageInfo && this.config.packageInfo.desc); + this.composer.github = this.composer.github || (this.config.packageInfo && this.config.packageInfo.github); + this.composer.main = this.composer.main || 'src/Client.php'; + this.composer.authors = this.composer.authors || []; + if(this.config.maintainers) { + this.config.maintainers.forEach(maintainer => { + let name = maintainer.name ? maintainer.name : ''; + let email = maintainer.email ? maintainer.email : ''; + this.composer.authors.push({ name: name, email: email }); + }); + } + this.composer.license = this.composer.license || 'Apache-2.0'; + if (!this.composer.autoload) { + this.composer.autoload = { + 'psr-4': {} + }; + const namsespace = this.config.package.split('.').join('\\'); + this.composer.autoload['psr-4'][`${namsespace}\\`] = 'src'; + } + + if (!this.composer.scripts) { + this.composer.scripts = { + fixer: 'php-cs-fixer fix ./' + }; + } + + if (!this.composer.config) { + this.composer.config = { + 'sort-packages': true, + 'preferred-install': 'dist', + 'optimize-autoloader': true + }; + } + if (!this.composer.require) { + this.composer.require = { + 'php': '>5.5' + }; + } else { + Object.keys(this.requires).map(key => { + this.composer.require[key] = this.requires[key]; + }); + if(this.typedef) { + Object.keys(this.typedef).map(key => { + if(!this.typedef[key].package) { + return; + } + const [ name, version ] = this.typedef[key].package.split(':'); + this.composer.require[name] = version; + }); + } + } + + + + if (!this.composer['prefer-stable']) { + this.composer['prefer-stable'] = true; + } + + if (!this.composer.config) { + this.composer.config = { + 'sort-packages': true, + 'preferred-install': 'dist', + 'optimize-autoloader': true + }; + } + } + + getInnerClient(aliasId, phpPath) { + const moduleAst = this.ast.innerDep.get(aliasId); + const beginNotes = DSL.note.getNotes(moduleAst.notes, 0, moduleAst.moduleBody.nodes[0].tokenRange[0]); + const clientNote = beginNotes.find(note => note.note.lexeme === '@clientName'); + if(clientNote) { + return _string(clientNote.arg.value); + } + const fileInfo = path.parse(phpPath); + return `${_upperFirst(fileInfo.name.toLowerCase())}Client`; + } + + saveInnerModule(ast, targetPath) { + const keys = ast.innerModule.keys(); + let data = keys.next(); + while (!data.done) { + const aliasId = data.value; + const moduleAst = ast.innerDep.get(aliasId); + + const filepath = path.join(path.dirname(targetPath), `${ast.innerModule.get(aliasId)}.php`); + this.visitModule(moduleAst, filepath, false, 0); + data = keys.next(); + } + } + + save(filepath) { + let targetPath = filepath; + if(filepath.startsWith(this.outputDir)) { + const baseDir = path.join(this.outputDir, 'src', path.sep); + filepath = filepath.replace(baseDir, ''); + } + targetPath = path.join(this.outputDir, 'src', filepath); + const namespace = this.getClassNamespace(filepath); + const content = ` { + if (!namespace && i === fullModelNameArr.length - 1 && m.toLowerCase() === 'model') { + // If the model class name is 'model' + // add the '_' suffix. + return m + '_'; + } + return _avoidKeywords(m); + }).join('\\'); + } + + getRealClientName(aliasId) { + const moduleInfo = this.moduleClass.get(aliasId); + if(!moduleInfo) { + return; + } + if(moduleInfo.aliasName) { + this.used.push(`use ${moduleInfo.namespace}\\${moduleInfo.className} as ${moduleInfo.aliasName};`); + return moduleInfo.aliasName; + } + this.used.push(`use ${moduleInfo.namespace}\\${moduleInfo.className};`); + return moduleInfo.className; + } + + getRealModelName(fullModelName) { + if(fullModelName !== MODEL) { + const fullModelNameArr = fullModelName.split('\\'); + fullModelName = fullModelNameArr.map((m, i) => { + if (i === fullModelNameArr.length - 1 && m.toLowerCase() === 'model') { + // If the model class name is 'model' + // add the '_' suffix. + return m + '_'; + } + return _avoidKeywords(m); + }).join('\\'); + } + let [ modelName ] = fullModelName.split('\\').slice(-1); + const existName = this.usedClass.get(modelName); + if(existName && existName !== fullModelName) { + return `\\${fullModelName}`; + } + this.used.push(`use ${fullModelName};`); + + + this.usedClass.set(modelName, fullModelName); + return modelName; + } + + visitExceptions(ast, filepath, level) { + const exs = ast.moduleBody.nodes.filter((item) => { + return item.type === 'exception'; + }); + const exDir = path.join(path.dirname(filepath), 'Exceptions'); + for (let i = 0; i < exs.length; i++) { + const exceptionName = _modelName(exs[i].exceptionName.lexeme); + const modelFilepath = path.join(exDir, `${exceptionName}.php`); + const classNamespace = this.classNamespace.get(filepath); + this.modelSpace = exceptionName; + this.visitException(exs[i].exceptionBody, exceptionName, ast.extendOn, level); + this.save(modelFilepath); + if (this.predefined) { + Object.keys(this.predefined).filter((key) => { + return key.startsWith(exceptionName + '.'); + }).map((key) => { + const modelDir = path.join(path.dirname(filepath), 'Models'); + this.modelSpace = this.getfullModelName(key, true); + const realFullModelName = this.getfullModelName(key); + const [ modelName ] = realFullModelName.split('\\').slice(-1); + + const realFullClassName = `${classNamespace}\\Models\\${realFullModelName}`; + this.usedClass.set(modelName, realFullClassName); + const subModelFilepath = path.join(modelDir, `${realFullModelName.split('\\').join(path.sep)}.php`); + this.visitModel(this.predefined[key].modelBody, modelName, this.predefined[key].extendOn, level); + this.save(subModelFilepath); + }); + } + } + } + + visitModels(ast, filepath, level) { + const models = ast.moduleBody.nodes.filter((item) => { + return item.type === 'model'; + }); + const modelDir = path.join(path.dirname(filepath), 'Models'); + for (let i = 0; i < models.length; i++) { + const modelName = _modelName(models[i].modelName.lexeme); + const modelFilepath = path.join(modelDir, `${modelName}.php`); + const classNamespace = this.classNamespace.get(filepath); + this.modelSpace = modelName; + this.visitAnnotation(models[i].annotation, level); + let comments = DSL.comment.getFrontComments(this.comments, models[i].tokenRange[0]); + this.visitComments(comments, level); + this.visitModel(models[i].modelBody, modelName, models[i].extendOn, level); + this.save(modelFilepath); + if (this.predefined) { + Object.keys(this.predefined).filter((key) => { + return key.startsWith(modelName + '.'); + }).map((key) => { + this.modelSpace = this.getfullModelName(key, true); + const realFullModelName = this.getfullModelName(key); + const [ modelName ] = realFullModelName.split('\\').slice(-1); + + const realFullClassName = `${classNamespace}\\Models\\${realFullModelName}`; + this.usedClass.set(modelName, realFullClassName); + const subModelFilepath = path.join(modelDir, `${realFullModelName.split('\\').join(path.sep)}.php`); + this.visitModel(this.predefined[key].modelBody, modelName, this.predefined[key].extendOn, level); + this.save(subModelFilepath); + }); + } + } + } + + visitModule(ast, filepath, main, level) { + assert.equal(ast.type, 'module'); + this.ast = ast; + this.predefined = ast.models; + this.parentModule = ast.extends; + this.comments = ast.comments; + this.notes = ast.notes; + this.requires = {}; + this.moduleTypedef = {}; + ast.innerModule = new Map(); + this.moduleClass = new Map(); + this.clientName = new Map(); + if(main) { + this.clientName.set(this.config.clientName, true); + } + this.builtin = getBuiltin(this); + + + + this.eachImport(ast.imports, ast.usedExternModel, filepath, ast.innerModule, level); + this.namespace = this.config.package.split('.').join('\\'); + this.visitModels(ast, filepath, level); + + this.visitExceptions(ast, filepath, level); + + const apis = ast.moduleBody.nodes.filter((item) => { + return item.type === 'api'; + }); + + if(apis.length > 0) { + this.used.push(`use ${CORE};`); + this.clientName.set('Dara', true); + } + this.visitAnnotation(ast.annotation, level); + // // models definition + this.apiBefore(main, filepath, level); + const types = ast.moduleBody.nodes.filter((item) => { + return item.type === 'type'; + }); + + const inits = ast.moduleBody.nodes.filter((item) => { + return item.type === 'init'; + }); + + const [init] = inits; + if (init) { + this.visitInit(init, types, level); + } + + + + for (let i = 0; i < apis.length; i++) { + if (i !== 0) { + this.emit('\n'); + } + + this.eachAPI(apis[i], level + 1); + } + + this.functionBefore(); + const functions = ast.moduleBody.nodes.filter((item) => { + return item.type === 'function'; + }); + + for (let i = 0; i < functions.length; i++) { + if (i !== 0) { + this.emit('\n'); + } + + this.eachFunction(functions[i], level + 1); + } + + this.moduleAfter(); + if (this.config.exec) { + this.emitExec(); + } + this.save(filepath); + this.saveInnerModule(ast, filepath); + } + + emitExec() { + this.emit(`$path = __DIR__ . \\DIRECTORY_SEPARATOR . '..' . \\DIRECTORY_SEPARATOR . 'vendor' . \\DIRECTORY_SEPARATOR . 'autoload.php'; +if (file_exists($path)) { + require_once $path; +} +${this.config.clientName}::main(array_slice($argv, 1));`); + } + + visitComments(comments, level) { + comments.forEach(comment => { + this.emit(`${comment.value}`, level); + this.emit('\n'); + }); + } + + visitAnnotation(annotation, level, bottom = true) { + if (!annotation || !annotation.value) { + return; + } + let comments = DSL.comment.getFrontComments(this.comments, annotation.index); + this.visitComments(comments, level); + var ast = Annotation.parse(annotation.value); + var description = ast.items.find((item) => { + return item.type === 'description'; + }); + var summary = ast.items.find((item) => { + return item.type === 'summary'; + }); + var _return = ast.items.find((item) => { + return item.type === 'return'; + }); + var deprecated = ast.items.find((item) => { + return item.type === 'deprecated'; + }); + var params = ast.items.filter((item) => { + return item.type === 'param'; + }).map((item) => { + return { + name: item.name.id, + text: item.text.text.trimEnd() + }; + }); + var throws = ast.items.filter((item) => { + return item.type === 'throws'; + }).map((item) => { + return item.text.text.trimEnd(); + }); + + var descriptionText = description ? description.text.text.trimEnd() : ''; + var summaryText = summary ? summary.text.text.trimEnd() : ''; + var returnText = _return ? _return.text.text.trimEnd() : ''; + let hasNextSection = false; + + this.emit('/**\n', level); + if (summaryText !== '') { + summaryText.split('\n').forEach((line) => { + this.emit(` * ${line}\n`, level); + }); + hasNextSection = true; + } + if (descriptionText !== '') { + if (hasNextSection) { + this.emit(' * \n', level); + } + this.emit(' * @remarks\n', level); + descriptionText.split('\n').forEach((line) => { + this.emit(` * ${line}\n`, level); + }); + hasNextSection = true; + } + if (deprecated) { + if (hasNextSection) { + this.emit(' * \n', level); + } + if (deprecated.text.text.trimEnd() === '') { + this.emit(' * @deprecated\n', level); + } else { + this.emit(` * @deprecated ${deprecated.text.text.trimEnd()}\n`, level); + } + hasNextSection = true; + } + if (params.length > 0) { + if (hasNextSection) { + this.emit(' * \n', level); + } + params.forEach((item) => { + this.emit(` * @param ${item.name} - ${item.text}\n`, level); + }); + } + if (returnText !== '') { + this.emit(` * @returns ${returnText}\n`, level); + } + if (throws.length > 0) { + this.emit(' * \n', level); + throws.forEach((item) => { + this.emit(` * @throws ${item}\n`, level); + }); + } + if(bottom) { + this.emit(' */', level); + this.emit('\n'); + } + } + + visitInit(ast, types, level) { + assert.equal(ast.type, 'init'); + types.forEach((item) => { + let comments = DSL.comment.getFrontComments(this.comments, item.tokenRange[0]); + this.visitComments(comments, level + 1); + this.emit('/**\n', level + 1); + this.emit(' * @var ', level+ 1); + this.visitType(item.value); + this.emit('\n'); + this.emit(' */\n', level + 1); + this.emit(`protected $${_vid(item.vid)};\n`, level + 1); + this.emit('\n'); + }); + this.emit('\n'); + this.visitAnnotation(ast.annotation, level + 1); + let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]); + this.visitComments(comments, level + 1); + + if (ast.initBody) { + this.emit('public function __construct', level + 1); + this.visitParams(ast.params, level); + this.emit('\n'); + this.emit('{\n', level + 1); + this.visitStmts(ast.initBody, level + 2); + + this.emit('}\n', level + 1); + this.emit('\n'); + } + } + + getClassNamespace(phpPath) { + if(phpPath.startsWith(this.outputDir)) { + const baseDir = path.join(this.outputDir, 'src', path.sep); + phpPath = phpPath.replace(baseDir, ''); + } + + const arr = phpPath.split(path.sep).slice(0, -1); + + const namsespace = this.config.package.split('.').join('\\'); + let className = namsespace; + arr.map(key => { + className += '\\' + key; + }); + return className; + } + + getAliasName(classNamespace, name, aliasId) { + let aliasName = ''; + if(!this.clientName.has(name)) { + this.clientName.set(name, true); + return aliasName; + } + if(aliasId) { + aliasName = aliasId + name; + } + if(aliasName && !this.clientName.has(aliasName)) { + this.clientName.set(aliasName, true); + return aliasName; + } + const arr = classNamespace.split('\\'); + for(let i = arr.length - 1; i >= 0; i--) { + aliasName = arr[i] + name; + if(!this.clientName.has(aliasName)) { + this.clientName.set(aliasName, true); + return aliasName; + } + } + } + + eachImport(imports, usedModels, filepath, innerModule, level) { + this.imports = new Map(); + if (imports.length > 0) { + const lockPath = path.join(this.config.pkgDir, '.libraries.json'); + const lock = JSON.parse(fs.readFileSync(lockPath, 'utf8')); + for (let i = 0; i < imports.length; i++) { + const item = imports[i]; + let comments = DSL.comment.getFrontComments(this.comments, item.tokenRange[0]); + this.visitComments(comments, level); + const aliasId = item.lexeme; + const moduleDir = this.config.libraries[aliasId]; + const innerPath = item.innerPath; + if (!moduleDir && innerPath) { + let phpPath = innerPath.replace(/(\.tea)$|(\.spec)$|(\.dara)$/gi, ''); + if (phpPath.startsWith('./') || phpPath.startsWith('../')) { + phpPath = path.join(path.dirname(filepath), `${phpPath}.php`); + } else if (phpPath.startsWith('/')) { + phpPath = `${phpPath}.php`; + } + + const classNamespace = this.getClassNamespace(phpPath); + const className = this.getInnerClient(aliasId, phpPath); + innerModule.set(aliasId, innerPath); + this.moduleClass.set(aliasId, { + namespace: classNamespace, + className: className, + aliasName: this.getAliasName(classNamespace, className, aliasId) + }); + continue; + } + let targetPath = ''; + if (moduleDir.startsWith('./') || moduleDir.startsWith('../')) { + targetPath = path.join(this.config.pkgDir, moduleDir); + } else if (moduleDir.startsWith('/')) { + targetPath = moduleDir; + } else { + targetPath = path.join(this.config.pkgDir, lock[moduleDir]); + } + const pkgPath = fs.existsSync(path.join(targetPath, 'Teafile')) ? path.join(targetPath, 'Teafile') : path.join(targetPath, 'Darafile'); + const pkg = JSON.parse(fs.readFileSync(pkgPath)); + const phpRelease = pkg.releases && pkg.releases.php; + const phpPkg = pkg.php; + if (!phpRelease || !phpPkg || !phpPkg.package) { + throw new Error(`The '${aliasId}' has no PHP supported.`); + } + const classNamespace = phpPkg.package.split('.').join('\\'); + const className = phpPkg.clientName || 'Client'; + const [ key ,value ] = phpRelease.split(':'); + this.requires[key] = value; + this.moduleClass.set(aliasId, { + namespace: classNamespace, + className: className, + aliasName: this.getAliasName(classNamespace, className, aliasId) + }); + this.moduleTypedef[aliasId] = phpPkg.typedef; + } + this.__externModule = usedModels; + } + } + + visitParams(ast, level) { + assert.equal(ast.type, 'params'); + this.emit('('); + for (var i = 0; i < ast.params.length; i++) { + if (i !== 0) { + this.emit(', '); + } + const node = ast.params[i]; + assert.equal(node.type, 'param'); + const name = _name(node.paramName); + this.emit(`$${_avoidKeywords(name)}`); + } + this.emit(')'); + } + + visitType(ast, level) { + if (ast.type === 'array') { + this.visitType(ast.subType, level); + this.emit('[]'); + } else if (ast.type === 'moduleModel') { + const [moduleId, ...rest] = ast.path; + const { namespace } = this.moduleClass.get(moduleId.lexeme); + const moduleModelName = rest.map((item) => { + return item.lexeme; + }).join('\\'); + const subModelName = this.getRealModelName(`${namespace}\\Models\\${moduleModelName}`); + this.emit(subModelName); + } else if (ast.type === 'subModel') { + const [moduleId, ...rest] = ast.path; + const subModelName = _subModelName([moduleId.lexeme, ...rest.map((item) => { + return item.lexeme; + })].join('\\')); + const realModelName = this.getRealModelName(`${this.namespace}\\Models\\${subModelName}`); + this.emit(realModelName); + } else if (ast.type === 'map') { + this.visitType(ast.valueType, level); + this.emit('[]'); + } else if (ast.type === 'model') { + let namespace = this.namespace; + if (ast.moduleName) { + namespace = this.moduleClass.get(ast.moduleName).namespace; + } + const realModelName = this.getRealModelName(`${namespace}\\Models\\${ast.name}`); + this.emit(realModelName); + } else if (this.isIterator(ast)) { + this.visitType(ast.valueType); + } else if (ast.type === 'entry') { + this.emit('[string, '); + this.visitType(ast.valueType); + this.emit(']'); + } else if (ast.idType === 'model') { + const realModelName = this.getRealModelName(`${this.namespace}\\Models\\${ast.lexeme}`); + this.emit(realModelName); + } else if (ast.idType === 'module') { + let moduleName = _name(ast); + if(this.builtin[moduleName]) { + moduleName = this.getType(moduleName); + } else { + moduleName = this.getRealClientName(moduleName); + } + this.emit(moduleName); + } else if (ast.idType === 'builtin_model') { + const realModelName = this.getRealModelName(this.getType(ast.lexeme)); + this.emit(realModelName); + } else if (ast.type === 'moduleTypedef') { + const [moduleId, modelName] = ast.path; + const moduleTypedef = this.moduleTypedef[moduleId.lexeme]; + const typedef = moduleTypedef[modelName.lexeme]; + if(!typedef.import) { + this.emit(typedef.type); + } else { + const typedefName = this.getRealModelName(`${typedef.import}\\${typedef.type}`); + this.emit(typedefName); + } + } else if (ast.type === 'typedef' || ast.idType === 'typedef') { + const typedef = this.typedef[ast.lexeme]; + if(!typedef.import) { + this.emit(typedef.type); + } else { + const typedefName = this.getRealModelName(`${typedef.import}\\${typedef.type}`); + this.emit(typedefName); + } + } else { + this.emit(this.getType(_name(ast))); + } + } + + visitAPIBody(ast, level) { + assert.equal(ast.type, 'apiBody'); + const requestName = this.getRealModelName(REQUEST); + this.emit(`$_request = new ${requestName}();\n`, level); + this.visitStmts(ast.stmts, level); + } + + visitRuntimeBefore(ast, level) { + assert.equal(ast.type, 'object'); + this.emit('$_runtime = ', level); + this.visitObject(ast, level); + this.emit(';\n'); + this.emit('\n'); + this.emit('$_retriesAttempted = 0;\n', level); + this.emit('$_lastRequest = null;\n', level); + this.emit('$_lastResponse = null;\n', level); + const retryContextName = this.getRealModelName(RETRY_CONTEXT); + this.emit(`$_context = new ${retryContextName}([\n`, level); + this.emit('\'retriesAttempted\' => $_retriesAttempted,\n', level + 1); + this.emit(']);\n', level); + this.emit('while (Dara::shouldRetry($_runtime[\'retryOptions\'], $_context)) {\n', level); + this.emit('if ($_retriesAttempted > 0) {\n', level + 1); + this.emit('$_backoffTime = Dara::getBackoffDelay($_runtime[\'retryOptions\'], $_context);\n', level + 2); + this.emit('if ($_backoffTime > 0) {\n', level + 2); + this.emit('Dara::sleep($_backoffTime);\n', level + 3); + this.emit('}\n', level + 2); + this.emit('}\n', level + 1); + this.emit('\n'); + this.emit('$_retriesAttempted++;\n', level + 1); + this.emit('try {\n', level + 1); + } + + visitStmt(ast, level) { + let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]); + this.visitComments(comments, level); + if (ast.type === 'return') { + this.visitReturn(ast, level); + } else if (ast.type === 'yield') { + this.visitYield(ast, level); + } else if (ast.type === 'if') { + this.visitIf(ast, level); + } else if (ast.type === 'throw') { + this.visitThrow(ast, level); + } else if (ast.type === 'assign') { + this.visitAssign(ast, level); + } else if (ast.type === 'retry') { + this.visitRetry(ast, level); + } else if (ast.type === 'break') { + this.emit('break;\n', level); + } else if (ast.type === 'declare') { + this.visitDeclare(ast, level); + } else if (ast.type === 'while') { + this.visitWhile(ast, level); + } else if (ast.type === 'for') { + this.visitFor(ast, level); + } else if (ast.type === 'try') { + this.visitTry(ast, level); + } else { + this.emit('', level); + this.visitExpr(ast, level); + this.emit(';\n'); + } + } + + getType(name) { + if (name === 'integer' || name === 'number' || + name === 'int8' || name === 'uint8' || + name === 'int16' || name === 'uint16' || + name === 'int32' || name === 'uint32' || + name === 'int64' || name === 'uint64' || + name === 'long' || name === 'ulong') { + return 'int'; + } + + if (name === 'float' || name === 'double') { + return 'float'; + } + + if (name === 'readable') { + return STREAM; + } + + if (name === 'writable') { + return STREAM; + } + + if (name === '$Request') { + return REQUEST; + } + + if (name === '$Response') { + return RESPONSE; + } + + if (name === '$Model') { + return MODEL; + } + + if (name === '$Error') { + return ERROR; + } + + if (name === '$ResponseError') { + return RESP_ERROR; + } + + if (name === '$SSEEvent') { + return SSE_EVENT; + } + + if (name === '$Date' || name === '$File' || + name === '$URL' || name === '$Stream') { + return this.builtin[name].getClientName(); + } + + if (name === 'object') { + return 'mixed[]'; + } + + if (name === 'bytes') { + return 'int[]'; + } + + if (name === 'any') { + return 'mixed'; + } + + return name; + } + + visitFieldType(value, level, fieldName) { + if (value.type === 'modelBody') { + const subModelName = this.getRealModelName(`${this.namespace}\\Models\\${this.modelSpace}\\${fieldName}`); + this.emit(subModelName); + } else if (value.type === 'array') { + this.visitType(value); + } else if (value.fieldType === 'array') { + this.visitFieldType(value.fieldItemType, level, fieldName); + this.emit('[]'); + } else if (value.fieldType === 'map') { + this.visitFieldType(value.valueType); + this.emit('[]'); + } else if (value.type === 'map') { + this.visitFieldType(value.valueType); + this.emit('[]'); + } else if (value.tag === Tag.TYPE) { + this.emit(`${this.getType(value.lexeme)}`); + } else if (value.tag === Tag.ID && value.idType === 'model') { + const modelName = _name(value); + const realModelName = this.getRealModelName(`${this.namespace}\\Models\\${modelName}`); + this.emit(realModelName); + } else if (value.tag === Tag.ID && value.idType === 'module') { + let moduleName = _name(value); + if(this.builtin[moduleName]) { + moduleName = this.getType(moduleName); + } else { + moduleName = this.getRealClientName(moduleName); + } + this.emit(moduleName); + } else if (value.tag === Tag.ID && value.idType === 'builtin_model') { + const realModelName = this.getRealModelName(this.getType(value.lexeme)); + this.emit(realModelName); + } else if (value.tag === Tag.ID) { + this.emit(`${value.lexeme}`); + } else if (value.type === 'moduleModel') { + const [moduleId, ...models] = value.path; + const { namespace } = this.moduleClass.get(moduleId.lexeme); + const moduleModelName = models.map((item) => { + return item.lexeme; + }).join('\\'); + const subModelName = this.getRealModelName(`${namespace}\\Models\\${moduleModelName}`); + this.emit(subModelName); + } else if (value.type === 'subModel') { + const [moduleId, ...rest] = value.path; + const subModelName = [moduleId.lexeme, ...rest.map((item) => { + return item.lexeme; + })].join('\\'); + const realModelName = this.getRealModelName(`${this.namespace}\\Models\\${subModelName}`); + this.emit(realModelName); + } else if (value.fieldType === 'readable' || value.fieldType === 'writable') { + const realModelName = this.getRealModelName(this.getType(value.fieldType)); + this.emit(realModelName); + } else if (typeof value.fieldType === 'string') { + this.emit(`${this.getType(value.fieldType)}`); + } else if (value.fieldType.type === 'moduleModel') { + const [moduleId, ...models] = value.fieldType.path; + const { namespace } = this.moduleClass.get(moduleId.lexeme); + const subModelName = models.map((item) => { + return item.lexeme; + }).join('\\'); + const realModelName = this.getRealModelName(`${namespace}\\Models\\${subModelName}`); + this.emit(realModelName); + } else if (value.fieldType.type === 'moduleTypedef') { + const [moduleId, modelName] = value.fieldType.path; + const moduleTypedef = this.moduleTypedef[moduleId.lexeme]; + const typedef = moduleTypedef[modelName.lexeme]; + if(!typedef.import) { + this.emit(typedef.type); + } else { + const typedefName = this.getRealModelName(`${typedef.import}\\${typedef.type}`); + this.emit(typedefName); + } + } else if (value.fieldType.type === 'typedef' || value.fieldType.idType === 'typedef') { + const typedef = this.typedef[value.fieldType.lexeme]; + if(!typedef.import) { + this.emit(typedef.type); + } else { + const typedefName = this.getRealModelName(`${typedef.import}\\${typedef.type}`); + this.emit(typedefName); + } + } else if (value.fieldType.type) { + this.emit(`${this.getType(value.fieldType.lexeme)}`); + } else if (value.fieldType.idType === 'model') { + const realModelName = this.getRealModelName(`${this.namespace}\\Models\\${value.fieldType.lexeme}`); + this.emit(realModelName); + } else if (value.fieldType.idType === 'module') { + let moduleName = _name(value.fieldType); + if(this.builtin[moduleName]) { + moduleName = this.getType(moduleName); + } else { + moduleName = this.getRealClientName(moduleName); + } + this.emit(moduleName); + } else if (value.fieldType.idType === 'builtin_model') { + const realModelName = this.getRealModelName(this.getType(value.fieldType.lexeme)); + this.emit(realModelName); + } + } + + + visitFromField(fieldValue, fieldName, key, value, level) { + const deep = Math.floor(level / 2); + if (fieldValue.type === 'modelBody') { + const subModelName = this.getRealModelName(`${this.namespace}\\Models\\${this.modelSpace}\\${fieldName}`); + this.emit(`${key} = ${subModelName}::fromMap(${value});\n`, level + 1); + } else if (fieldValue.type === 'array' || fieldValue.fieldType === 'array') { + this.emit(`if(!empty(${value})) {\n`, level + 1); + this.emit(`${key} = [];\n`, level + 2); + this.emit(`$n${deep} = 0;\n`, level + 2); + this.emit(`foreach(${value} as $item${deep}) {\n`, level + 2); + this.visitFromField(fieldValue.fieldItemType, fieldName, `${key}[$n${deep}++]`, `$item${deep}`, level + 2); + this.emit('}\n', level + 2); + this.emit('}\n', level + 1); + } else if (fieldValue.fieldType === 'map' || fieldValue.type === 'map') { + this.emit(`if(!empty(${value})) {\n`, level + 1); + this.emit(`${key} = [];\n`, level + 2); + this.emit(`foreach(${value} as $key${deep} => $value${deep}) {\n`, level + 2); + this.visitFromField(fieldValue.valueType, fieldName, `${key}[$key${deep}]`, `$value${deep}`, level + 2); + this.emit('}\n', level + 2); + this.emit('}\n', level + 1); + } else if (fieldValue.type === 'moduleModel' || + (fieldValue.fieldType && fieldValue.fieldType.type === 'moduleModel')) { + const [moduleId, ...models] = fieldValue.path || fieldValue.fieldType.path; + const { namespace } = this.moduleClass.get(moduleId.lexeme); + const moduleModelName = models.map((item) => { + return item.lexeme; + }).join('\\'); + const subModelName = this.getRealModelName(`${namespace}\\Models\\${moduleModelName}`); + this.emit(`${key} = ${subModelName}::fromMap(${value});\n`, level + 1); + } else if (fieldValue.type === 'subModel') { + const [moduleId, ...rest] = fieldValue.path; + const subModelName = _subModelName([moduleId.lexeme, ...rest.map((item) => { + return item.lexeme; + })].join('\\')); + const realModelName = this.getRealModelName(`${this.namespace}\\Models\\${subModelName}`); + this.emit(`${key} = ${realModelName}::fromMap(${value});\n`, level + 1); + } else if (fieldValue.fieldType && fieldValue.fieldType.idType === 'model') { + const realModelName = this.getRealModelName(`${this.namespace}\\Models\\${fieldValue.fieldType.lexeme}`); + this.emit(`${key} = ${realModelName}::fromMap(${value});\n`, level + 1); + } else if (fieldValue.fieldType && fieldValue.fieldType.idType === 'builtin_model') { + const realModelName = this.getRealModelName(this.getType(fieldValue.fieldType.lexeme)); + this.emit(`${key} = ${realModelName}::fromMap(${value});\n`, level + 1); + } else { + this.emit(`${key} = ${value};\n`, level + 1); + } + + } + + visitToArrayField(fieldValue, key, value, level) { + const deep = Math.floor(level / 2); + if (fieldValue.type === 'modelBody' || fieldValue.type === 'moduleModel' || + fieldValue.type === 'subModel') { + this.emit(`${key} = null !== ${value} ? ${value}->toArray($noStream) : ${value};\n`, level + 1); + } else if(fieldValue.idType === 'model') { + this.emit(`${key} = null !== ${value} ? ${value}->toArray($noStream) : ${value};\n`, level + 1); + } else if(fieldValue.fieldType && (fieldValue.fieldType.type === 'moduleModel' || + fieldValue.fieldType.idType === 'model' || fieldValue.fieldType.idType === 'builtin_model')) { + this.emit(`${key} = null !== ${value} ? ${value}->toArray($noStream) : ${value};\n`, level + 1); + } else if (fieldValue.type === 'array' || fieldValue.fieldType === 'array') { + this.emit(`if(is_array(${value})) {\n`, level + 1); + this.emit(`${key} = [];\n`, level + 2); + this.emit(`$n${deep} = 0;\n`, level + 2); + this.emit(`foreach(${value} as $item${deep}) {\n`, level + 2); + this.visitToArrayField(fieldValue.fieldItemType, `${key}[$n${deep}++]`, `$item${deep}`, level + 2); + this.emit('}\n', level + 2); + this.emit('}\n', level + 1); + } else if (fieldValue.fieldType === 'map' || fieldValue.type === 'map') { + this.emit(`if(is_array(${value})) {\n`, level + 1); + this.emit(`${key} = [];\n`, level + 2); + this.emit(`foreach(${value} as $key${deep} => $value${deep}) {\n`, level + 2); + this.visitToArrayField(fieldValue.valueType, `${key}[$key${deep}]`, `$value${deep}`, level + 2); + this.emit('}\n', level + 2); + this.emit('}\n', level + 1); + } else { + this.emit(`${key} = ${value};\n`, level + 1); + } + + } + + visitModelBody(ast, level, modelName) { + assert.equal(ast.type, 'modelBody'); + let node; + for (let i = 0; i < ast.nodes.length; i++) { + node = ast.nodes[i]; + // TODO document gen + node = ast.nodes[i]; + let comments = DSL.comment.getFrontComments(this.comments, node.tokenRange[0]); + this.visitComments(comments, level); + this.emit('/**\n', level); + this.emit(' * @var ', level); + this.visitFieldType(node.fieldValue, level, _name(node.fieldName)); + this.emit('\n'); + this.emit(' */\n', level); + this.emit(`public $${_name(node.fieldName)};\n`, level); + } + if (node) { + //find the last node's back comment + let comments = DSL.comment.getBetweenComments(this.comments, node.tokenRange[0], ast.tokenRange[1]); + this.visitComments(comments, level); + } + + if (ast.nodes.length === 0) { + //empty block's comment + let comments = DSL.comment.getBetweenComments(this.comments, ast.tokenRange[0], ast.tokenRange[1]); + this.visitComments(comments, level); + } + + this.emit('protected $_name = [\n', level); + for (let i = 0; i < ast.nodes.length; i++) { + const node = ast.nodes[i]; + const nameAttr = node.attrs.find((item) => { + return item.attrName.lexeme === 'name'; + }); + if (nameAttr) { + this.emit(`'${_name(node.fieldName)}' => '${_string(nameAttr.attrValue)}',\n`, level + 2); + } else { + this.emit(`'${_name(node.fieldName)}' => '${_name(node.fieldName)}',\n`, level + 2); + } + } + this.emit('];\n', level); + this.emit('\n'); + + this.emit('public function validate()\n', level); + this.emit('{\n', level); + this.visitModelValidate(ast, level + 1); + this.emit('}\n', level); + this.emit('\n'); + this.emit('public function toArray($noStream = false)\n', level); + this.emit('{\n', level); + this.emit('$res = [];\n', level + 1); + for (let i = 0; i < ast.nodes.length; i++) { + const node = ast.nodes[i]; + const nameAttr = node.attrs.find((item) => { + return item.attrName.lexeme === 'name'; + }); + const realName = nameAttr ?_string(nameAttr.attrValue) : _name(node.fieldName); + + this.emit(`if (null !== $this->${_name(node.fieldName)}) {\n`, level + 1); + this.visitToArrayField(node.fieldValue, `$res['${realName}']`, `$this->${_name(node.fieldName)}`, level + 1); + this.emit('}\n', level + 1); + this.emit('\n'); + } + this.emit('return $res;\n', level + 1); + this.emit('}\n', level); + this.emit('\n'); + + this.emit('public function toMap($noStream = false)\n', level); + this.emit('{\n', level); + this.emit('return $this->toArray($noStream);\n', level + 1); + this.emit('}\n', level); + this.emit('\n'); + + this.emit('public static function fromMap($map = [])\n', level); + this.emit('{\n', level); + this.emit('$model = new self();\n', level + 1); + for (let i = 0; i < ast.nodes.length; i++) { + const node = ast.nodes[i]; + const nameAttr = node.attrs.find((item) => { + return item.attrName.lexeme === 'name'; + }); + const realName = nameAttr ?_string(nameAttr.attrValue) : _name(node.fieldName); + const fieldName = _name(node.fieldName); + this.emit(`if (isset($map['${realName}'])) {\n`, level + 1); + this.visitFromField(node.fieldValue, fieldName, `$model->${fieldName}`, `$map['${realName}']`, level + 1); + this.emit('}\n', level + 1); + this.emit('\n'); + } + this.emit('return $model;\n', level + 1); + this.emit('}\n', level); + this.emit('\n'); + + + } + + + getAttributes(ast, name) { + const attr = ast.attrs.find((item) => { + return item.attrName.lexeme === name; + }); + if(!attr) { + return; + } + return attr.attrValue.string || attr.attrValue.lexeme || attr.attrValue.value; + } + + visitFieldValidate(modelName, value, level, name) { + if (value.type === 'array' || value.fieldType === 'array') { + this.emit(`if(is_array(${name})) {\n`, level); + this.emit(`${modelName}::validateArray(${name});\n`, level + 1); + this.emit('}\n', level); + } else if (value.fieldType === 'map' || value.type === 'map') { + this.emit(`if(is_array(${name})) {\n`, level); + this.emit(`${modelName}::validateArray(${name});\n`, level + 1); + this.emit('}\n', level); + } else if (value.type === 'moduleModel' || value.type === 'modelBody' + || value.type === 'subModel' || value.fieldType.type === 'moduleModel' + || value.fieldType.idType === 'model' || value.fieldType.idType === 'module') { + this.emit(`if(null !== ${name}) {\n`, level); + this.emit(`${name}->validate();\n`, level + 1); + this.emit('}\n', level); + } + } + + visitModelValidate(ast, level) { + const modelName = this.getRealModelName(MODEL); + for (let i = 0; i < ast.nodes.length; i++) { + const node = ast.nodes[i]; + this.visitFieldValidate(modelName, node.fieldValue, level, `$this->${_name(node.fieldName)}`); + const attrName = _name(node.fieldName); + const pattern = this.getAttributes(node, 'pattern') || ''; + const maxLength = this.getAttributes(node, 'maxLength') || 0; + const minLength = this.getAttributes(node, 'minLength') || 0; + const maximum = this.getAttributes(node, 'maximum') || 0; + const minimum = this.getAttributes(node, 'minimum') || 0; + const required = node.required || false; + if (required || maxLength > 0 || minLength > 0 || maximum > 0 || pattern !== '') { + if (required) { + this.emit(`${modelName}::validateRequired('${attrName}', $this->${attrName}, true);\n`, level); + } + if (pattern !== '') { + this.emit(`${modelName}::validatePattern('${attrName}', $this->${attrName}, '${pattern}');\n`, level); + } + if (maxLength > 0 && maxLength <= 2147483647) { + this.emit(`${modelName}::validateMaxLength('${attrName}', $this->${attrName}, ${maxLength});\n`, level); + } + if (minLength > 0 && minLength <= 2147483647) { + this.emit(`${modelName}::validateMinLength('${attrName}', $this->${attrName}, ${minLength});\n`, level); + } + // 不能超过JS中最大安全整数 + if (maximum > 0 && maximum <= Number.MAX_SAFE_INTEGER) { + this.emit(`${modelName}::validateMaximum('${attrName}', $this->${attrName}, ${maximum});\n`, level); + } + // 不能超过JS中最大安全整数 + if (minimum > 0 && minimum <= Number.MAX_SAFE_INTEGER) { + this.emit(`${modelName}::validateMinimum('${attrName}', $this->${attrName}, ${minimum});\n`, level); + } + } + } + this.emit('parent::validate();\n', level); + } + + visitExtendOn(extendOn, type = 'model') { + if (!extendOn) { + const modelName = type === 'model' ? this.getRealModelName(MODEL) : this.getRealModelName(ERROR); + return this.emit(modelName); + } + let namespace = this.namespace; + let modelName = _name(extendOn); + if (extendOn.type === 'moduleModel') { + const [moduleId, ...rest] = extendOn.path; + namespace = this.moduleClass.get(moduleId.lexeme).namespace; + modelName = rest.map((item) => { + return item.lexeme; + }).join('\\'); + } else if (extendOn.type === 'subModel') { + const [moduleId, ...rest] = extendOn.path; + modelName = [moduleId.lexeme, ...rest.map((item) => { + return item.lexeme; + })].join('\\'); + } + this.emit(this.getRealModelName(`${namespace}\\Models\\${modelName}`)); + } + + visitModel(modelBody, modelName, extendOn, level) { + this.emit(`class ${modelName} extends `, level); + this.visitExtendOn(extendOn); + this.emit(' {\n'); + this.visitModelBody(modelBody, level + 1, modelName); + this.emit('\n'); + this.emit('}\n\n', level); + } + + visitEcxceptionBody(ast, level) { + assert.equal(ast.type, 'exceptionBody'); + let node; + for (let i = 0; i < ast.nodes.length; i++) { + node = ast.nodes[i]; + // TODO document gen + this.emit('/**\n', level); + this.emit('* @var ', level); + this.visitFieldType(node.fieldValue, level, _name(node.fieldName)); + this.emit('\n'); + this.emit('*/\n', level); + this.emit(`protected $${_name(node.fieldName)};\n`, level); + } + + this.emit('\n'); + this.emit('public function __construct($map)\n', level); + this.emit('{\n', level); + this.emit('parent::__construct($map);\n', level + 1); + for (let i = 0; i < ast.nodes.length; i++) { + node = ast.nodes[i]; + this.emit(`$this->${_name(node.fieldName)} = $map['${_name(node.fieldName)}'];\n`, level + 1); + } + this.emit('}\n\n', level); + for (let i = 0; i < ast.nodes.length; i++) { + node = ast.nodes[i]; + // TODO document gen + this.emit('/**\n', level); + this.emit('* @return ', level); + this.visitFieldType(node.fieldValue, level, _name(node.fieldName)); + this.emit('\n'); + this.emit('*/\n', level); + this.emit(`public function get${_upperFirst(_name(node.fieldName))}()\n`, level); + this.emit('{\n', level); + this.emit(`return $this->${_name(node.fieldName)};\n`, level + 1); + this.emit('}\n', level); + } + if (node) { + //find the last node's back comment + let comments = DSL.comment.getBetweenComments(this.comments, node.tokenRange[0], ast.tokenRange[1]); + this.visitComments(comments, level); + } + + if (ast.nodes.length === 0) { + //empty block's comment + let comments = DSL.comment.getBetweenComments(this.comments, ast.tokenRange[0], ast.tokenRange[1]); + this.visitComments(comments, level); + } + } + + visitException(exceptionBody, exceptionName, extendOn, level) { + this.emit(`class ${exceptionName} extends `, level); + this.visitExtendOn(extendOn, 'exception'); + this.emit(' {\n'); + this.visitEcxceptionBody(exceptionBody, level + 1, exceptionName); + this.emit('}\n\n', level); + } + + eachSubModel(ast, level) { + assert.equal(ast.type, 'model'); + const modelName = _subModelName(_name(ast.modelName)); + this.visitModel(ast.modelBody, modelName, ast.extendOn, level); + } + + visitObjectFieldValue(ast, level) { + this.visitExpr(ast, level); + } + + visitObjectField(ast, level) { + let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]); + this.visitComments(comments, level); + var key = _name(ast.fieldName) || _string(ast.fieldName); + this.emit(`'${key}' => `, level); + this.visitObjectFieldValue(ast.expr, level); + this.emit(',\n'); + } + + visitObject(ast, level) { + assert.equal(ast.type, 'object'); + + if (ast.fields.length === 0) { + this.emit('[ '); + let comments = DSL.comment.getBetweenComments(this.comments, ast.tokenRange[0], ast.tokenRange[1]); + if (comments.length > 0) { + this.emit('\n'); + this.visitComments(comments, level + 1); + this.emit('', level); + } + this.emit(']'); + } else { + const mergeFields = []; + const mapFields = []; + for (let i = 0; i < ast.fields.length; i++) { + const field = ast.fields[i]; + if (field.type === 'objectField') { + mapFields.push(field); + } else if (field.type === 'expandField') { + mergeFields.push(field); + } else { + throw new Error('unimpelemented'); + } + } + + if(mergeFields.length > 0) { + this.emit('Dara::merge('); + } + this.emit('[\n'); + for (let i = 0; i < mapFields.length; i++) { + this.visitObjectField(mapFields[i], level + 1); + } + //find the last item's back comment + let comments = DSL.comment.getBetweenComments(this.comments, ast.fields[ast.fields.length - 1].tokenRange[0], ast.tokenRange[1]); + this.visitComments(comments, level + 1); + this.emit(']', level); + if(mergeFields.length > 0) { + for (let i = 0; i < mergeFields.length; i++) { + this.emit(', '); + this.visitExpr(mergeFields[i].expr, level + 1); + } + this.emit(')'); + } + + + } + } + + visitMethodCall(ast, level) { + assert.equal(ast.left.type, 'method_call'); + const name = _name(ast.left.id); + if (name.startsWith('$') && this.builtin[name]) { + const method = name.replace('$', ''); + this.builtin[name][method](ast.args, level); + return; + } else if (ast.isStatic) { + this.emit(`self::${name}`); + } else { + this.emit(`$this->${name}`); + } + this.visitArgs(ast.args, level); + } + + visitInstanceCall(ast, level) { + assert.equal(ast.left.type, 'instance_call'); + const method = _avoidKeywords(_name(ast.left.propertyPath[0])); + + if (ast.builtinModule && this.builtin[ast.builtinModule] && this.builtin[ast.builtinModule][method]) { + this.builtin[ast.builtinModule][method](ast, level); + } else { + if (ast.left.id.tag === DSL.Tag.Tag.VID) { + this.emit(`$this->${_vid(ast.left.id)}`); + } else { + this.emit(`$${_name(ast.left.id)}`); + } + this.emit(`->${(method)}`); + this.visitArgs(ast.args, level); + } + + } + + visitStaticCall(ast, level) { + assert.equal(ast.left.type, 'static_call'); + + if (ast.left.id.type === 'builtin_module') { + this.visitBuiltinStaticCall(ast); + return; + } + const aliasId = _name(ast.left.id); + const clientName= this.getRealClientName(aliasId); + this.emit(`${clientName}::${_avoidKeywords(_name(ast.left.propertyPath[0]))}`); + this.visitArgs(ast.args, level); + } + + visitBuiltinStaticCall(ast) { + const moduleName = _name(ast.left.id); + + const builtiner = this.builtin[moduleName]; + if (!builtiner) { + throw new Error('un-implemented'); + } + const func = _name(ast.left.propertyPath[0]); + builtiner[func](ast.args); + } + + visitCall(ast, level) { + assert.equal(ast.type, 'call'); + if (ast.left.type === 'method_call') { + this.visitMethodCall(ast, level); + } else if (ast.left.type === 'instance_call') { + this.visitInstanceCall(ast, level); + } else if (ast.left.type === 'static_call') { + this.visitStaticCall(ast, level); + } else { + throw new Error('un-implemented'); + } + } + + visitConstruct(ast, level) { + assert.equal(ast.type, 'construct'); + this.emit('new '); + let aliasId = this.getType(ast.aliasId.lexeme); + const clientName = this.getRealClientName(aliasId); + + this.emit(clientName || aliasId); + this.visitArgs(ast.args, level); + } + + visitSuper(ast, level) { + assert.equal(ast.type, 'super'); + this.emit('parent::__construct'); + this.visitArgs(ast.args, level); + } + + visitArgs(args, level) { + this.emit('('); + for (let i = 0; i < args.length; i++) { + const expr = args[i]; + if (expr.needCast) { + this.visitExpr(expr, level); + this.emit('->toArray()'); + } else { + this.visitExpr(expr, level); + } + if (i !== args.length - 1) { + this.emit(', '); + } + } + this.emit(')'); + } + + visitPropertyAccess(ast) { + assert.ok(ast.type === 'property_access' || ast.type === 'property'); + var id = _name(ast.id); + if (ast.id.tag === Tag.VID) { + id = `this->${_vid(ast.id)}`; + } + + var expr = `$${_avoidKeywords(id)}`; + + var current = ast.id.inferred; + for (var i = 0; i < ast.propertyPath.length; i++) { + var name = _name(ast.propertyPath[i]); + if (current.type === 'model') { + expr += `->${name}`; + } else { + if(!expr.startsWith('@')) { + expr = `@${expr}`; + } + expr += `['${name}']`; + } + current = ast.propertyPathTypes[i]; + } + this.emit(expr); + } + + visitExpr(ast, level) { + if (ast.type === 'boolean') { + this.emit(ast.value); + } else if (ast.type === 'property_access') { + this.visitPropertyAccess(ast); + } else if (ast.type === 'string') { + this.emit(`'${_string(ast.value)}'`); + } else if (ast.type === 'number') { + this.emit(ast.value.value); + } else if (ast.type === 'null') { + this.emit('null'); + } else if (ast.type === 'object') { + this.visitObject(ast, level); + } else if (ast.type === 'variable') { + if(ast.inferred && ast.inferred.type === 'basic' && ast.inferred.name === 'class') { + this.emit(`${_avoidKeywords(_name(ast.id))}::class`); + } else { + this.emit(`$${_avoidKeywords(_name(ast.id))}`); + } + } else if (ast.type === 'virtualVariable') { + this.emit(`$this->${_vid(ast.vid)}`); + } else if (ast.type === 'decrement') { + if (ast.position === 'front') { + this.emit('--'); + } + this.visitExpr(ast.expr, level); + if (ast.position === 'backend') { + this.emit('--'); + } + } else if (ast.type === 'increment') { + if (ast.position === 'front') { + this.emit('++'); + } + this.visitExpr(ast.expr, level); + if (ast.position === 'backend') { + this.emit('++'); + } + } else if (ast.type === 'template_string') { + this.emit('\''); + for (var i = 0; i < ast.elements.length; i++) { + var item = ast.elements[i]; + if (item.type === 'element') { + this.emit(_string(item.value)); + } else if (item.type === 'expr') { + this.emit('\' . '); + if(item.expr.inferred && item.expr.inferred.name !== 'string') { + this.emit('(string)'); + } + if(_isBinaryOp(item.expr.type)) { + this.emit('('); + } + this.visitExpr(item.expr, level); + if(_isBinaryOp(item.expr.type)) { + this.emit(')'); + } + this.emit(' . \''); + } else { + throw new Error('unimpelemented'); + } + } + this.emit('\''); + } else if (ast.type === 'call') { + this.visitCall(ast, level); + } else if (ast.type === 'construct') { + this.visitConstruct(ast, level); + } else if (ast.type === 'array') { + this.visitArray(ast, level); + } else if (ast.type === 'group') { + this.emit('('); + this.visitExpr(ast.expr, level); + this.emit(')'); + } else if (_isBinaryOp(ast.type)) { + this.visitExpr(ast.left, level); + if (ast.type === 'or') { + this.emit(' || '); + } else if (ast.type === 'add') { + if(ast.inferred && ast.inferred.type === 'basic' && ast.inferred.name === 'string') { + this.emit(' . '); + } else { + this.emit(' + '); + } + } else if (ast.type === 'subtract') { + this.emit(' - '); + } else if (ast.type === 'div') { + this.emit(' / '); + } else if (ast.type === 'multi') { + this.emit(' * '); + } else if (ast.type === 'and') { + this.emit(' && '); + } else if (ast.type === 'or') { + this.emit(' || '); + } else if (ast.type === 'lte') { + this.emit(' <= '); + } else if (ast.type === 'lt') { + this.emit(' < '); + } else if (ast.type === 'gte') { + this.emit(' >= '); + } else if (ast.type === 'gt') { + this.emit(' > '); + } else if (ast.type === 'neq') { + this.emit(' != '); + } else if (ast.type === 'eq') { + this.emit(' == '); + } + this.visitExpr(ast.right, level); + } else if (ast.type === 'group') { + this.emit('('); + this.visitExpr(ast.expr, level); + this.emit('('); + } else if (ast.type === 'not') { + this.emit('!'); + this.visitExpr(ast.expr, level); + } else if (ast.type === 'construct_model') { + this.visitConstructModel(ast, level); + } else if (ast.type === 'map_access') { + this.visitMapAccess(ast); + } else if (ast.type === 'array_access') { + this.visitArrayAccess(ast); + } else if (ast.type === 'super') { + this.visitSuper(ast, level); + } else { + console.log(ast); + throw new Error('unimpelemented'); + } + } + + visitConstructModel(ast, level) { + assert.equal(ast.type, 'construct_model'); + if (ast.aliasId.isModule) { + let aliasId = ast.aliasId.lexeme; + const { namespace } = this.moduleClass.get(aliasId); + const moduleModelName = ast.propertyPath.map((item) => { + return item.lexeme; + }).join('\\'); + const subModelName = this.getRealModelName(`${namespace}\\Models\\${moduleModelName}`); + this.emit(`new ${subModelName}`); + } + + if (ast.aliasId.isModel) { + let mainModelName = ast.aliasId; + + this.emit('new '); + const modelName = [mainModelName, ...ast.propertyPath].map((item) => { + return item.lexeme; + }).join('\\'); + if(_isBuiltinModel(modelName)) { + const subModelName = this.getRealModelName(this.getType(modelName)); + this.emit(subModelName); + } else { + const subModelName = this.getRealModelName(`${this.namespace}\\Models\\${modelName}`); + this.emit(subModelName); + } + + } + + this.emit('('); + if (ast.object) { + this.visitObject(ast.object, level); + } else { + this.emit('[ ]'); + } + this.emit(')'); + } + + visitMapAccess(ast, level) { + assert.equal(ast.type, 'map_access'); + let expr; + if (ast.id.tag === DSL.Tag.Tag.VID) { + expr = `$this->${_vid(ast.id)}`; + } else { + expr = `$${_name(ast.id)}`; + } + if (ast.propertyPath && ast.propertyPath.length) { + var current = ast.id.inferred; + for (var i = 0; i < ast.propertyPath.length; i++) { + var name = _name(ast.propertyPath[i]); + if (current.type === 'model') { + expr += `->${name}`; + } else { + expr += `['${name}']`; + } + current = ast.propertyPathTypes[i]; + } + } + this.emit(`@${expr}[`, level); + this.visitExpr(ast.accessKey, level); + this.emit(']'); + } + + visitArrayAccess(ast, level) { + assert.equal(ast.type, 'array_access'); + let expr; + if (ast.id.tag === DSL.Tag.Tag.VID) { + expr = `$this->${_vid(ast.id)}`; + } else { + expr = `$${_name(ast.id)}`; + } + if (ast.propertyPath && ast.propertyPath.length) { + var current = ast.id.inferred; + for (var i = 0; i < ast.propertyPath.length; i++) { + var name = _name(ast.propertyPath[i]); + if (current.type === 'model') { + expr += `->${name}`; + } else { + expr += `['${name}']`; + } + current = ast.propertyPathTypes[i]; + } + } + this.emit(`@${expr}[`, level); + this.visitExpr(ast.accessKey, level); + this.emit(']'); + } + + visitArray(ast, level) { + assert.equal(ast.type, 'array'); + let arrayComments = DSL.comment.getBetweenComments(this.comments, ast.tokenRange[0], ast.tokenRange[1]); + if (ast.items.length === 0) { + this.emit('[ '); + if (arrayComments.length > 0) { + this.emit('\n'); + this.visitComments(arrayComments, level + 1); + this.emit('', level); + } + this.emit(']'); + return; + } + + this.emit('[\n'); + let item; + for (let i = 0; i < ast.items.length; i++) { + item = ast.items[i]; + let comments = DSL.comment.getFrontComments(this.comments, item.tokenRange[0]); + this.visitComments(comments, level + 1); + this.emit('', level + 1); + this.visitExpr(item, level + 1); + if (i < ast.items.length - 1) { + this.emit(','); + } + this.emit('\n'); + } + if (item) { + //find the last item's back comment + let comments = DSL.comment.getBetweenComments(this.comments, item.tokenRange[0], ast.tokenRange[1]); + this.visitComments(comments, level + 1); + } + this.emit(']', level); + } + + visitYield(ast, level) { + assert.equal(ast.type, 'yield'); + this.emit('yield ', level); + if (!ast.expr) { + this.emit(';\n'); + return; + } + + if (ast.needCast) { + this.visitType(ast.expectedType); + this.emit('::fromMap('); + } + + this.visitExpr(ast.expr, level); + + if (ast.needCast) { + this.emit(')'); + } + + this.emit(';\n'); + } + + visitReturn(ast, level) { + assert.equal(ast.type, 'return'); + this.emit('return ', level); + if (!ast.expr) { + this.emit('null;\n'); + return; + } + + if (ast.needCast) { + this.visitType(ast.expectedType); + this.emit('::fromMap('); + } + + this.visitExpr(ast.expr, level); + + if (ast.needCast) { + this.emit(')'); + } + + this.emit(';\n'); + } + + visitRetry(ast, level) { + assert.equal(ast.type, 'retry'); + const errorName = this.getRealModelName(UNRETRY_ERROR); + this.emit(`throw ${errorName}($_lastRequest, $_lastException);\n`, level); + } + + visitTry(ast, level) { + assert.equal(ast.type, 'try'); + this.emit('try {\n', level); + this.visitStmts(ast.tryBlock, level + 1); + this.emit('}', level); + if (ast.catchBlocks && ast.catchBlocks.length > 0) { + ast.catchBlocks.forEach(catchBlock => { + if (!catchBlock.id) { + return; + } + if (!catchBlock.id.type) { + const errorName = this.getRealModelName(ERROR); + this.emit(` catch (${errorName} $${_name(catchBlock.id)}) {\n`); + } else { + this.emit(' catch ('); + this.visitType(catchBlock.id.type); + this.emit(` $${_name(catchBlock.id)}) {\n`); + } + this.visitStmts(catchBlock.catchStmts, level + 1); + this.emit('}', level); + }); + } else if (ast.catchBlock && ast.catchBlock.stmts.length > 0) { + const errorName = this.getRealModelName(ERROR); + this.emit(` catch (${errorName} $${_name(ast.catchId)}) {\n`); + this.visitStmts(ast.catchBlock, level + 1); + this.emit('}', level); + } + if (ast.finallyBlock && ast.finallyBlock.stmts.length > 0) { + this.emit(' finally {\n'); + this.visitStmts(ast.finallyBlock, level + 1); + this.emit('}', level); + } + this.emit('\n', level); + } + + visitWhile(ast, level) { + assert.equal(ast.type, 'while'); + this.emit('\n'); + this.emit('while (', level); + this.visitExpr(ast.condition, level + 1); + this.emit(') {\n'); + this.visitStmts(ast.stmts, level + 1); + this.emit('}\n', level); + } + + visitFor(ast, level) { + assert.equal(ast.type, 'for'); + this.emit('\n'); + this.emit('foreach(', level); + this.visitExpr(ast.list, level + 1); + this.emit(` as $${_name(ast.id)}`); + this.emit(') {\n'); + this.visitStmts(ast.stmts, level + 1); + this.emit('}\n', level); + } + + visitIf(ast, level) { + assert.equal(ast.type, 'if'); + this.emit('if (', level); + this.visitExpr(ast.condition, level + 1); + this.emit(') {\n'); + if(!ast.stmts.stmts.length) { + this.emit('', level + 1); + this.emit('\n'); + } + this.visitStmts(ast.stmts, level + 1); + this.emit('}', level); + if (ast.elseIfs) { + for (let i = 0; i < ast.elseIfs.length; i++) { + const branch = ast.elseIfs[i]; + this.emit(' else if ('); + this.visitExpr(branch.condition, level + 1); + this.emit(') {\n'); + if(!branch.stmts.stmts.length) { + this.emit('', level + 1); + this.emit('\n'); + } + this.visitStmts(branch.stmts, level + 1); + this.emit('}', level); + } + + } + + if (ast.elseStmts) { + this.emit(' else {\n'); + for (let i = 0; i < ast.elseStmts.stmts.length; i++) { + this.visitStmt(ast.elseStmts.stmts[i], level + 1); + } + if (ast.elseStmts.stmts.length === 0) { + const comments = DSL.comment.getBetweenComments(this.comments, ast.elseStmts.tokenRange[0], ast.elseStmts.tokenRange[1]); + this.visitComments(comments, level + 1); + this.emit('', level + 1); + this.emit('\n'); + } + this.emit('}', level); + } + + this.emit('\n'); + this.emit('\n'); + } + + visitThrow(ast, level) { + this.emit('throw ', level); + if (ast.expr.type === 'construct_model') { + this.visitConstructModel(ast.expr, level); + this.emit(';\n'); + } else { + const errorName = this.getRealModelName(ERROR); + this.emit(`new ${errorName}(`); + this.visitObject(ast.expr, level); + this.emit(');\n'); + } + } + + visitAssign(ast, level) { + if (ast.left.type === 'property_assign' || ast.left.type === 'property') { + this.emit('', level); + this.visitPropertyAccess(ast.left); + } else if (ast.left.type === 'virtualVariable') { // vid + this.emit(`$this->${_vid(ast.left.vid)}`, level); + } else if (ast.left.type === 'variable') { + this.emit(`$${_name(ast.left.id)}`, level); + } else if (ast.left.type === 'map_access') { + this.visitMapAccess(ast.left, level); + } else if (ast.left.type === 'array_access') { + this.visitArrayAccess(ast.left, level); + } else { + throw new Error('unimpelemented'); + } + + this.emit(' = '); + if (ast.expr.needToReadable) { + const streamName = this.getRealModelName(STREAM); + this.emit(`new ${streamName}(`); + } + this.visitExpr(ast.expr, level); + if (ast.expr.needToReadable) { + this.emit(')'); + } + this.emit(';\n'); + } + + visitDeclare(ast, level) { + var id = _name(ast.id); + this.emit(`$${id}`, level); + this.emit(' = '); + this.visitExpr(ast.expr, level); + this.emit(';\n'); + } + + visitStmts(ast, level) { + assert.equal(ast.type, 'stmts'); + let node; + for (var i = 0; i < ast.stmts.length; i++) { + node = ast.stmts[i]; + this.visitStmt(node, level); + } + if (node) { + //find the last node's back comment + let comments = DSL.comment.getBackComments(this.comments, node.tokenRange[1]); + this.visitComments(comments, level); + } + + if (ast.stmts.length === 0) { + //empty block's comment + let comments = DSL.comment.getBetweenComments(this.comments, ast.tokenRange[0], ast.tokenRange[1]); + this.visitComments(comments, level); + } + } + + visitReturnBody(ast, level) { + assert.equal(ast.type, 'returnBody'); + this.emit('\n'); + this.visitStmts(ast.stmts, level); + } + + visitDefaultReturnBody(level) { + this.emit('\n'); + this.emit('return [];\n', level); + } + + visitFunctionBody(ast, level) { + assert.equal(ast.type, 'functionBody'); + this.visitStmts(ast.stmts, level); + } + + isIterator(returnType) { + if (returnType.type === 'iterator' || returnType.type === 'asyncIterator') { + return true; + } + return false; + } + + eachFunction(ast, level) { + let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]); + this.visitComments(comments, level); + this.visitAnnotation(ast.annotation, level, false); + const functionName = _avoidKeywords(_name(ast.functionName)); + + if(!ast.annotation || !ast.annotation.value) { + this.emit('/**\n', level); + } + this.visitParamsType(ast.params, level); + this.visitReturnType(ast, level); + this.emit(' */', level); + this.emit('\n'); + + this.emit('', level); + if (ast.isStatic) { + this.emit('static '); + } + + this.emit(`public function ${functionName}`); + + this.visitParams(ast.params, level); + this.emit('\n'); + this.emit('{\n', level); + if (ast.functionBody) { + this.visitFunctionBody(ast.functionBody, level + 1); + } else { + this.used.push('use RuntimeException;'); + // interface mode + this.emit('throw new RuntimeException(\'Un-implemented!\');\n', level + 1); + } + this.emit('}\n', level); + } + + visitParamsType(ast, level) { + for (var i = 0; i < ast.params.length; i++) { + const node = ast.params[i]; + assert.equal(node.type, 'param'); + this.emit(' * @param ', level); + this.visitType(node.paramType, level); + this.emit(' '); + const name = _name(node.paramName); + this.emit(`$${_avoidKeywords(name)}\n`); + } + } + + visitReturnType(ast, level) { + this.emit(' * @return ', level); + this.visitType(ast.returnType, level); + this.emit('\n'); + } + + eachAPI(ast, level) { + // if (ast.annotation) { + // this.emit(`${_anno(ast.annotation.value)}\n`, level); + // } + let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]); + this.visitComments(comments, level); + this.visitAnnotation(ast.annotation, level, false); + const apiName = _avoidKeywords(_name(ast.apiName)); + if(!ast.annotation || !ast.annotation.value) { + this.emit('/**\n', level); + } + + this.visitParamsType(ast.params, level); + this.visitReturnType(ast, level); + this.emit(' */', level); + this.emit('\n'); + + + this.emit(`public function ${apiName}`, level); + this.visitParams(ast.params, level); + this.emit('\n'); + this.emit('{\n', level); + let baseLevel = ast.runtimeBody ? level + 2 : level; + // api level + if (ast.runtimeBody) { + this.visitRuntimeBefore(ast.runtimeBody, level + 1); + } + + // temp level + this.visitAPIBody(ast.apiBody, baseLevel + 1); + + + + this.emit('$_response = Dara::send($_request', baseLevel + 1); + + if (ast.runtimeBody) { + this.emit(', $_runtime'); + } + this.emit(');\n'); + + if (ast.runtimeBody) { + this.emit('$_lastRequest = $_request;\n', baseLevel + 1); + this.emit('$_lastResponse = $_response;\n', baseLevel + 1); + } + + if (ast.returns) { + this.visitReturnBody(ast.returns, baseLevel + 1); + } else { + this.visitDefaultReturnBody(baseLevel + 1); + } + + if (ast.runtimeBody) { + this.visitRuntimeAfter(ast.runtimeBody, level + 1); + } + + this.emit('}\n', level); + } + + visitRuntimeAfter(ast, level) { + const errorName = this.getRealModelName(ERROR); + this.emit(`} catch (${errorName} $e) {\n`, level + 1); + const retryContextName = this.getRealModelName(RETRY_CONTEXT); + this.emit(`$_context = new ${retryContextName}([\n`, level + 2); + this.emit('\'retriesAttempted\' => $_retriesAttempted,\n', level + 3); + this.emit('\'lastRequest\' => $_lastRequest,\n', level + 3); + this.emit('\'lastResponse\' => $_lastResponse,\n', level + 3); + this.emit('\'exception\' => $e,\n', level + 3); + this.emit(']);\n', level + 2); + this.emit('continue;\n', level + 2); + this.emit('}\n', level + 1); + this.emit('}\n', level); + this.emit('\n'); + const unretryErrorName = this.getRealModelName(UNRETRY_ERROR); + this.emit(`throw ${unretryErrorName}($_context);\n`, level); + } + + importBefore(level) { + if (this.config.editable !== true) { + this.emit('// This file is auto-generated, don\'t edit it\n', level); + } + } + + apiBefore(main, filepath, level) { + let clientName = this.config.clientName; + if(!main) { + const beginNotes = DSL.note.getNotes(this.notes, 0, this.ast.moduleBody.nodes[0].tokenRange[0]); + const clientNote = beginNotes.find(note => note.note.lexeme === '@clientName'); + if(clientNote) { + clientName = _string(clientNote.arg.value); + } else { + const fileInfo = path.parse(filepath); + clientName = `${_upperFirst(fileInfo.name.toLowerCase())}Client`; + } + } + + this.emit(`class ${clientName}`, level); + if (this.parentModule) { + const moduleName = this.getRealClientName(this.parentModule.lexeme); + this.emit(` extends ${moduleName}\n`); + } + this.emit(' {\n', level); + } + + functionBefore() { + this.emit('\n'); + } + + moduleAfter() { + this.emit(` +} +`); + } + +} + +module.exports = Visitor; diff --git a/lib/helper.js b/lib/helper.js new file mode 100644 index 0000000..d9f2f40 --- /dev/null +++ b/lib/helper.js @@ -0,0 +1,101 @@ +'use strict'; + +const keywords = [ + // https://www.php.net/manual/zh/reserved.keywords.php + '__halt_compiler', 'abstract', 'and', 'array', 'as', + 'break', 'callable', 'case', 'catch', 'class', + 'clone', 'const', 'continue', 'declare', 'default', + 'die', 'do', 'echo', 'else', 'elseif', + 'empty', 'enddeclare', 'endfor', 'endforeach', 'endif', + 'endswitch', 'endwhile', 'eval', 'exit', 'extends', + 'final', 'for', 'foreach', 'function', + 'global', 'goto', 'if', 'implements', 'include', + 'include_once', 'instanceof', 'insteadof', 'interface', 'isset', + 'list', 'namespace', 'new', 'or', 'print', + 'private', 'protected', 'public', 'require', 'require_once', + 'return', 'static', 'switch', 'throw', 'trait', + 'try', 'unset', 'use', 'var', 'while', 'xor' +]; + +const builtinModels = ['$Request', '$Response', '$Error', '$SSEEvent', '$Model']; +const NAMESPACE = 'AlibabaCloud\\Dara'; +const CORE = 'AlibabaCloud\\Dara\\Dara'; +const REQUEST = 'AlibabaCloud\\Dara\\Request'; +const RESPONSE = 'AlibabaCloud\\Dara\\Response'; +const MODEL = 'AlibabaCloud\\Dara\\Model'; +const ERROR = 'AlibabaCloud\\Dara\\Exception\\DaraException'; +const UNRETRY_ERROR = 'AlibabaCloud\\Dara\\Exception\\DaraUnableRetryException'; +const RESP_ERROR = 'AlibabaCloud\\Dara\\Exception\\DaraRespException'; +const RETRY_CONTEXT = 'AlibabaCloud\\Dara\\RetryPolicy\\RetryPolicyContext'; +const SSE_EVENT = 'AlibabaCloud\\Dara\\SSE\\Event'; +const STREAM = 'GuzzleHttp\\Psr7\\Stream'; + + +function _name(str) { + if (str.lexeme === '__request') { + return '_reqeust'; + } + + if (str.lexeme === '__response') { + return '_response'; + } + + return str.lexeme || str.name; +} + +function _upperFirst(str) { + return str[0].toUpperCase() + str.substring(1); +} + +function _subModelName(name) { + return name.split('.').map((name) => _upperFirst(name)).join(''); +} + +function _avoidKeywords(str) { + if (keywords.indexOf(str.toLowerCase()) > -1) { + return str + '_'; + } + return str; +} + +function _modelName(str) { + if (keywords.indexOf(str.toLowerCase()) > -1 || str.toLowerCase() === 'model') { + return str + '_'; + } + return str; +} + + +function _string(str) { + if (str.string === '\'\'') { + return '\\\'\\\''; + } + return str.string.replace(/([^\\])'+|^'/g, function(str){ + return str.replace(/'/g, '\\\''); + }); +} + +function _isBinaryOp(type){ + const op = [ + 'or', 'eq', 'neq', + 'gt', 'gte', 'lt', + 'lte', 'add', 'subtract', + 'div', 'multi', 'and' + ]; + return op.includes(type); +} + +function _vid(vid) { + return `_${_name(vid).substr(1)}`; +} + +function _isBuiltinModel(name){ + return builtinModels.includes(name); +} + +module.exports = { + _name, _string, _subModelName, _vid, _upperFirst, _isBuiltinModel, + _isBinaryOp, _modelName, _avoidKeywords, RETRY_CONTEXT, + REQUEST, RESPONSE, MODEL, NAMESPACE, ERROR, STREAM, UNRETRY_ERROR, + CORE, SSE_EVENT, RESP_ERROR +}; \ No newline at end of file diff --git a/package.json b/package.json index 82de350..874b2ed 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,8 @@ "lib": "src" }, "scripts": { - "lint": "eslint --fix src/ tests/", - "test": "mocha --reporter spec --timeout 3000 tests/*.tests.js", + "lint": "eslint --fix lib/ tests/", + "test": "mocha --reporter spec --timeout 3000 tests/*.test.js", "test-cov": "nyc -r=lcov -r=html -r=text -r=json mocha -t 3000 -R spec tests/*.tests.js", "ci": "npm run lint && npm run test-cov && codecov" }, @@ -19,7 +19,8 @@ "author": "Alibaba Cloud OpenAPI Team", "license": "Apache-2.0", "dependencies": { - "@darabonba/parser": "^1.2.7", + "@darabonba/annotation-parser": "^1.0.0", + "@darabonba/parser": "^2.0.5", "camelcase": "^6.0", "enum": "^3.0" }, diff --git a/src/generator.js b/src/generator.js deleted file mode 100644 index e97208d..0000000 --- a/src/generator.js +++ /dev/null @@ -1,245 +0,0 @@ -'use strict'; - -const path = require('path'); -const fs = require('fs'); -const debug = require('./lib/debug'); -const { _deepClone, _assignObject } = require('./lib/helper'); -const ClientResolver = require('./resolver/client'); -const ModelResolver = require('./resolver/model'); -const DSL = require('@darabonba/parser'); - -function readLock(pkg_dir) { - const filepath = path.join(pkg_dir, '.libraries.json'); - if (!fs.existsSync(filepath)) { - throw new Error('The `.libraries.json` file could not be found. Please execute "dara install" first.'); - } - return JSON.parse(fs.readFileSync(filepath, 'utf8')); -} - -function readMetafile(module_dir) { - const filepath = fs.existsSync(path.join(module_dir, 'Teafile')) - ? path.join(module_dir, 'Teafile') - : path.join(module_dir, 'Darafile'); - return JSON.parse(fs.readFileSync(filepath)); -} - -function readModuleMeta(module_dir, pkg_dir, lock) { - if (!path.isAbsolute(module_dir)) { - if (module_dir.startsWith('./') || module_dir.startsWith('../')) { - module_dir = path.join(pkg_dir, module_dir); - } else { - module_dir = path.join(pkg_dir, lock[module_dir]); - } - } - return readMetafile(module_dir); -} - -function resolveDependencies(lang, config, ast) { - const imports = ast.imports; - const dependencies = { - // Package AliasID : { meta, scope, package_name, client_name, client_alias } - }; - if (!imports || !imports.length) { - return dependencies; - } - - const self_client_name = config.clientName - ? config.clientName.toLowerCase() - : config.client.name.toLowerCase(); - const libraries = config.libraries; - const lock = readLock(config.pkgDir); - const default_client_name = config.client.name; - const default_model_dir = config.model.dir; - - let package_sets = []; - let client_sets = []; - ast.imports.forEach((item) => { - const aliasId = item.lexeme; - const meta = readModuleMeta( - libraries[aliasId], - config.pkgDir, - lock - ); - meta.libraries = { - lock: lock[libraries[aliasId]], - tag: libraries[aliasId], - alias_id: aliasId - }; - const scope = meta.scope; - let package_name = meta.name; - let client_name = default_client_name; - let model_dir = default_model_dir; - let lang_config = !meta[lang] ? {} : meta[lang]; - let typedef = {}; - if (lang_config.package) { - package_name = lang_config.package; - } - if (lang_config.clientName) { - client_name = lang_config.clientName; - } - if (lang_config.modelDirName) { - model_dir = lang_config.modelDirName; - } - if (lang_config.typedef) { - const moduleTypedef = lang_config.typedef; - Object.keys(moduleTypedef || {}).forEach((types) => { - if (!typedef[types]) { - typedef[types] = {}; - } - typedef[types].import = moduleTypedef[types].import; - typedef[types].type = moduleTypedef[types].type; - typedef[types].package = moduleTypedef[types].package; - }); - } - // check package name duplication - if (package_sets.indexOf(package_name.toLowerCase()) > 0) { - debug.stack(`The package name (${package_name}) has been defined in ${aliasId} dara package.`); - } - package_sets.push(package_name.toLowerCase()); - - // check client name duplication - let client_name_lower = client_name.toLowerCase(); - let client_alias = ''; - if (client_sets.indexOf(client_name_lower) > -1 || client_name_lower === self_client_name) { - client_alias = package_name.split('.').join('') + '->' + client_name.split('.').join(''); - } else { - client_sets.push(client_name_lower); - } - dependencies[aliasId] = { - meta, - scope, - package_name, - client_name, - client_alias, - model_dir, - typedef - }; - }); - return dependencies; -} - -function getCombinator(lang, configOriginal, denpendencies) { - const config = _deepClone(configOriginal); - - // init combinator - const Combinator = require(`./langs/${lang}/combinator`); - return new Combinator(config, denpendencies); -} - -function resolveAST(lang, config, type, ast, globalAST) { - const combinator = getCombinator(lang, config); - let resolver; - switch (type) { - case 'client': - resolver = new ClientResolver(ast, combinator, ast); - break; - case 'model': - resolver = new ModelResolver(ast, combinator, globalAST); - break; - } - const objectItem = resolver.resolve(); - objectItem.includeList = combinator.includeList; - objectItem.includeModelList = combinator.includeModelList; - return objectItem; -} - -function resolveObject(lang, config, ast, dependencies) { - const objects = []; - - // combine client code - const clientObjectItem = resolveAST(lang, config, 'client', ast, ast); - objects.push(clientObjectItem); - - // combine model code - ast.moduleBody.nodes.filter((item) => { - return item.type === 'model'; - }).forEach((model) => { - const modelName = model.modelName.lexeme; - const modelObjectItem = resolveAST(lang, config, 'model', model, ast); - if (ast.models) { - Object.keys(ast.models).filter((key) => { - return key.startsWith(modelName + '.'); - }).forEach((key) => { - const subModel = ast.models[key]; - const subModelObjectItem = resolveAST(lang, config, 'model', subModel, ast); - modelObjectItem.subObject.push(subModelObjectItem); - }); - } - objects.push(modelObjectItem); - }); - - const combinator = getCombinator(lang, config, dependencies); - combinator.combine(objects); - return objects; -} - -function resolveLibraries(pkg_dir, dependencies) { - const lock = readLock(pkg_dir); - Object.keys(dependencies).forEach((pack) => { - const lib = dependencies[pack]; - const libraries = lib.meta.libraries; - const basepath = path.join(pkg_dir, libraries.lock); - const meta = readMetafile(basepath); - if (meta.libraries && Object.keys(meta.libraries).length > 0) { - const obj = {}; - Object.keys(meta.libraries).forEach(item => { - if (lock[meta.libraries[item]]) { - obj[meta.libraries[item]] = lock[meta.libraries[item]].replace('libraries/', '../'); - } - }); - fs.writeFileSync(path.join(basepath, '.libraries.json'), JSON.stringify(obj, null, 2)); - } - // resolve sub package AST - let mainFilePath = path.join(basepath, meta.main); - const content = fs.readFileSync(mainFilePath, 'utf-8'); - dependencies[pack].ast = DSL.parse(content, mainFilePath); - }); -} - -class Generator { - constructor(meta = {}, lang = 'php') { - if (!meta.outputDir) { - throw new Error('`option.outputDir` should not empty'); - } - this.lang = lang; - const langDir = path.join(__dirname, `./langs/${lang}/`); - if (!fs.existsSync(langDir)) { - throw new Error(`Not supported language : ${lang}`); - } - const lang_config = require(`./langs/${lang}/config`); - const common_config = _deepClone(require('./langs/common/config')); - const config = { - dir: meta.outputDir, - }; - const meta_lang_config = !meta[lang] ? {} : meta[lang]; - const typedef = meta[lang] && meta[lang].typedef ? meta[lang].typedef : {}; - this.config = _assignObject( - config, - common_config, - lang_config, - meta, - meta_lang_config, - typedef - ); - } - - visit(ast) { - const lang = this.lang; - const config = this.config; - - // return objects; - const dependencies = resolveDependencies(lang, config, ast); - if (config.advanced) { - resolveLibraries(config.pkgDir, dependencies); - } - if (config.clientName) { - config.client.name = config.clientName; - } - if (config.modelDirName) { - config.model.dir = config.modelDirName; - } - return resolveObject(lang, config, ast, dependencies); - } -} - -module.exports = Generator; diff --git a/src/langs/common/combinator.js b/src/langs/common/combinator.js deleted file mode 100644 index 83749b4..0000000 --- a/src/langs/common/combinator.js +++ /dev/null @@ -1,216 +0,0 @@ -'use strict'; - -const debug = require('../../lib/debug'); -const Emitter = require('../../lib/emitter'); - -const { - Grammer, - GrammerThrows, - - Behavior, - PropItem, - AnnotationItem, - ObjectItem, -} = require('./items'); - -const { - _name, - _config, - _upperFirst, - _lowerFirst, - is, -} = require('../../lib/helper.js'); - -class BaseCombinator { - constructor(config = {}, dependencies = {}) { - this.level = 0; - this.eol = ''; - - this.includeList = []; - this.includeModelList = []; - this.includeSet = []; - - this.config = config; - this.dependencies = dependencies; - this.typedef = config.typedef; - - _config(this.config); - } - - combine(objects = []) { - if (objects.some(Object => !(Object instanceof ObjectItem))) { - throw new Error('Only supported ObjectItem.'); - } - } - - combineOutputParts(config, outputParts, append = false) { - const globalEmitter = new Emitter(config); - globalEmitter.emit(outputParts.head); - globalEmitter.emit(outputParts.body); - globalEmitter.emit(outputParts.foot); - globalEmitter.save(append); - } - - coreClass(objName) { - const key = _lowerFirst(objName.split('$').join('')); - if (this.config.tea[key]) { - return this.config.tea[key].name; - } - debug.stack('Unsupported core class name : ' + objName); - } - - resolveNotes(nodes) { - let notes = {}; - nodes.filter(node => node instanceof PropItem).map(prop => { - if (prop.notes.length > 0) { - prop.notes.forEach(note => { - note.belong = prop.index; - note.prop = prop.name; - if (typeof notes[note.key] === 'undefined') { - notes[note.key] = []; - } - notes[note.key].push(note); - }); - } - }); - return notes; - } - - resolveName(path_name, avoidKeyword = true) { - if (path_name instanceof Grammer) { - let emit = new Emitter(this.config); - this.grammer(emit, path_name, false, false); - path_name = emit.output; - } else { - path_name = `${path_name}`; - if (path_name.indexOf('^') === 0) { // Client - path_name = this.addInclude(path_name.substr(1)); - } else if (path_name.indexOf('#') === 0) { // Model - path_name = this.addModelInclude(path_name.substr(1)); - } else if (path_name.indexOf('$') === 0) { // System : Tea Core Class - path_name = this.addInclude(path_name); - } else if (path_name.indexOf('%') === 0) { // Typedef - return this.addTypedefInclude(path_name.substr(1)); - } - } - return _name(path_name, avoidKeyword); - } - - emitAnnotations(emitter, annotations) { - annotations.forEach(annotation => { - this.emitAnnotation(emitter, annotation); - }); - } - - findThrows(grammer, set = []) { - if (grammer.body) { - grammer.body.filter(node => { - if (node instanceof GrammerThrows) { - set.push(node); - } else if (node.body) { - this.findThrows(node, set); - } - }); - } - return set; - } - - init(ast) { - throw new Error('unimpelemented'); - } - - levelUp() { - this.level++; - return this.level; - } - - levelDown() { - this.level--; - return this.level; - } - - addModelInclude(modelName) { - throw new Error('unimpelemented'); - } - - addInclude(include) { - throw new Error('unimpelemented'); - } - - systemfunc(emitter, gram) { - let tmp = []; - gram.path.forEach(path => { - tmp.push(_upperFirst(path.name)); - }); - if (tmp.length === 0) { - debug.stack('Invalid path. path list cannot be empty.'); - } - let systemFunc = 'sys' + tmp.join(''); - if (this[systemFunc]) { - this[systemFunc].apply(this, [emitter, gram]); - } else { - debug.stack(`unimpelemented ${systemFunc}(emitter, gram){} method\n`, gram); - } - } - - grammer(emit, gram, eol = true, newLine = true) { - if (gram instanceof AnnotationItem) { - this.emitAnnotation(emit, gram); - return; - } - - let emitter = new Emitter(this.config); - let method = null; - if (gram instanceof Behavior) { - method = gram.name; - } else if (gram instanceof Grammer) { - method = _lowerFirst(gram.constructor.name); - } else { - debug.stack('Unsupported', gram); - } - if (typeof this[method] !== 'undefined') { - this[method].call(this, emitter, gram); - } else { - debug.stack('Unimpelemented : ' + method); - } - if (gram.eol !== null) { - eol = gram.eol; - } - if (gram.newLine !== null) { - newLine = gram.newLine; - } - if (newLine) { - emit.emit('', this.level); - } - emit.emit(emitter.output); - if (eol) { - emit.emitln(this.eol); - } - emitter = null; - } - - gramRender(gram) { - if (!is.grammer(gram)) { - return ''; - } - let emitter = new Emitter(this.config); - this.grammer(emitter, gram, false, false); - return emitter.output; - } - - grammerNewLine(emitter, gram) { - let number = gram.number; - while (number > 0) { - emitter.emitln(); - number--; - } - } - - emitGrammerValue(gram) { - let emitter = new Emitter(this.config); - this.grammerValue(emitter, gram); - return emitter.output; - } -} - -module.exports = BaseCombinator; diff --git a/src/langs/common/config.js b/src/langs/common/config.js deleted file mode 100644 index 765e2ac..0000000 --- a/src/langs/common/config.js +++ /dev/null @@ -1,33 +0,0 @@ -'use strict'; - -module.exports = { - indent: ' ', - ext: '.tea', - resolvePathByPackage: false, - package: 'DarabonbaSDK', - pkgDir: '', - output: true, - layer: '', - keywords: [], - typeMap: {}, - symbolMap: {}, - modifyOrder: [], - exceptionMap: {}, - model: { - include: [], - constructor: { - params: [] - } - }, - client: { - filename: 'client', - include: [] - }, - generateFileInfo: 'This file is auto-generated, don\'t edit it. Thanks.', - response: '_response', - request: '_request', - runtime: '_runtime', - baseClient: [], - tea: {}, - modules: {} -}; diff --git a/src/langs/common/enum.js b/src/langs/common/enum.js deleted file mode 100644 index 26c112a..0000000 --- a/src/langs/common/enum.js +++ /dev/null @@ -1,125 +0,0 @@ -'use strict'; - -const Enum = require('enum'); - -class SymbolEnum extends Enum { - constructor() { - super([ - 'ASSIGN', - 'EQ', - 'NOT', - 'AND', - 'OR', - 'PLUS', - 'SUB', - 'MULTI', - 'DIV', - 'POWER', - 'GREATER', - 'GREATER_EQ', - 'LESS', - 'LESS_EQ', - 'REVERSE', - 'CONCAT', - 'JUDGE', - 'RISK' - ], { name: 'symbol', ignoreCase: true }); - } - assign() { - return this.ASSIGN.key; - } - eq() { - return this.EQ.key; - } - not() { - return this.NOT.key; - } - and() { - return this.AND.key; - } - or() { - return this.OR.key; - } - plus() { - return this.PLUS.key; - } - multi() { - return this.MULTI.key; - } - div() { - return this.DIV.key; - } - power() { - return this.POWER.key; - } - greater() { - return this.GREATER.key; - } - greaterEq() { - return this.GREATER_EQ.key; - } - less() { - return this.LESS.key; - } - lessEq() { - return this.LESS_EQ.key; - } - reverse() { - return this.REVERSE.key; - } - concat() { - return this.CONCAT.key; - } - judge() { - return this.JUDGE.key; - } - risk() { - return this.RISK.key; - } -} - -class ModifyEnum extends Enum { - constructor() { - super([ - 'ASYNC', - 'PRIVATE', - 'PROTECTED', - 'INTERNAL', - 'PUBLIC', - 'FINAL', - 'ABSTRACT', - 'STATIC' - ], { name: 'modify', ignoreCase: true }); - } - async() { - return this.ASYNC.key; - } - private() { - return this.PRIVATE.key; - } - protected() { - return this.PROTECTED.key; - } - internal() { - return this.INTERNAL.key; - } - public() { - return this.PUBLIC.key; - } - final() { - return this.FINAL.key; - } - abstract() { - return this.ABSTRACT.key; - } - static() { - return this.STATIC.key; - } -} -const Symbol = new SymbolEnum(); -const Modify = new ModifyEnum(); - -module.exports = { - Symbol, - Modify, -}; diff --git a/src/langs/common/items.js b/src/langs/common/items.js deleted file mode 100644 index 5489846..0000000 --- a/src/langs/common/items.js +++ /dev/null @@ -1,652 +0,0 @@ -'use strict'; - -const assert = require('assert'); -const debug = require('../../lib/debug'); - -class Counter { - constructor(start = -1) { - this.index = start; - } - once() { - this.index++; - return this.index; - } - step(step = 1, length = 1) { - this.index = this.index + step * length; - return this.index; - } -} -const count = new Counter(); -const ItemSet = {}; - -class Item { - constructor() { - this.index = count.once(); - ItemSet[this.index] = this; - this.belong = 0; - } - - getItemByIndex(index) { - if (ItemSet[index]) { - return ItemSet[index]; - } - debug.stack(`Index [${index}] not exist in ItemSet`); - } - - setBelongTo(gram, belong) { - if (gram instanceof Item) { - gram.belong = belong; - } - } - - getParent() { - return this.getItemByIndex(this.belong); - } -} - -class TypeItem extends Item { - constructor() { - super(); - this.isOptional = false; - } -} - -class TypeBase extends TypeItem { } - -class TypeVoid extends TypeBase { } - -class TypeNull extends TypeBase { } - -class TypeGeneric extends TypeBase { } - -class TypeString extends TypeBase { - constructor() { super(); } -} - -class TypeNumber extends TypeBase { - constructor() { - super(); - // TypeNumber contains TypeInteger/TypeDecimal - } -} - -class TypeInteger extends TypeNumber { - constructor(length = 16, unsigned = false) { - super(); - // int/uint long/ulong integer - this.length = length; - this.unsigned = unsigned; - } -} - -class TypeDecimal extends TypeNumber { - constructor(precision = 8) { - super(); - // float : precision = 4 - // double : precision = 8 - this.precision = precision; - } -} - -class TypeBool extends TypeBase { } - -class TypeTree extends TypeBase { } - -class TypeArray extends TypeTree { - constructor(itemType = null) { - super(); - assert.strictEqual(true, itemType instanceof TypeItem); - this.itemType = itemType; // TypeItem - } -} - -class TypeBytes extends TypeTree { - constructor() { - super(new TypeInteger(8, true)); - // bytes = uint8[] - } -} - -class TypeMap extends TypeTree { - constructor(keyType, valType) { - super(); - assert.strictEqual(true, keyType instanceof TypeItem); - assert.strictEqual(true, valType instanceof TypeItem); - this.keyType = keyType; - this.valType = valType; - } -} - -class TypeObject extends TypeItem { - constructor(objectName = null) { - super(); - this.objectName = objectName; - } -} - -class TypeStream extends TypeBase { - constructor(writable = null) { - super(); - this.writable = writable; - } -} - -class AnnotationItem extends Item { - constructor(belong, mode = 'single', content = null) { - super(); - this.belong = belong; - this.mode = mode; // single | multi - this.content = content; - } -} - -class Grammer extends Item { - constructor(eol = null, newLine = null) { - super(); - this.eol = eol; - this.newLine = newLine; - } -} - -class GrammerValue extends Grammer { - constructor(type, value, key = '', needCast = false) { - super(); - if (key instanceof TypeItem) { - this.dataType = key; - } else { - this.key = key; - this.dataType = null; // TypeItem - } - this.type = type; // map | array | string | number | call | null | behavior | param | expr | merge | var | class - this.value = value; - this.needCast = needCast; - this.isExpand = false; - } -} - -class GrammerNewObject extends Grammer { - constructor(objectName, params = [], type = 'var') { - super(); - this.name = objectName; - this.params = params; - this.type = type; // var | map - } - - addParam(param) { - this.params.push(param); - } -} - -class GrammerVar extends Grammer { - constructor(name = '', dataType = '', varType = 'var') { - super(); - this.name = name; - this.type = dataType; // TypeItem - this.varType = varType; // static_class 静态类名 || var 可变 || const 不可变 - this.eol = false; - assert.strictEqual(true, this.type instanceof TypeItem); - } -} - -class GrammerExpr extends Grammer { - constructor(left = null, opt = '', right = '') { - super(); - this.left = left; // GrammerVar - this.opt = opt; - this.right = right; - this.setBelongTo(left, this.index); - this.setBelongTo(right, this.index); - } -} - -class GrammerCall extends Grammer { - constructor(type = 'method', path = [], params = [], returnType = null, hasThrow = false) { - super(); - this.type = type; // method | key | index | prop | sys_func | super - this.path = []; - path.forEach(p => { - this.addPath(p); - }); - this.params = params; - if (returnType === null) { - returnType = new TypeVoid(); - } - this.returnType = returnType; // TypeItem - this.hasThrow = hasThrow; - assert.strictEqual(true, this.returnType instanceof TypeItem); - } - - addPath(path) { - // {type: '', name: ''} - const pathType = [ - 'parent', 'object', 'object_static', 'call', 'call_static', 'prop', 'prop_static', 'map', 'list' - ]; - if (pathType.indexOf(path.type) < 0) { - throw new Error( - `${path.type} path.type should be parent|object|object_static|call|call_static|prop|prop_static|map|list` - ); - } - this.path.push(path); - return this; - } - - addParams(param) { - this.params.push(param); - return this; - } -} - -class GrammerCondition extends Grammer { - constructor(type = '', conditionBody = [], body = []) { - super(); - this.type = type; // like 'if' | elseif | else | 'while' | 'doWhile' - this.body = body; // Grammer - this.conditionBody = conditionBody; // GrammerExpr | GrammerValue | GrammerCall - this.elseItem = []; - this.eol = false; - } - - addElse(elseItem) { - assert.strictEqual(true, elseItem instanceof GrammerCondition); - this.elseItem.push(elseItem); - } - - addBodyNode(node) { - assert.strictEqual(true, node instanceof Grammer || node instanceof AnnotationItem); - this.body.push(node); - return this; - } - - addCondition(condition) { - assert.strictEqual(true, - condition instanceof GrammerExpr || - condition instanceof GrammerValue || - condition instanceof GrammerCall - ); - this.conditionBody.push(condition); - } -} - -class GrammerException extends Grammer { - constructor(type, exceptionVar = null) { - super(); - this.type = type; - this.exceptionVar = exceptionVar; // GrammerVar - } -} - -class GrammerCatch extends Grammer { - constructor(body = [], exceptions = null) { - super(); - this.exceptions = exceptions; // GrammerException - this.body = body; // Grammer - } - - addBodyNode(node) { - this.body.push(node); - } -} - -class GrammerFinally extends Grammer { - constructor(body = []) { - super(); - this.body = body; // Grammer - } - - addBodyNode(node) { - this.body.push(node); - } -} - -class GrammerTryCatch extends Grammer { - constructor(body = [], catchGramList = [], finallyGram = null) { - super(); - this.body = body; // Grammer - this.catchBody = catchGramList; // GrammerCatch - this.finallyBody = finallyGram; // GrammerFinally - this.eol = false; - } - - addBodyNode(node) { - assert.strictEqual(true, node instanceof Grammer || node instanceof AnnotationItem); - this.body.push(node); - } - - addCatch(node) { - assert.strictEqual(true, node instanceof GrammerCatch); - this.catchBody.push(node); - } - - setFinally(node) { - assert.strictEqual(true, node instanceof GrammerFinally); - this.finallyBody = node; - } -} - -class GrammerThrows extends Grammer { - constructor(exceptionType = null, params = [], msg = '') { - super(); - if (exceptionType !== null) { - assert.strictEqual(true, exceptionType instanceof TypeObject); - } - this.exception = exceptionType; // TypeObject - this.params = params; // GrammerValue - this.message = msg; - } - - addParam(param) { - assert.strictEqual(true, param instanceof GrammerValue); - this.params.push(param); - } -} - -class GrammerReturn extends Grammer { - constructor(expr = '', type = '') { - super(); - this.type = type; // null | grammer - this.expr = expr; - } -} - -class GrammerLoop extends Grammer { - constructor(type = '') { - super(); - this.type = type; // foreach | forCondition - this.item = null; // GrammerVar - this.source = null; // GrammerCall | GrammerValue - this.start = null; // GrammerExpr - this.contions = []; - this.step = null; // GrammerExpr - this.body = []; - this.eol = false; - } - - addBodyNode(node) { - assert.strictEqual(true, node instanceof Grammer); - this.body.push(node); - } -} - -class GrammerContinue extends Grammer { - constructor(belong) { - super(); - this.belong = belong; // counter index - } -} - -class GrammerBreak extends Grammer { - constructor(belong) { - super(); - this.belong = belong; // counter index - } -} - -class GrammerNewLine extends Grammer { - constructor(number = 1) { - super(); - this.number = number; - } -} - -class GrammerSymbol extends Grammer { - constructor(symbol) { - super(); - this.symbol = symbol; - this.eol = false; - this.newLine = false; - } -} - -class PropItem extends Item { - constructor() { - super(); - this.modify = []; // Modify - this.name = ''; - this.type = ''; // TypeItem - this.value = null; - this.notes = []; // [{key:'name', value:'test', type:'string'}, {key:'length', value:10, type:'number'}] - } - - addModify(modify) { - this.modify.push(modify); - return this; - } - - addNote(note) { - this.notes.push(note); - return this; - } -} - -class NoteItem extends Item { - constructor(key, value) { - super(); - const typeMap = ['number', 'string', 'boolean']; - let type = typeof value; - if (value === null || value === 'null') { - type = 'null'; - } else if (typeMap.indexOf(type) === -1) { - throw new Error(`Not suppoted type : ${type} [${typeMap.toString()}]`); - } - this.key = key; - this.value = value; - this.type = type; - } -} - -class FuncItem extends Item { - constructor() { - super(); - this.name = ''; - this.modify = []; // Modify - this.params = []; // param - this.throws = []; // Exception name - this.return = []; // GrammerReturn - this.annotations = []; // AnnotationItem - this.body = []; // grammer - } - - addBodyNode(node) { - assert.strictEqual(true, node instanceof Grammer); - this.body.push(node); - return this; - } - - addAnnotation(node) { - assert.strictEqual(true, node instanceof AnnotationItem); - this.annotations.push(node); - } -} - -class ConstructItem extends Item { - constructor(params = [], body = [], annotations = []) { - super(); - this.params = params; - this.body = body; - this.annotations = annotations; - this.throws = []; - } - - addParamNode(node) { - assert.strictEqual(true, node instanceof Grammer); - this.params.push(node); - } - - addBodyNode(node) { - assert.strictEqual(true, node instanceof Grammer); - this.body.push(node); - } - - addAnnotation(node) { - assert.strictEqual(true, node instanceof AnnotationItem); - this.annotations.push(node); - } -} - -class ObjectItem extends Item { - constructor(type) { - super(); - assert.strictEqual(true, type === 'client' || type === 'model' || type === 'test'); - this.type = type; // client | model - this.modify = []; // Modify - this.name = ''; // object name - this.extends = []; // object extends - this.body = []; // PropItem | FuncItem | ConstructItem ... - this.annotations = []; // AnnotationItem - this.topAnnotation = []; // AnnotationItem - this.subObject = []; // ObjectItem - this.includeList = []; - this.includeModelList = []; - } - - addBodyNode(node) { - if (!(node instanceof PropItem || node instanceof FuncItem || node instanceof ObjectItem || node instanceof AnnotationItem || node instanceof ConstructItem)) { - throw new Error('Only suppoted PropItem | FuncItem | ObjectItem | AnnotationItem | ConstructItem'); - } - this.body.push(node); - } - - addModify(modify) { - this.modify.push(modify); - return this; - } - - addExtends(extend) { - this.extends.push(extend); - return this; - } -} - -class Behavior extends Grammer { - constructor() { - super(); - this.name = ''; - this.eol = false; - this.newLine = false; - } -} - -class BehaviorTimeNow extends Behavior { - constructor() { - super(); - this.name = 'behaviorTimeNow'; - } -} - -class BehaviorSetMapItem extends Behavior { - constructor(call = null, key = '', value = null) { - super(); - this.name = 'behaviorSetMapItem'; - assert.strictEqual(true, call instanceof GrammerCall); - this.call = call; - this.key = key; - this.value = value; - } -} - -class BehaviorDoAction extends Behavior { - constructor(responseVar = null, params = [], callbackBody = []) { - super(); - this.name = 'behaviorDoAction'; - this.var = responseVar; - this.params = params; - this.body = callbackBody; - } - addBodyNode(node) { - this.body.push(node); - } -} - -class BehaviorRetry extends Behavior { - constructor() { - super(); - this.name = 'behaviorRetry'; - } -} - -class BehaviorToModel extends Behavior { - constructor(grammer, expected) { - super(); - this.name = 'behaviorToModel'; - this.grammer = grammer; - this.expected = expected; - } -} - -class BehaviorToMap extends Behavior { - constructor(grammer, inferred) { - super(); - this.name = 'behaviorToMap'; - this.grammer = grammer; - this.inferred = inferred; - } -} - -class BehaviorTamplateString extends Behavior { - constructor(items = []) { - super(); - this.name = 'behaviorTamplateString'; - this.items = items; - } - - addItem(item) { - this.items.push(item); - } -} - -module.exports = { - TypeStream, - TypeObject, - - TypeGeneric, - TypeDecimal, - TypeInteger, - TypeString, - TypeNumber, - TypeArray, - TypeBytes, - TypeTree, - TypeBool, - TypeBase, - TypeItem, - TypeVoid, - TypeNull, - TypeMap, - - Counter, - - AnnotationItem, - ConstructItem, - ObjectItem, - FuncItem, - PropItem, - NoteItem, - - Grammer, - GrammerVar, - GrammerCall, - GrammerExpr, - GrammerLoop, - GrammerBreak, - GrammerCatch, - GrammerValue, - GrammerSymbol, - GrammerReturn, - GrammerThrows, - GrammerNewLine, - GrammerFinally, - GrammerContinue, - GrammerTryCatch, - GrammerNewObject, - GrammerCondition, - GrammerException, - - Behavior, - BehaviorToMap, - BehaviorRetry, - BehaviorTimeNow, - BehaviorToModel, - BehaviorDoAction, - BehaviorSetMapItem, - BehaviorTamplateString -}; diff --git a/src/langs/common/package_info.js b/src/langs/common/package_info.js deleted file mode 100644 index a5057f7..0000000 --- a/src/langs/common/package_info.js +++ /dev/null @@ -1,52 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const path = require('path'); -const debug = require('../../lib/debug'); -const { _render } = require('../../lib/helper'); - -class BasePackageInfo { - constructor(config, dependencies) { - this.config = config; - this.dependencies = dependencies; - this.outputDir = ''; - } - - renderAuto(templatePath, targetPath, params = {}) { - let content = fs.readFileSync(templatePath, 'utf-8'); - this.renderContent(content, targetPath, params); - } - - renderContent(templateContent, targetPath, params = {}) { - let content = _render(templateContent, params); - if (!fs.existsSync(path.dirname(targetPath))) { - fs.mkdirSync(path.dirname(targetPath), { - recursive: true - }); - } - fs.writeFileSync(targetPath, content); - } - - resolveOutputDir(packageInfo, append = '../') { - let outputDir = path.join(this.config.dir, append); - if (packageInfo.outputDir) { - outputDir = path.join(outputDir, packageInfo.outputDir); - } - if (!fs.existsSync(outputDir)) { - fs.mkdirSync(outputDir, { - recursive: true - }); - } - return outputDir; - } - - checkParams(packageInfo, validateParam = []) { - validateParam.forEach(key => { - if (typeof packageInfo[key] === 'undefined') { - debug.stack('need config packageInfo.' + key, packageInfo); - } - }); - } -} - -module.exports = BasePackageInfo; diff --git a/src/langs/php/combinator.js b/src/langs/php/combinator.js deleted file mode 100644 index e7bf374..0000000 --- a/src/langs/php/combinator.js +++ /dev/null @@ -1,1265 +0,0 @@ -'use strict'; - -const assert = require('assert'); -const debug = require('../../lib/debug'); -const CombinatorBase = require('../common/combinator'); -const Emitter = require('../../lib/emitter'); -const PackageInfo = require('./package_info'); -const modules = require('./modules'); - -const { - Symbol, - Modify -} = require('../common/enum'); - -const { - BehaviorToMap, - - AnnotationItem, - ConstructItem, - ObjectItem, - FuncItem, - PropItem, - - // GrammerVar, - Grammer, - GrammerCall, - GrammerCatch, - GrammerValue, - TypeStream, - TypeObject, - - TypeGeneric, - TypeDecimal, - TypeInteger, - TypeString, - TypeNumber, - TypeArray, - TypeBytes, - TypeBool, - TypeItem, - TypeVoid, - TypeNull, - TypeBase, - TypeMap, -} = require('../common/items'); - -const { - _symbol, - _modify, - _deepClone, - _upperFirst, - _isKeywords, - _avoidKeywords, - _resolveGrammerCall -} = require('../../lib/helper'); - -function _name(str) { - if (str.indexOf('-') > -1) { - let tmp = str.split('-'); - tmp.map((s, i) => { - if (i !== 0) { - return s; - } - return s; - }); - str = tmp.join(''); - } - return str; -} - -class Combinator extends CombinatorBase { - constructor(config, dependencies) { - super(config, dependencies); - this.eol = ';'; - this.classNameMap = {}; - } - - addInclude(className) { - let realFullClassName = ''; - let last = ''; - const dependencies = this.dependencies; - if (className.indexOf('$') > -1) { - realFullClassName = this.coreClass(className); - } else if (dependencies[className]) { - const package_name = dependencies[className].package_name; - const client_name = dependencies[className].client_name; - // is third package - realFullClassName = `\\${package_name.split('.').join('\\')}\\${client_name}`; - if (dependencies[className].client_alias) { - last = dependencies[className].client_alias.split('->').join(''); - } - } else if (this.config.baseClient && this.config.baseClient === className) { - realFullClassName = `\\${className.split('.').join('\\')}`; - } else { - debug.stack(`Class Name Error : ${className}`, dependencies); - } - - // avoid keywords - realFullClassName = realFullClassName.split('\\').map(m => { - return _avoidKeywords(m); - }).join('\\'); - - if (!last) { - let tmp = realFullClassName.split('\\'); - last = tmp[tmp.length - 1]; - } - let lower = last.toLowerCase(); - if (this.classNameMap[lower]) { - if (this.classNameMap[lower] !== realFullClassName) { - // return full class name if already have same name class - return realFullClassName; - } - return last; - } - - this.classNameMap[lower] = realFullClassName; - if (this.dependencies[className]) { - // has alias - this.includeList.push({ import: realFullClassName, alias: this.dependencies[className].client_alias }); - } else { - this.includeList.push({ import: realFullClassName, alias: null }); - } - - return last; - } - - addModelInclude(modelName, useFull = false) { - let realFullClassName = ''; - let accessPath = modelName.split('.'); - const dependencies = this.dependencies; - if (modelName.indexOf('$') > -1) { - realFullClassName = this.coreClass(modelName); - } else if (accessPath.length > 1 && dependencies[accessPath[0]]) { - const info = dependencies[accessPath[0]]; - // is third package model - realFullClassName = `\\${info.package_name.split('.').join('\\')}\\${info.model_dir}\\${accessPath.slice(1).join('\\')}`; - } else { - // is not third package model - realFullClassName = `\\${this.config.package.split('.').join('\\')}\\${this.config.model.dir}\\${accessPath.join('\\')}`; - } - - // avoid keywords - let realFullClassNameArr = realFullClassName.split('\\'); - realFullClassName = realFullClassNameArr.map((m, i) => { - if (i === realFullClassNameArr.length - 1 && m.toLowerCase() === 'model') { - // If the model class name is 'model' - // add the '_' suffix. - return m + '_'; - } - return _avoidKeywords(m); - }).join('\\'); - - if (useFull) { - return realFullClassName; - } - - let tmp = realFullClassName.split('\\'); - let last = tmp[tmp.length - 1]; - let lower = last.toLowerCase(); - if (this.classNameMap[lower]) { - if (this.classNameMap[lower] !== realFullClassName) { - // return full class name if already have same name class - return realFullClassName; - } - return last; - } - this.classNameMap[lower] = realFullClassName; - this.includeModelList.push({ import: realFullClassName, alias: null }); - return last; - } - - addTypedefInclude(typeName) { - let accessPath = typeName.split('.'); - let importName = ''; - let fromName = ''; - let typedefModule = {}; - if (accessPath.length === 2) { - if (this.dependencies[accessPath[0]] - && this.dependencies[accessPath[0]].typedef - && this.dependencies[accessPath[0]].typedef[accessPath[1]]) { - typedefModule = this.dependencies[accessPath[0]].typedef[accessPath[1]]; - } - } else if (accessPath.length === 1 && this.typedef[accessPath[0]]) { - typedefModule = this.typedef[accessPath[0]]; - } - if (typedefModule.import || typedefModule.package) { - if (typedefModule.import) { - fromName = typedefModule.import; - } - if (typedefModule.type) { - importName = typedefModule.type; - } - } - - let existResult = this.includeList.some(item => item.import === importName && item.from === fromName); - if (!existResult) { - this.includeList.push({ - import: fromName && importName ? `${fromName}\\${importName}` : fromName ? fromName : importName ? importName : null, - alias: null, - }); - } - return typedefModule.type || typeName; - } - - combine(objectArr = []) { - if (this.config.packageInfo) { - const packageInfo = new PackageInfo(this.config, this.dependencies); - packageInfo.emit(); - } - - const [clientObjectItem] = objectArr.filter(obj => obj.type === 'client'); - this.combineOject(clientObjectItem); - - const models = objectArr.filter(obj => obj.type === 'model'); - if (models.length > 0) { - const self = this; - models.forEach(modelObjectItem => { - self.combineOject(modelObjectItem); - if (modelObjectItem.subObject && modelObjectItem.subObject.length > 0) { - modelObjectItem.subObject.forEach(subModelObjectItem => { - self.combineOject(subModelObjectItem); - }); - } - }); - } - - if (this.config.withTest) { - const object = new ObjectItem('test'); - object.name = `Tests.${clientObjectItem.name}Test`; - object.extends = ['TestCase']; - object.includeList = [{ import: 'PHPUnit\\Framework\\TestCase', alias: null }]; - clientObjectItem.body.forEach(node => { - if (node instanceof FuncItem) { - const func = new FuncItem(); - func.name = `test${_upperFirst(node.name)}`; - func.modify.push(Modify.public()); - object.addBodyNode(func); - } - }); - const outputParts = this.combineOject(object, false); - const config = _deepClone(this.config); - config.filename = `${clientObjectItem.name}Test`; - config.dir = `${config.dir}/tests/`; - config.layer = ''; - this.combineOutputParts(config, outputParts); - } - } - - combineOject(object, output = true) { - let layer = ''; - if (object.type === 'model') { - layer = this.config.model.dir; - } - this.includeList = object.includeList; - this.includeModelList = object.includeModelList; - this.classNameMap = {}; - - let emitter, outputParts = { head: '', body: '', foot: '' }; - if (object.type === 'model' && (object.name.endsWith('.model') || object.name === 'model')) { - object.name = object.name + '_'; - } - /******************************** emit body ********************************/ - emitter = new Emitter(this.config); - if (object.name.indexOf('.') > -1) { - // reset layer&filename if object is sub model - let tmp = object.name.split('.'); - object.name = tmp[tmp.length - 1]; - tmp.splice(tmp.length - 1, 1); - layer = layer ? layer + '.' + tmp.join('.') : tmp.join('.'); - } - const currClassName = this.emitClass(emitter, object); - outputParts.body = emitter.output; - - /******************************** emit head ********************************/ - emitter = new Emitter(this.config); - emitter.emitln(' 0) { - this.emitAnnotations(emitter, object.topAnnotation); - } - - let appendNamespace = ''; - if (layer) { - appendNamespace = '\\' + layer.split('.').map(m => { - return _avoidKeywords(m); - }).join('\\'); - } - emitter.emitln(`namespace ${this.config.package.split('.').join('\\')}${appendNamespace};`).emitln(); - this.emitInclude(emitter); - outputParts.head = emitter.output; - - /***************************** combine output ******************************/ - if (output) { - const config = _deepClone(this.config); - config.filename = _avoidKeywords(object.name); - config.layer = layer.split('.').map(m => { - return _avoidKeywords(m); - }).join('.'); - if (config.packageInfo) { - config.dir = config.outputDir + '/src/'; - } - if (object.type === 'client' && config.exec) { - emitter = new Emitter(this.config); - emitter.emitln('$path = __DIR__ . \\DIRECTORY_SEPARATOR . \'..\' . \\DIRECTORY_SEPARATOR . \'vendor\' . \\DIRECTORY_SEPARATOR . \'autoload.php\';', this.level); - emitter.emitln('if (file_exists($path)) {', this.level); - this.levelUp(); - emitter.emitln('require_once $path;', this.level); - this.levelDown(); - emitter.emitln('}', this.level); - emitter.emitln(`${currClassName}::main(array_slice($argv, 1));`, this.level); - outputParts.foot = emitter.output; - } - this.combineOutputParts(config, outputParts); - } - return outputParts; - } - - emitType(type, onComment = false) { - if (!(type instanceof TypeItem)) { - debug.stack('Inavalid type', type); - } - if (type instanceof TypeString) { - return 'string'; - } else if (type instanceof TypeBytes || type instanceof TypeArray || type instanceof TypeMap) { - if (onComment) { - if (type instanceof TypeBytes) { - return 'int[]'; - } else if (type instanceof TypeMap) { - let subType = this.emitType(type.valType, onComment); - return `${subType}[]`; - } - let itemType = this.emitType(type.itemType, onComment); - return `${itemType}[]`; - } - return 'array'; - } else if (type instanceof TypeObject) { - return this.resolveName(type.objectName); - } else if (type instanceof TypeStream) { - return this.addInclude('$Stream'); - } else if (type instanceof TypeGeneric) { - if (onComment) { - return 'mixed'; - } - return 'any'; - } else if (type instanceof TypeDecimal) { - return 'float'; - } else if (type instanceof TypeInteger) { - return 'int'; - } else if (type instanceof TypeNumber) { - return 'int'; - } else if (type instanceof TypeBool) { - return 'bool'; - } else if (type instanceof TypeVoid) { - return 'void'; - } else if (type instanceof TypeNull) { - return 'null'; - } - debug.stack(type); - } - - emitClass(emitter, object) { - var parent = ''; - if (object.extends.length > 0) { - let tmp = []; - if (!(object.extends instanceof Array)) { - object.extends = [object.extends]; - } - object.extends.forEach(baseClass => { - tmp.push(this.resolveName(baseClass)); - }); - parent = 'extends ' + tmp.join(', ') + ' '; - } - let className = object.name; - if (object.type === 'client') { - className = this.config.client.name; - this.config.filename = className; - } - className = _avoidKeywords(className); - if (object.annotations.length > 0) { - this.emitAnnotations(emitter, object.annotations); - } - if (_isKeywords(className)) { - this.config.filename = className; - } - this.classNameMap[className.toLowerCase()] = className; - emitter.emitln(`class ${className} ${parent}{`, this.level); - this.levelUp(); - const notes = this.resolveNotes(object.body); - if (Object.keys(notes).length > 0) { - this.emitNotes(emitter, notes); - } - - if (object.type === 'model') { - this.emitValidate(emitter, notes); - let props = object.body.filter(node => node instanceof PropItem); - this.emitToMap(emitter, props, notes); - this.emitFromMap(emitter, className, props, notes); - } - - // emit body nodes : PropItem | FuncItem | ConstructItem | AnnotationItem - object.body.forEach(node => { - if (node instanceof PropItem) { - this.emitProp(emitter, node); - } else if (node instanceof FuncItem) { - this.emitFunc(emitter, node); - } else if (node instanceof ConstructItem) { - this.emitConstruct(emitter, node, parent); - } else if (node instanceof AnnotationItem) { - this.emitAnnotation(emitter, node); - } else { - debug.stack(node); - } - }); - this.levelDown(); - emitter.emitln('}', this.level); - return className; - } - - emitValidate(emitter, notes) { - let validateNoteKeys = [ - 'required', - 'maximum', - 'minimum', - 'maxLength', - 'minLength', - // 'format', - // 'enum', - 'pattern', - // 'maxItems' - ]; - let noteKeys = Object.keys(notes).filter(key => { - return validateNoteKeys.indexOf(key) > -1 && notes[key].length > 0; - }); - if (noteKeys.length > 0) { - emitter.emitln('public function validate() {', this.level); - this.levelUp(); - noteKeys.forEach((key) => { - notes[key].forEach(note => { - let val = note.value; - if (note.type === 'string') { - val = `'${val}'`; - } - emitter.emitln(`Model::validate${_upperFirst(note.key)}('${note.prop}', $this->${note.prop}, ${val});`, this.level); - }); - }); - this.levelDown(); - emitter.emitln('}', this.level); - } else { - emitter.emitln('public function validate() {}', this.level); - } - } - - emitToMap(emitter, props, notes) { - let nameMap = {}; - if (notes['name']) { - notes['name'].forEach(note => { - if (note.prop !== note.value) { - nameMap[note.prop] = note.value; - } - }); - } - emitter.emitln('public function toMap() {', this.level); - this.levelUp(); - emitter.emitln('$res = [];', this.level); - props.forEach(prop => { - let name = typeof nameMap[prop.name] !== 'undefined' ? nameMap[prop.name] : prop.name; - emitter.emitln(`if (null !== $this->${prop.name}) {`, this.level); - this.levelUp(); - if (prop.type instanceof TypeArray && !(prop.type instanceof TypeBytes)) { - if (prop.type.itemType instanceof TypeBase) { - emitter.emitln(`$res['${name}'] = $this->${prop.name};`, this.level); - } else { - emitter.emitln(`$res['${name}'] = [];`, this.level); - emitter.emitln(`if(null !== $this->${prop.name} && is_array($this->${prop.name})){`, this.level); - this.levelUp(); - emitter.emitln('$n = 0;', this.level); - emitter.emitln(`foreach($this->${prop.name} as $item){`, this.level); - this.levelUp(); - emitter.emitln(`$res['${name}'][$n++] = null !== $item ? $item->toMap() : $item;`, this.level); - this.levelDown(); - emitter.emitln('}', this.level); - this.levelDown(); - emitter.emitln('}', this.level); - } - } else if (prop.type instanceof TypeMap) { - if (prop.type.valType instanceof TypeBase) { - emitter.emitln(`$res['${name}'] = $this->${prop.name};`, this.level); - } else { - emitter.emitln(`$res['${name}'] = [];`, this.level); - emitter.emitln(`if(null !== $this->${prop.name} && is_array($this->${prop.name})){`, this.level); - this.levelUp(); - emitter.emitln(`foreach($this->${prop.name} as $key => $val){`, this.level); - this.levelUp(); - emitter.emitln(`$res['${name}'][$key] = null !== $val ? $val->toMap() : $val;`, this.level); - this.levelDown(); - emitter.emitln('}', this.level); - this.levelDown(); - emitter.emitln('}', this.level); - } - } else if (prop.type instanceof TypeBase || prop.type instanceof TypeBytes || prop.type instanceof TypeStream) { - emitter.emitln(`$res['${name}'] = $this->${prop.name};`, this.level); - } else { - if (prop.type.objectName.indexOf('%') === 0) { - emitter.emitln(`$res['${name}'] = $this->${prop.name};`, this.level); - } else { - emitter.emitln(`$res['${name}'] = null !== $this->${prop.name} ? $this->${prop.name}->toMap() : null;`, this.level); - } - } - this.levelDown(); - emitter.emitln('}', this.level); - }); - emitter.emitln('return $res;', this.level); - this.levelDown(); - emitter.emitln('}', this.level); - } - - emitFromMap(emitter, modelName, props, notes) { - let nameMap = {}; - if (notes['name']) { - notes['name'].forEach(note => { - if (note.prop !== note.value) { - nameMap[note.prop] = note.value; - } - }); - } - let annotation = new AnnotationItem(0, 'multi'); - annotation.content = []; - annotation.content.push('@param array $map'); - annotation.content.push(`@return ${modelName}`); - this.emitAnnotation(emitter, annotation); - emitter.emitln('public static function fromMap($map = []) {', this.level); - this.levelUp(); - emitter.emitln('$model = new self();', this.level); - props.forEach(prop => { - let name = typeof nameMap[prop.name] !== 'undefined' ? nameMap[prop.name] : prop.name; - let mapVal = `$map['${name}']`; - emitter.emitln(`if(isset(${mapVal})){`, this.level); - this.levelUp(); - if (prop.type instanceof TypeArray && !(prop.type instanceof TypeBytes)) { - emitter.emitln(`if(!empty(${mapVal})){`, this.level); - this.levelUp(); - if (prop.type.itemType instanceof TypeBase) { - emitter.emitln(`$model->${prop.name} = ${mapVal};`, this.level); - } else if (prop.type.itemType instanceof TypeObject) { - emitter.emitln(`$model->${prop.name} = [];`, this.level); - emitter.emitln('$n = 0;', this.level); - emitter.emitln(`foreach(${mapVal} as $item) {`, this.level); - this.levelUp(); - emitter.emitln(`$model->${prop.name}[$n++] = null !== $item ? ${this.resolveName(prop.type.itemType.objectName)}::fromMap($item) : $item;`, this.level); - this.levelDown(); - emitter.emitln('}', this.level); - } else { - debug.stack('Unsupported', prop.type); - } - this.levelDown(); - emitter.emitln('}', this.level); - } else if (prop.type instanceof TypeObject && prop.type.objectName.indexOf('%') !== 0) { - emitter.emitln(`$model->${prop.name} = ${this.resolveName(prop.type.objectName)}::fromMap(${mapVal});`, this.level); - } else { - emitter.emitln(`$model->${prop.name} = ${mapVal};`, this.level); - } - this.levelDown(); - emitter.emitln('}', this.level); - }); - emitter.emitln('return $model;', this.level); - this.levelDown(); - emitter.emitln('}', this.level); - } - - emitNotes(emitter, notes) { - let descNoteKeys = [ - 'name', - 'default', - ]; - Object.keys(notes).forEach((key) => { - if (descNoteKeys.indexOf(key) > -1 && notes[key].length > 0) { - emitter.emitln(`protected $_${key.split('-').join('')} = [`, this.level); - this.levelUp(); - notes[key].forEach(note => { - if (note.key === key) { - let val = note.value; - if (note.type === 'string') { - val = `'${val}'`; - } - emitter.emitln(`'${note.prop}' => ${val},`, this.level); - } - }); - this.levelDown(); - emitter.emitln('];', this.level); - } - }); - } - - emitConstruct(emitter, construct, parent) { - let constructParams = []; - // let parentConstructParams = []; - if (construct.annotations) { - this.emitAnnotations(emitter, construct.annotations); - } - if (construct.params.length > 0) { - construct.params.forEach(param => { - if (param.value !== null && param.value !== 'null') { - constructParams.push(`$${param.key} = ${param.value}`); - } else { - constructParams.push(`$${param.key}`); - } - }); - emitter.emit('public function __construct(', this.level); - emitter.emit(constructParams.join(', ')); - emitter.emitln('){'); - this.levelUp(); - - construct.body.forEach(gram => { - this.grammer(emitter, gram); - }); - this.levelDown(); - emitter.emitln('}', this.level); - } else if (construct.body.length > 0) { - emitter.emitln('public function __construct(){', this.level); - this.levelUp(); - construct.body.forEach(gram => { - this.grammer(emitter, gram); - }); - this.levelDown(); - emitter.emitln('}', this.level); - } - } - - emitAnnotation(emitter, annotation, level) { - if (typeof level === 'undefined') { - level = this.level; - } - if (annotation.mode === 'single') { - emitter.emitln(`// ${annotation.content}`, level); - } else if (annotation.mode === 'multi') { - emitter.emitln('/**', level); - annotation.content.forEach(c => { - emitter.emitln(` * ${c.split('*/').join('*\\/')}`, level); - }); - emitter.emitln(' */', level); - } else { - debug.stack('Unsupported annotation.mode :' + annotation.mode, annotation); - } - } - - emitFunc(emitter, func) { - emitter.emitln(); - this.emitFuncComment(emitter, func); - emitter.emit(`${_modify(func.modify)} function ${_avoidKeywords(func.name)}(`, this.level); - if (func.params.length > 0) { - let params = []; - func.params.forEach(p => { - params.push(`$${p.key}`); - }); - emitter.emit(params.join(', ')); - } - emitter.emitln('){'); - this.levelUp(); - func.body.forEach(gram => { - this.grammer(emitter, gram); - }); - this.levelDown(); - emitter.emitln('}', this.level); - } - - emitFuncComment(emitter, func) { - emitter.emitln('/**', this.level); - const commentTag = ['@param', '@return', '@throws']; - const paramDesc = {}; - let returnDesc = ''; - if (func.annotations.length > 0) { - func.annotations.forEach(annotation => { - if (annotation.mode === 'multi') { - annotation.content.forEach(c => { - let tagIndex = null; - c.split(' ').forEach((item, index) => { - if (commentTag.indexOf(item) > -1) { - tagIndex = index; - } - }); - if (tagIndex !== null) { - let tmp = c.split(' '); - let paramName = ''; - if (tmp[tagIndex] === '@param') { - paramName = tmp[tagIndex + 1]; - tmp = tmp.slice(tagIndex + 2); - paramDesc[paramName] = tmp.join(' '); - } else if (tmp[tagIndex] === '@return') { - if (typeof tmp[tagIndex + 1] !== 'undefined') { - returnDesc = tmp.slice(tagIndex + 1).join(' '); - } - } - } else { - emitter.emitln(` * ${c}`, this.level); - } - }); - } else { - emitter.emitln(` * ${annotation.content}`, this.level); - } - }); - } - func.params.forEach(p => { - let t = this.emitType(p.type, true); - const desc = paramDesc[p.key] ? ' ' + paramDesc[p.key] : ''; - if (t === 'any') { - t = 'mixed'; - } - emitter.emitln(` * @param ${t} $${p.key}${desc}`, this.level); - }); - if (func.return) { - if (func.return.length > 0) { - let t = ''; - if (func.return.length === 1) { - t = this.emitType(func.return[0]); - } else { - let tmp = []; - func.return.forEach(r => { - tmp.push(r.type); - }); - t = tmp.join('|'); - } - if (t.indexOf('object') > -1) { - t += '|array'; - } - const desc = returnDesc ? ' ' + returnDesc : ''; - emitter.emitln(` * @return ${t}${desc}`, this.level); - } - if (func.throws.length) { - func.throws.forEach(exception => { - emitter.emitln(' * @throws ' + this.emitType(exception), this.level); - }); - } - } - emitter.emitln(' */', this.level); - } - - emitProp(emitter, prop) { - let annotationsNoteKeys = [ - 'description', - 'example', - ]; - - if (prop.notes.length > 0) { - let annotation = new AnnotationItem(prop.index, 'multi'); - annotation.content = []; - prop.notes.forEach(note => { - if (annotationsNoteKeys.indexOf(note.key) > -1) { - annotation.content.push(`@${note.key} ${note.value}`); - } else if (note.key === 'deprecated' && note.value === 'true') { - annotation.content.push('@deprecated'); - } - }); - annotation.content.push(`@var ${this.emitType(prop.type, true)}`); - this.emitAnnotation(emitter, annotation); - } - emitter.emitln(`${_modify(prop.modify)} $${_name(prop.name)};`, this.level).emitln(); - } - - emitInclude(emitter) { - let emitSet = []; - this.includeList.forEach(include => { - let importClass; - if (include.import === this.config.tea.exception.name) { - importClass = include.import; - } else if (include.import) { - importClass = include.import.split('\\').filter(str => str.length > 0).join('\\'); - } - if (importClass) { - let emitContent = include.alias ? `use ${importClass} as ${include.alias.split('->').join('')};` : `use ${importClass};`; - if (emitSet.indexOf(emitContent) === -1) { - emitter.emitln(emitContent); - emitSet.push(emitContent); - } - } - }); - if (this.includeList.length) { - emitter.emitln(); - } - this.includeModelList.forEach(include => { - const importClass = include.import.split('\\').filter(str => str.length > 0).join('\\'); - if (importClass) { - let emitContent = include.alias ? `use ${importClass} as ${include.alias};` : `use ${importClass};`; - if (emitSet.indexOf(emitContent) === -1) { - emitter.emitln(emitContent); - emitSet.push(emitContent); - } - } - }); - if (this.includeModelList.length) { - emitter.emitln(); - } - } - - grammerCall(emitter, gram) { - if (gram.type === 'sys_func' || gram.type === 'method') { - const resolve_method = _resolveGrammerCall(gram, this.dependencies); - if (resolve_method !== null) { - if (!modules[resolve_method]) { - debug.stack(`Unsupported method : ${resolve_method}`); - } - modules[resolve_method].call(this, emitter, gram); - return; - } - } - // path : 'parent', 'object', 'object_static', 'call', 'call_static', 'prop', 'prop_static', 'map', 'list' - var pre = ''; - let params = ''; - if (gram.params.length > 0) { - let tmp = []; - gram.params.forEach(p => { - let emit = new Emitter(); - if (p.value instanceof BehaviorToMap && gram.type === 'sys_func' && gram.path[1].name === 'isUnset') { - this.grammer(emit, p.value.grammer, false, false); - } else { - this.grammer(emit, p, false, false); - } - tmp.push(emit.output); - }); - params = tmp.join(', '); - } - let last_path; - if (gram.type === 'super') { - pre = `parent::__construct(${params})`; - } else { - gram.path.forEach((path, i) => { - let pathName = this.resolveName(path.name); - if (path.type === 'parent') { - if (gram.path[i + 1] && gram.path[i + 1].type.indexOf('static') > -1) { - pre += 'self'; - if (path.name) { - pre += '::' + pathName; - } - } else { - pre += '$this'; - if (path.name) { - pre += '->' + pathName; - } - } - } else if (path.type === 'object') { - if (path.name.indexOf('@') === 0 && pre === '') { - pre += `$this->${pathName}`; - } else { - pre += `$${pathName}`; - } - } else if (path.type === 'object_static') { - pre += `${pathName}`; - } else if (path.type === 'call') { - pre += `->${pathName}(${params})`; - } else if (path.type === 'call_static') { - pre += `::${pathName}(${params})`; - } else if (path.type === 'prop') { - pre += `->${pathName}`; - } else if (path.type === 'prop_static') { - pre += `::${pathName}`; - } else if (path.type === 'map') { - if (path.isVar) { - pre += `[$${pathName}]`; - } else if (path.name instanceof Grammer) { - pre += `[${pathName}]`; - } else { - pre += `["${pathName}"]`; - } - } else if (path.type === 'list') { - if (path.name instanceof Grammer) { - pre += `[${pathName}]`; - } else if (path.isVar) { - pre += `[$${pathName}]`; - } else { - pre += `[${pathName}]`; - } - } else { - debug.stack(gram); - } - last_path = path; - }); - } - - if (pre[0] === '-' || pre[0] === ':') { - pre = pre.slice(2); - } - if (last_path && (last_path.type === 'map' || last_path.type === 'list')) { - pre = '@' + pre; - } - emitter.emit(pre); - } - - grammerExpr(emitter, gram) { - if (!gram.left && !gram.right) { - emitter.emit(` ${_symbol(gram.opt)} `); - return; - } - this.grammer(emitter, gram.left, false, false); - emitter.emit(` ${_symbol(gram.opt)} `); - this.grammer(emitter, gram.right, false, false); - } - - grammerVar(emitter, gram) { - if (gram.varType === 'static_class') { - const name = gram.name ? gram.name : gram.key; - emitter.emit(`${this.resolveName(name)}::class`); - } else if (gram.varType === 'var' || gram.varType === 'const') { - const name = gram.name ? gram.name : gram.key; - emitter.emit(`$${this.resolveName(name, false)}`); - } else { - debug.stack(gram); - } - } - - grammerValue(emitter, gram) { - if (gram instanceof AnnotationItem) { - this.emitAnnotation(emitter, gram); - return; - } - const emitMap = function (emitter, values) { - if (values.length > 0) { - emitter.emitln('[', this.levevl); - this.levelUp(); - values.forEach((item, i) => { - if (item instanceof AnnotationItem) { - this.grammer(emitter, item); - return; - } - emitter.emit(`"${item.key}" => `, this.level); - this.grammerValue(emitter, item, false, false); - if (i < values.length - 1) { - emitter.emitln(','); - } else { - emitter.emitln(); - } - }); - this.levelDown(); - emitter.emit(']', this.level); - } else { - emitter.emit('[]'); - } - }; - if (gram.type === 'map' || gram.type === 'model_construct_params') { - if (gram.needCast) { - let expandParams = gram.value.filter((item) => { - return item.isExpand !== true; - }); - let notExpandParams = gram.value.filter((item) => { - return item.isExpand === true; - }); - emitter.emit(`${this.addInclude('$Core')}::${this.config.tea.core.merge}(`); - if (expandParams.length) { - emitMap.call(this, emitter, expandParams); - emitter.emit(', '); - } - for (let i = 0; i < notExpandParams.length; i++) { - let v = notExpandParams[i]; - if (v instanceof AnnotationItem) { - this.emitAnnotation(emitter, v, 0); - continue; - } - this.levelUp(); - this.grammerValue(emitter, v); - this.levelDown(); - if (i < notExpandParams.length - 1) { - emitter.emit(', '); - } - } - emitter.emit(')'); - } else { - emitMap.call(this, emitter, gram.value); - } - } else if (gram.type === 'string') { - let str = gram.value.split('\\"').map(str => str.split('"').join('\\"')).join('\\"'); - emitter.emit(`"${str.split('$').join('\\$')}"`); - } else if (gram.type === 'null') { - emitter.emit('null'); - } else if (gram.type === 'behavior' || gram.type === 'call' - || gram.type === 'var' || gram.type === 'instance') { - this.grammer(emitter, gram.value, false, false); - } else if (gram.type === 'number' || gram.type === 'bool') { - emitter.emit(gram.value); - } else if (gram.type === 'param') { - emitter.emit(`$${gram.value}`); - } else if (gram.type === 'expr') { - if (Array.isArray(gram.value)) { - gram.value.forEach(gramItem => { - this.grammer(emitter, gramItem, false, false); - }); - } else { - this.grammer(emitter, gram.value, false, false); - } - } else if (gram.type === 'array') { - if (gram.value.length) { - emitter.emitln('[', this.levevl); - this.levelUp(); - gram.value.forEach((item, i) => { - if (item instanceof AnnotationItem) { - this.grammer(emitter, item); - return; - } - emitter.emit('', this.level); - this.grammerValue(emitter, item, false, false); - if (i < gram.value.length - 1) { - emitter.emitln(','); - } else { - emitter.emitln(); - } - }); - this.levelDown(); - emitter.emit(']', this.level); - } else { - emitter.emit('[]'); - } - } else if (gram.type === 'not') { - emitter.emit(_symbol(Symbol.reverse())); - this.grammerValue(emitter, gram.value); - } else { - debug.stack('Unsupported GrammerValue type', gram); - } - } - - grammerLoop(emitter, gram) { - if (gram.type === 'foreach') { - emitter.emit('foreach('); - this.grammer(emitter, gram.source, false, false); - emitter.emit(' as '); - this.grammerVar(emitter, gram.item, false, false); - emitter.emitln('){'); - } - this.levelUp(); - gram.body.forEach(node => { - this.grammer(emitter, node); - }); - this.levelDown(); - emitter.emitln('}', this.level); - } - - grammerBreak(emitter, gram) { - emitter.emit('break'); - } - - grammerCondition(emitter, gram) { - if (gram.type === 'elseif') { - emitter.emit('else if'); - } else { - emitter.emit(`${gram.type}`); - } - - if (gram.type !== 'else') { - emitter.emit(' ('); - let emit = new Emitter(this.config); - gram.conditionBody.forEach(condition => { - this.grammer(emitter, condition, false, false); - }); - emitter.emit(`${emit.output})`); - } - - if (gram.body.length) { - emitter.emitln(' {'); - this.levelUp(); - gram.body.forEach(node => { - this.grammer(emitter, node); - }); - this.levelDown(); - emitter.emitln('}', this.level); - } else { - emitter.emitln(' {}'); - } - - if (gram.elseItem.length && gram.elseItem.length > 0) { - gram.elseItem.forEach(e => { - this.grammer(emitter, e); - }); - } - } - - grammerReturn(emitter, gram) { - emitter.emit('return '); - - if (gram.type === 'null') { - this.grammerValue(emitter, new GrammerValue('null')); - } else if (gram.type === 'grammer') { - this.grammer(emitter, gram.expr, false, false); - } else if (gram.type === 'string') { - emitter.emit('\'\''); - } else { - this.grammer(emitter, gram.expr, false, false); - } - } - - grammerContinue(emitter, gram) { - emitter.emit('continue'); - } - - grammerThrows(emitter, gram) { - if (gram.exception === null) { - emitter.emit('throw '); - this.grammerValue(emitter, gram.params[0]); - } else { - if (gram.params.length > 0) { - emitter.emit(`throw new ${this.emitType(gram.exception)}(`); - if (gram.params.length === 1) { - this.grammerValue(emitter, gram.params[0]); - } else { - let tmp = []; - gram.params.forEach(p => { - let emit = new Emitter(); - this.grammerValue(emit, p); - tmp.push(emit.output); - }); - emitter.emit(tmp.join(', ')); - } - emitter.emit(')'); - } else { - let msg = gram.message ? `'${gram.message}'` : ''; - emitter.emit(`throw new ${this.emitType(gram.exception)}(${msg})`); - } - } - } - - grammerTryCatch(emitter, gram) { - emitter.emitln('try {'); - this.levelUp(); - gram.body.forEach(node => { - this.grammer(emitter, node); - }); - this.levelDown(); - emitter.emitln('}', this.level); - gram.catchBody.forEach(node => { - assert.equal(true, node instanceof GrammerCatch); - this.grammerCatch(emitter, node); - }); - - if (gram.finallyBody) { - this.grammerFinally(emitter, gram.finallyBody); - } - } - - grammerFinally(emitter, gram) { - emitter.emitln('finally {', this.level); - this.levelUp(); - gram.body.forEach(childGram => { - this.grammer(emitter, childGram); - }); - this.levelDown(); - emitter.emitln('}', this.level); - } - - grammerCatch(emitter, gram) { - let emitterVar = new Emitter(); - this.grammerVar(emitterVar, gram.exceptions.exceptionVar); - let varName = emitterVar.output; - emitter.emit(`catch (${this.emitType(gram.exceptions.type)} `, this.level); - emitter.emit(varName); - emitter.emitln(') {'); - this.levelUp(); - emitter.emitln(`if (!(${varName} instanceof ${this.addInclude('$Error')})) {`, this.level); - this.levelUp(); - emitter.emitln(`${varName} = new ${this.addInclude('$Error')}([], ${varName}->getMessage(), ${varName}->getCode(), ${varName});`, this.level); - this.levelDown(); - emitter.emitln('}', this.level); - gram.body.forEach(childGram => { - this.grammer(emitter, childGram); - }); - this.levelDown(); - emitter.emitln('}', this.level); - } - - grammerNewObject(emitter, gram) { - let objectName = ''; - objectName = gram.name; - emitter.emit(`new ${this.resolveName(objectName)}(`); - if (!Array.isArray(gram.params)) { - this.grammerValue(emitter, gram.params); - } else { - if (gram.params.length > 0) { - let params = []; - gram.params.forEach(p => { - let emit = new Emitter(); - if (p.key) { - emit.emit(`$${p.key}`); - emit.emit(' = '); - } - if (typeof (p.value) === 'string') { - if (p.value) { - emit.emit(`${p.value}`); - } else if (p.key) { - emit.emit('\'\''); - } - } else { - this.grammerVar(emit, p.value, false, false); - } - params.push(emit.output); - }); - emitter.emit(params.join(', ')); - } - } - emitter.emit(')'); - } - - behaviorTimeNow(emitter, behavior) { - emitter.emit('time()'); - } - - behaviorSetMapItem(emitter, behavior) { - let emit = new Emitter(); - this.grammerCall(emit, behavior.call); - const key = typeof behavior.key === 'string' ? `"${behavior.key}"` : this.gramRender(behavior.key); - emitter.emit(`${emit.output}[${key}] = `, this.level); - this.grammerValue(emitter, behavior.value); - emitter.emitln(';'); - } - - behaviorDoAction(emitter, behavior) { - emitter.emit('', this.level); - this.grammerVar(emitter, behavior.var); - emitter.emit(`= ${this.addInclude('$Core')}::${this.config.tea.core.doAction}(`); - let params = []; - behavior.params.forEach(p => { - let emit = new Emitter(); - this.grammerValue(emit, p); - params.push(emit.output); - }); - emitter.emit(params.join(', ')); - emitter.emitln(');'); - behavior.body.forEach(node => { - this.grammer(emitter, node); - }); - } - - behaviorRetry(emitter, behavior) { - emitter.emitln(`throw new ${this.addInclude('$Error')}($${this.config.request}, $${this.config.response});`, this.level); - } - - behaviorToModel(emitter, behavior) { - emitter.emit(`${behavior.expected}::fromMap(`); - this.grammer(emitter, behavior.grammer, false, false); - emitter.emit(')'); - } - - behaviorToMap(emitter, behavior) { - const grammer = behavior.grammer; - const grammerCall = new GrammerCall('sys_func', [ - { type: 'object_static', name: this.addInclude('$Core') }, - { type: 'call_static', name: 'merge' } - ], [grammer]); - this.grammer(emitter, grammerCall, false, false); - } - - grammerSymbol(emitter, gram) { - emitter.emit(_symbol(gram)); - } - - behaviorTamplateString(emitter, behavior) { - let tmp = []; - behavior.items.forEach(item => { - let emit = new Emitter(this.config); - if (item.dataType instanceof TypeString) { - this.grammer(emit, item, false, false); - } else { - emit.emit('(string) ('); - this.grammer(emit, item, false, false); - emit.emit(')'); - } - tmp.push(emit.output); - }); - emitter.emit(tmp.join(' . ')); - } -} - -module.exports = Combinator; diff --git a/src/langs/php/config.js b/src/langs/php/config.js deleted file mode 100644 index 12e2354..0000000 --- a/src/langs/php/config.js +++ /dev/null @@ -1,102 +0,0 @@ -'use strict'; - -module.exports = { - indent: ' ', - ext: '.php', - keywords: [ - // https://www.php.net/manual/zh/reserved.keywords.php - '__halt_compiler', 'abstract', 'and', 'array', 'as', - 'break', 'callable', 'case', 'catch', 'class', - 'clone', 'const', 'continue', 'declare', 'default', - 'die', 'do', 'echo', 'else', 'elseif', - 'empty', 'enddeclare', 'endfor', 'endforeach', 'endif', - 'endswitch', 'endwhile', 'eval', 'exit', 'extends', - 'final', 'for', 'foreach', 'function', - 'global', 'goto', 'if', 'implements', 'include', - 'include_once', 'instanceof', 'insteadof', 'interface', 'isset', - 'list', 'namespace', 'new', 'or', 'print', - 'private', 'protected', 'public', 'require', 'require_once', - 'return', 'static', 'switch', 'throw', 'trait', - 'try', 'unset', 'use', 'var', 'while', 'xor' - ], - symbolMap: { - 'ASSIGN': '=', - 'EQ': '==', - 'NOT': '!=', - 'AND': '&&', - 'OR': '||', - 'PLUS': '+', - 'SUB': '-', - 'MULTI': '*', - 'DIV': '/', - 'POWER': '^', - 'GREATER': '>', - 'GREATER_EQ': '>=', - 'LESS': '<', - 'LESS_EQ': '<=', - 'REVERSE': '!', - 'CONCAT': '.' - }, - modifyOrder: [ - 'PRIVATE', - 'PROTECTED', - 'PUBLIC', - 'FINAL', - 'ABSTRACT', - 'STATIC' - ], - model: { - dir: 'Models', - include: [], - }, - client: { - name: 'Client', - include: [] - }, - tea: { - namespace: '\\AlibabaCloud\\Tea\\', - name: 'Tea', - core: { - name: '\\AlibabaCloud\\Tea\\Tea', - doAction: 'send', - allowRetry: 'allowRetry', - sleep: 'sleep', - getBackoffTime: 'getBackoffTime', - isRetryable: 'isRetryable', - toModel: 'toModel', - merge: 'merge' - }, - stream: { name: '\\GuzzleHttp\\Psr7\\Stream' }, - model: { name: '\\AlibabaCloud\\Tea\\Model' }, - response: { name: '\\AlibabaCloud\\Tea\\Response' }, - request: { name: '\\AlibabaCloud\\Tea\\Request' }, - exception: { name: '\\Exception' }, - error: { name: '\\AlibabaCloud\\Tea\\Exception\\TeaError' }, - exceptionUnretryable: { name: '\\AlibabaCloud\\Tea\\Exception\\TeaUnableRetryError' }, - }, - modules: { - darabonba: { - // darabonba package name - Number: { - exclude: true, - methods: { - // the name of method in package - 'parseInt': 'parse', // : - 'parseLong': 'parse', - 'parseFloat': 'parse', - 'parseDouble': 'parse', - 'itol': 'parse', - 'ltoi': 'parse', - 'add': 'binary_operation', - 'sub': 'binary_operation', - 'mul': 'binary_operation', - 'div': 'binary_operation', - 'gt': 'binary_operation', - 'gte': 'binary_operation', - 'lt': 'binary_operation', - 'lte': 'binary_operation' - } - } - } - } -}; diff --git a/src/langs/php/files/composer.json.tmpl b/src/langs/php/files/composer.json.tmpl deleted file mode 100644 index 8a463e6..0000000 --- a/src/langs/php/files/composer.json.tmpl +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "${name}", - "description": "${desc}", - "type": "library", - "license": "Apache-2.0", - "authors": [], - "require": { - "php": ">5.5" - }, - "autoload": { - "psr-4": { - "${namespace}\\": "src" - } - }, - "scripts": { - "fixer": "php-cs-fixer fix ./" - }, - "config": { - "sort-packages": true, - "preferred-install": "dist", - "optimize-autoloader": true - }, - "prefer-stable": true -} diff --git a/src/langs/php/modules.js b/src/langs/php/modules.js deleted file mode 100644 index a0d7732..0000000 --- a/src/langs/php/modules.js +++ /dev/null @@ -1,118 +0,0 @@ -'use strict'; - -const Emitter = require('../../lib/emitter'); - -function param(param_gram) { - let emit = new Emitter(this.config); - this.grammer(emit, param_gram, false, false); - return emit.output; -} - -function parse(emitter, gram) { - const method_name = gram.path[1].name; - const map = { - 'parseInt': '(int)', - 'parseLong': '(int)', - 'parseFloat': '(double)', - 'parseDouble': '(double)', - 'itol': '', - 'ltoi': '', - }; - emitter.emit(`${map[method_name]}${param.call(this, gram.params[0])}`); -} - -function binary_operation(emitter, gram) { - const a = param.call(this, gram.params[0]); - const b = param.call(this, gram.params[1]); - const method_name = gram.path[1].name; - const map = { - 'add': '+', - 'sub': '-', - 'mul': '*', - 'div': '/', - 'gt': '>', - 'gte': '>=', - 'lt': '<', - 'lte': '<=' - }; - emitter.emit(`${a} ${map[method_name]} ${b}`); -} - -function str_split(emitter, gram) { - let raw = param.call(this, gram.params[0]); - let sep = param.call(this, gram.params[1]); - let limit = param.call(this, gram.params[2]); - emitter.emit(`explode(${sep}, (string)${raw}, ${limit} ? ${limit} : null)`); -} - -function str_replace(emitter, gram) { - let raw = param.call(this, gram.params[0]); - let old_str = param.call(this, gram.params[1]); - let new_str = param.call(this, gram.params[2]); - let count = param.call(this, gram.params[3]); - emitter.emit(`str_replace((string)${raw}, (string)${old_str}, (string)${new_str}, (int)${count})`); -} - -function str_contains(emitter, gram) { - let str = param.call(this, gram.params[0]); - let sub = param.call(this, gram.params[1]); - emitter.emit(`false !== strpos((string)${str}, (string)${sub})`); -} - -function str_count(emitter, gram) { - let str = param.call(this, gram.params[0]); - let sub = param.call(this, gram.params[1]); - emitter.emit(`substr_count((string)${str}, (string)${sub})`); -} - -function str_prefix(emitter, gram) { - let str = param.call(this, gram.params[0]); - let sub = param.call(this, gram.params[1]); - emitter.emit(`0 === strpos((string)${str}, (string)${sub})`); -} - -function str_suffix(emitter, gram) { - let str = param.call(this, gram.params[0]); - let sub = param.call(this, gram.params[1]); - emitter.emit(`substr((string)${str}, -\\strlen(${sub})) === ${sub}`); -} - -function str_index(emitter, gram) { - let str = param.call(this, gram.params[0]); - let sub = param.call(this, gram.params[1]); - emitter.emit(`(int)strpos((string)${str}, (string)${sub})`); -} - -function str_lower(emitter, gram) { - let str = param.call(this, gram.params[0]); - emitter.emit(`strtolower((string)${str})`); -} - -function str_upper(emitter, gram) { - let str = param.call(this, gram.params[0]); - emitter.emit(`strtoupper((string)${str})`); -} - -function str_sub(emitter, gram) { - let str = param.call(this, gram.params[0]); - let start = param.call(this, gram.params[1]); - let end = param.call(this, gram.params[2]); - emitter.emit(`substr((string)${str}, ${start}, ${end} - ${start} + 1)`); -} - -module.exports = { - parse, - - str_sub, - str_upper, - str_lower, - str_index, - str_split, - str_count, - str_prefix, - str_suffix, - str_replace, - str_contains, - - binary_operation, -}; diff --git a/src/langs/php/package_info.js b/src/langs/php/package_info.js deleted file mode 100644 index 1144827..0000000 --- a/src/langs/php/package_info.js +++ /dev/null @@ -1,163 +0,0 @@ -'use strict'; - -const path = require('path'); -const fs = require('fs'); -const BasePackageInfo = require('../common/package_info'); - -const { - _render, - _deepClone, - _toSnakeCase, - _isExcludePackage -} = require('../../lib/helper'); - -const OPTION_LOCAL = 0b1; // use local tmpl file to render content -const OPTION_SOURCE = 0b10; // config by Darafile.{lang}.packageInfo -const OPTION_RENDER = 0b100; // render content from tmpl -const OPTION_UPDATE = 0b1000; // update if file already exist - -// file_name : OPTIONS -const files = { - 'gitignore': { - filename: '.gitignore', - mode: OPTION_LOCAL - }, - 'php_cs': { - filename: '.php_cs.dist', - mode: OPTION_LOCAL, - }, - 'composer': { - filename: 'composer.json', - mode: OPTION_LOCAL | OPTION_RENDER | OPTION_SOURCE | OPTION_UPDATE - }, - 'LICENSE': { - filename: 'LICENSE', - mode: OPTION_SOURCE - }, - 'readme_cn': { - filename: 'README-CN.md', - mode: OPTION_SOURCE | OPTION_RENDER - }, - 'readme': { - filename: 'README.md', - mode: OPTION_SOURCE | OPTION_RENDER, - }, - 'phpunit': { - filename: 'phpunit.xml', - mode: OPTION_SOURCE - }, - 'autoload': { - filename: 'autoload.php', - mode: OPTION_LOCAL | OPTION_RENDER - } -}; - -class PackageInfo extends BasePackageInfo { - emit() { - const dependencies = this.dependencies; - const packageInfo = this.config.packageInfo; - const config = _deepClone(this.config); - let outputDir = this.resolveOutputDir(packageInfo, ''); - this.checkParams(packageInfo, ['name', 'desc', 'github']); - const params = { - name: packageInfo.name, - desc: packageInfo.desc, - github: packageInfo.github, - namespace: config.package.split('.').join('\\\\') - }; - if (config.withTest) { - if (!fs.existsSync(path.join(config.dir, 'tests'))) { - fs.mkdirSync(path.join(config.dir, 'tests'), { recursive: true }); - } - fs.writeFileSync( - path.join(config.dir, 'tests', 'bootstrap.php'), - fs.readFileSync(path.join(__dirname, './files/bootstrap.php.tmpl'), 'utf-8') - ); - } - Object.keys(files).forEach(key => { - const item = files[key]; - const filename = item.filename; - const optional = item.mode; - let content = ''; - if (optional & OPTION_UPDATE && fs.existsSync(path.join(outputDir, filename))) { - content = fs.readFileSync(path.join(outputDir, filename), 'utf-8'); - } else if (optional & OPTION_SOURCE && packageInfo.files && packageInfo.files[key]) { - let filepath = path.isAbsolute(packageInfo.files[key]) ? - packageInfo.files[key] : path.join(config.pkgDir, packageInfo.files[key]); - if (!fs.existsSync(filepath)) { - return; - } - content = fs.readFileSync(filepath, 'utf-8'); - } else if (optional & OPTION_LOCAL) { - content = fs.readFileSync(path.join(__dirname, './files/' + filename + '.tmpl'), 'utf-8'); - } - if (content !== '') { - if (optional & OPTION_RENDER) { - content = _render(content, params); - } - if (filename === 'composer.json') { - // extra require - let json = JSON.parse(content); - Object.keys(dependencies).forEach(key => { - Object.keys(dependencies[key].typedef).forEach((types) => { - if (dependencies[key].typedef[types].package) { - let [pack, version] = dependencies[key].typedef[types].package.split(':'); - if (version && version[0] && version[0] !== '^') { - version = '^' + version; - } - json.require[pack] = version; - } - }); - let name; - let version = '*'; - const item = dependencies[key].meta; - if (item.releases && item.releases.php) { - let [p, v] = item.releases.php.split(':'); - name = p; - version = v; - } else { - if (item.php && item.php.packageInfo && item.php.packageInfo.name) { - name = item.php.packageInfo.name; - } else { - name = `${item.scope}/${_toSnakeCase(item.name)}`; - } - } - if (_isExcludePackage(item.scope, item.name)) { - if (json.require[name]) { - delete json.require[name]; - } - return; - } - if (version && version[0] && version[0] !== '^') { - version = '^' + version; - } - json.require[name] = version; - }); - if (config.typedef) { - Object.keys(config.typedef).forEach((types) => { - if (config.typedef[types].package) { - let [pack, version] = config.typedef[types].package.split(':'); - if (version && version[0] && version[0] !== '^') { - version = '^' + version; - } - json.require[pack] = version; - } - }); - } - if (config.maintainers) { - json.authors = []; - config.maintainers.forEach(maintainer => { - let name = maintainer.name ? maintainer.name : ''; - let email = maintainer.email ? maintainer.email : ''; - json.authors.push({ name: name, email: email }); - }); - } - content = JSON.stringify(json, null, 2); - } - fs.writeFileSync(path.join(outputDir, filename), content); - } - }); - } -} - -module.exports = PackageInfo; diff --git a/src/lib/debug.js b/src/lib/debug.js deleted file mode 100644 index 7d7228e..0000000 --- a/src/lib/debug.js +++ /dev/null @@ -1,60 +0,0 @@ -'use strict'; - -const os = require('os'); - -var count = 0; - -function dump(...data) { - if (data && data.length) { - data.forEach(d => console.log(d)); - } -} - -function halt(...data) { - let stack = new Error().stack; - let tmp = stack.split(os.EOL); - let local = tmp[2].indexOf('at Object.jump') > -1 ? tmp[3] : tmp[2]; - process.stdout.write(`\x1b[33mhalt ${local.trim()}\x1b[0m${os.EOL}`); - this.dump(...data); - process.exit(-1); -} - -function jump(jumpNumber = 0, ...data) { - if (count === jumpNumber) { - count = 0; - this.halt(...data); - } else { - count++; - } - return count; -} - -function stack(...data) { - let msg = ''; - if (data[0] && typeof data[0] === 'string') { - msg = data[0]; - data = data.slice(1); - } - this.dump(...data); - throw new Error(msg); -} - -function warning(...data) { - let msg = ''; - if (data[0] && typeof data[0] === 'string') { - msg = data[0]; - data = data.slice(1); - } - this.dump(...data); - if (msg.length) { - process.stdout.write(`\x1b[33m${os.EOL}[WARNING] ${msg}\x1b[0m${os.EOL}`); - } -} - -module.exports = { - dump, - halt, - stack, - jump, - warning -}; diff --git a/src/lib/emitter.js b/src/lib/emitter.js deleted file mode 100644 index 56c1768..0000000 --- a/src/lib/emitter.js +++ /dev/null @@ -1,102 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const path = require('path'); -const os = require('os'); - -class Emitter { - constructor(option = {}) { - this.config = { - indent: ' ', - eol: 'auto', - dir: '', - layer: '', - filename: '', - ext: '', - ...option - }; - - this.output = ''; - - this.eol = this.config.eol === 'auto' ? os.EOL : this.config.eol; - } - - indent(level) { - if (typeof level === 'undefined') { - level = 0; - } - return this.config.indent.repeat(level); - } - - emit(str = '', level) { - this.output += this.indent(level) + str; - return this; - } - - emitln(str = '', level) { - this.emit(str + this.eol, level); - return this; - } - - emits(level, ...strs) { - strs.forEach(str => { - this.emitln(str, level); - }); - return this; - } - - currRow() { - let pos = this.output.length - 1; - while (pos > 0) { - pos--; - let s = this.output[pos]; - if (s === this.eol) { - break; - } - } - return this.output.substring(pos).replace(/[\t\n\r\f]/g, ''); - } - - savePath() { - return path.join( - this.config.dir, - this.config.layer.split('.').join(path.sep), - this.config.filename + this.config.ext - ); - } - - save(append = false) { - if (!this.config.dir) { - throw new Error('`option.dir` should not be empty'); - } - - if (!this.config.filename) { - throw new Error('filename cannot be empty'); - } - - const targetPath = this.savePath(); - - if (!fs.existsSync(path.dirname(targetPath))) { - fs.mkdirSync(path.dirname(targetPath), { - recursive: true - }); - } - - if (append && fs.existsSync(targetPath)) { - fs.appendFileSync(targetPath, this.output); - } else { - fs.writeFileSync(targetPath, this.output); - } - - this.output = ''; - - const consoleInfo = append ? 'append file : ' : 'save path : '; - if (this.config.showInfo) { - console.log(''); - console.log(`\x1b[32${consoleInfo}${path.resolve(targetPath)}\x1b[0m`); - console.log(''); - } - } -} - -module.exports = Emitter; diff --git a/src/lib/helper.js b/src/lib/helper.js deleted file mode 100644 index 91340ce..0000000 --- a/src/lib/helper.js +++ /dev/null @@ -1,326 +0,0 @@ -'use strict'; - -const path = require('path'); -const fs = require('fs'); -const DSL = require('@darabonba/parser'); - -const { - TypeGeneric, - TypeDecimal, - TypeInteger, - TypeStream, - TypeObject, - TypeString, - TypeNumber, - TypeArray, - TypeBytes, - TypeBool, - TypeItem, - TypeVoid, - TypeNull, - TypeMap, - TypeBase, - TypeTree, - PropItem, - FuncItem, - ConstructItem, - AnnotationItem, - GrammerCall, - Grammer, -} = require('../langs/common/items'); - -let config = {}; - -const is = { - undefined: a => typeof (a) === 'undefined', - any: a => a instanceof TypeGeneric, - array: a => a instanceof TypeArray, - map: a => a instanceof TypeMap, - decimal: a => a instanceof TypeDecimal, - base: a => a instanceof TypeBase, - null: a => a instanceof TypeNull, - integer: a => a instanceof TypeInteger, - stream: a => a instanceof TypeStream, - object: a => a instanceof TypeObject, - string: a => a instanceof TypeString, - number: a => a instanceof TypeNumber, - bytes: a => a instanceof TypeBytes, - bool: a => a instanceof TypeBool, - type: a => a instanceof TypeItem, - void: a => a instanceof TypeVoid, - tree: a => a instanceof TypeTree, - // Item - prop: a => a instanceof PropItem, - func: a => a instanceof FuncItem, - construct: a => a instanceof ConstructItem, - annotation: a => a instanceof AnnotationItem, - grammer: a => a instanceof Grammer -}; - -function _config(langConfig = null) { - if (null !== langConfig) { - config = langConfig; - } - return config; -} - -function _upperFirst(str) { - if (!str) { - return ''; - } - return str[0].toUpperCase() + str.substring(1); -} - -function _camelCase(str, split = '_') { - if (str.indexOf(split) > -1) { - let tmp = str.split(split); - tmp = tmp.map((s, i) => { - if (s.length > 0 && i !== 0) { - return _upperFirst(s); - } - return s; - }); - str = tmp.join(''); - } - return str; -} - -function _lowerFirst(str) { - return str[0].toLowerCase() + str.substring(1); -} - -function _subModelName(name) { - return name.split('.').map((name) => _upperFirst(name)).join(''); -} - -function _string(str) { - return str.string; -} - -function _isBasicType(type) { - return DSL.util.isBasicType(type); -} - -function _deepClone(obj) { - return JSON.parse(JSON.stringify(obj)); -} - -function _avoidKeywords(str) { - if (config.keywords.indexOf(str.toLowerCase()) > -1) { - return str + '_'; - } - return str; -} - -function _isKeywords(str) { - return config.keywords.indexOf(str.toLowerCase()) > -1; -} - -function _modify(modify) { - if (Array.isArray(modify)) { - return modify.filter((m) => config.modifyOrder.indexOf(m) > -1) - .map((m) => _modify(m)).sort(function (a, b) { - return config.modifyOrder.indexOf(a.toUpperCase()) - config.modifyOrder.indexOf(b.toUpperCase()); - }).join(' '); - } - return modify.toLowerCase(); -} - -function _symbol(str) { - if (config.symbolMap[str]) { - return config.symbolMap[str]; - } - throw new Error(`Unsupported symbol : ${str}`); -} - -function _toSnakeCase(str) { - if (!str) { - return ''; - } - let res = ''; - let tmp = ''; - for (const c of str) { - if (/[A-Z|0-9]/.test(c)) { - tmp += c; - } else { - if (tmp.length > 0) { - res += res === '' ? tmp.toLowerCase() : '_' + tmp.toLowerCase(); - tmp = ''; - } - res += c; - } - } - if (tmp.length > 0) { - res += '_' + tmp.toLowerCase(); - } - res = res.replace(/-/g, '_'); - if (str[0] !== '_' && res[0] === '_') { - res = res.substr(1); - } - return res; -} - -function _flatten(obj, sep = '.') { - function recurse(curr, prefix, res = {}) { - if (Array.isArray(curr)) { - curr.forEach((item, index) => { - recurse(item, prefix ? `${prefix}${sep}${index}` : `${index}`, res); - }); - } else if (curr instanceof Object) { - const keys = Object.keys(curr); - if (keys.length) { - keys.forEach((key) => { - recurse(curr[key], prefix ? `${prefix}${sep}${key}` : `${key}`, res); - }); - } else if (prefix) { - res[prefix] = curr; - } - } else { - res[prefix] = curr; - } - } - let output = {}; - recurse(obj, '', output); - return output; -} - -function _unflatten(obj, sep = '.') { - let output = {}; - Object.keys(obj).forEach(key => { - if (key.indexOf(sep) !== -1) { - const keyArr = key.split('.').filter(item => item !== ''); - let currObj = output; - keyArr.forEach((k, i) => { - if (typeof currObj[k] === 'undefined') { - if (i === keyArr.length - 1) { - currObj[k] = obj[key]; - } else { - currObj[k] = isNaN(keyArr[i + 1]) ? {} : []; - } - } - currObj = currObj[k]; - }); - } else { - output[key] = obj[key]; - } - }); - return output; -} - -function _assignObject(targetObj, ...objs) { - const res = _flatten(targetObj); - objs.forEach(obj => { - Object.assign(res, _flatten(obj)); - }); - Object.assign(targetObj, _unflatten(res)); - return targetObj; -} - -function _render(template, params) { - Object.keys(params).forEach((key) => { - template = template.split('${' + key + '}').join(params[key]); - }); - return template; -} - -function _dir(output) { - if (!fs.existsSync(path.dirname(output))) { - fs.mkdirSync(path.dirname(output), { - recursive: true - }); - } -} - -function _contain(str, substr) { - return str.indexOf(substr) > -1; -} - -function _startWith(str, substr) { - return str.indexOf(substr) === 0; -} - -function _name(str, avoidKeyword = true) { - str = `${str}`; - if (str.indexOf('@') === 0) { - str = `_${str.substr(1)}`; - } - if (str === '__response') { - str = config.response; - } else if (str === '__request') { - str = config.request; - } - return avoidKeyword ? _avoidKeywords(str) : str; -} - -function _resolveGrammerCall(grammer, dependencies) { - if (!(grammer instanceof GrammerCall)) { - return null; - } - if (grammer.path.length !== 2) { - return null; - } - if (grammer.path[0].type !== 'object_static' || grammer.path[1].type !== 'call_static') { - return null; - } - if (grammer.path[0].name[0] !== '^') { - return null; - } - const name = grammer.path[0].name.substr(1); - const scope = dependencies[name].scope; - if (!scope) { - return null; - } - const modules = config.modules; - if (!modules[scope]) { - return null; - } - const package_name = name; - const method_name = grammer.path[1].name; - const m = modules[scope]; - if (!m[package_name]) { - return null; - } - const methods = m[package_name].methods; - if (methods[method_name] === '') { - return `${_toSnakeCase(scope)}_${_toSnakeCase(package_name)}_${_toSnakeCase(method_name)}`; - } else if (!methods[method_name]) { - return null; - } - return methods[method_name]; -} - -function _isExcludePackage(scope, package_name) { - const modules = config.modules; - if (!modules[scope]) { - return false; - } - const m = modules[scope]; - return m[package_name] && m[package_name].exclude; -} - -module.exports = { - is, - _dir, - _name, - _config, - _string, - _modify, - _symbol, - _render, - _contain, - _flatten, - _startWith, - _unflatten, - _camelCase, - _deepClone, - _upperFirst, - _lowerFirst, - _isKeywords, - _toSnakeCase, - _isBasicType, - _assignObject, - _subModelName, - _avoidKeywords, - _isExcludePackage, - _resolveGrammerCall -}; diff --git a/src/resolver/base.js b/src/resolver/base.js deleted file mode 100644 index cea9627..0000000 --- a/src/resolver/base.js +++ /dev/null @@ -1,272 +0,0 @@ -'use strict'; - -const debug = require('../lib/debug'); - -const { - AnnotationItem, - TypeString, - TypeArray, - TypeInteger, - TypeBytes, - TypeMap, - TypeObject, - TypeGeneric, - TypeStream, - TypeVoid, - TypeNumber, - TypeBool, - TypeNull, - TypeDecimal -} = require('../langs/common/items'); - -const { _isBasicType } = require('../lib/helper'); - -const DSL = require('@darabonba/parser'); - -class BaseResolver { - constructor(astNode, combinator, globalAst) { - this.ast = astNode; - this.combinator = combinator; - this.config = combinator.config; - - this.comments = globalAst.comments ? globalAst.comments : {}; - this.commentsSet = []; - } - - resolveAnnotations(annotations, belong) { - if (annotations.length > 0) { - let comments = []; - annotations.forEach(annotation => { - comments.push(this.resolveAnnotation(annotation, belong)); - }); - return comments; - } - return []; - } - - resolveAnnotation(annotation, belong) { - let type = annotation.value.indexOf('/**') === 0 ? 'multi' : 'single'; - let content = ''; - if (type === 'multi') { - content = annotation.value.substring(3, annotation.value.length - 2) - .trim().split('\n').filter(c => c.length > 0).map(c => { - if (c.indexOf(' * ') === 0) { - return c.substring(3); - } else if (c.indexOf('* ') === 0) { - return c.substring(2); - } - return c; - }); - } else { - content = annotation.value.substring(2).trim(); - } - return new AnnotationItem(belong, type, content); - } - - getBackComments(index) { - return DSL.comment.getBackComments(this.comments, index); - } - - getBetweenComments(begin, end) { - return DSL.comment.getBetweenComments(this.comments, begin, end); - } - - getFrontComments(index) { - return DSL.comment.getFrontComments(this.comments, index); - } - - getComments(node, position = 'front') { - if (typeof node.tokenRange === 'undefined') { - return []; - } - switch (position) { - case 'back': - return this.getBackComments(node.tokenRange[1]); - case 'between': - return this.getBetweenComments(node.tokenRange[0], node.tokenRange[1]); - default: - return this.getFrontComments(node.tokenRange[0]); - } - } - - addAnnotations(obj, node, position = 'front') { - let comments = this.getComments(node, position); - if (comments.length > 0) { - comments.forEach(c => { - if (this.commentsSet.indexOf(c.index) < 0) { - if (typeof obj.annotations !== 'undefined') { - obj.annotations.push(this.resolveAnnotation(c, obj.index)); - } else { - debug.stack(obj, node); - } - this.commentsSet.push(c.index); - } - }); - } - } - - findComments(obj, node, position = 'front') { - let comments = this.getComments(node, position); - - if (comments.length > 0) { - comments.forEach(c => { - if (this.commentsSet.indexOf(c.index) < 0) { - if (typeof obj.body !== 'undefined') { - obj.body.push(this.resolveAnnotation(c, obj.index)); - } else if (typeof obj.value !== 'undefined') { - obj.value.push(this.resolveAnnotation(c, obj.index)); - } else { - debug.stack('Invalid data node', obj, node); - } - this.commentsSet.push(c.index); - } - }); - } - } - - initAnnotation(annotation) { - let topComments = this.getFrontComments(annotation.index); - topComments.map(c => { - this.object.topAnnotation.push(this.resolveAnnotation(c, this.object.index)); - }); - if (annotation && annotation.value) { - this.object.annotations.push(this.resolveAnnotation(annotation, this.object.index)); - } - } - - resolveTypeItem(typeNode, sourceNode = null) { - if (typeNode.idType) { - if (typeNode.idType === 'model') { - return new TypeObject(`#${typeNode.lexeme}`); - } else if (typeNode.idType === 'module') { - return new TypeObject(`^${typeNode.lexeme}`); - } else if (typeNode.idType === 'typedef') { - return new TypeObject(`%${typeNode.lexeme}`); - } else if (typeNode.idType === 'builtin_model') { - return new TypeObject(`^${typeNode.lexeme}`); - } - debug.stack(typeNode, sourceNode); - } else if (typeNode.type) { - if (typeNode.type === 'fieldType') { - if (typeNode.fieldType.idType) { - if (typeNode.fieldType.idType === 'module') { - return new TypeObject(`^${typeNode.fieldType.lexeme}`); - } else if (typeNode.fieldType.idType === 'typedef') { - return new TypeObject(`%${typeNode.fieldType.lexeme}`); - } - return new TypeObject(`#${typeNode.fieldType.lexeme}`); - } - return this.resolveTypeItem(typeNode.fieldType, typeNode); - } else if (typeNode.type === 'modelBody') { - // is sub model - const modelName = `#${[this.object.name, sourceNode.fieldName.lexeme].join('.')}`; - return new TypeObject(modelName); - } else if (_isBasicType(typeNode.type)) { - return this.resolveTypeItem(typeNode.type, typeNode); - } else if (typeNode.type === 'basic') { - return this.resolveTypeItem(typeNode.name, sourceNode); - } else if (typeNode.type === 'model') { - let name = typeNode.name; - if (typeNode.moduleName) { - name = typeNode.moduleName + '.' + name; - } - return new TypeObject(`#${name}`); - } else if (typeNode.type === 'module_instance') { - return new TypeObject(`^${typeNode.name}`); - } else if (typeNode.type === 'param') { - if (typeNode.paramType.idType) { - return new TypeObject(`#${typeNode.paramType.lexeme}`); - } - return this.resolveTypeItem(typeNode.paramType, typeNode); - } else if (typeNode.type === 'array') { - const subType = typeNode.subType ? typeNode.subType : typeNode.itemType; - return new TypeArray(this.resolveTypeItem(subType)); - } else if (typeNode.type === 'moduleModel') { - let tmp = []; - typeNode.path.forEach(item => { - tmp.push(item.lexeme); - }); - return new TypeObject(`#${tmp.join('.')}`); - } else if (typeNode.type === 'moduleTypedef') { - let tmp = []; - typeNode.path.forEach(item => { - tmp.push(item.lexeme); - }); - return new TypeObject(`%${tmp.join('.')}`); - } else if (typeNode.type === 'typedef') { - if (typeNode.moduleName) { - return new TypeObject(`%${typeNode.moduleName}.${typeNode.name}`); - } - return new TypeObject(`%${typeNode.name}`); - } else if (typeNode.type === 'subModel' || typeNode.type === 'subModel_or_moduleModel') { - // subModel_or_moduleModel is retained for compatibility with older parser. - let tmp = []; - typeNode.path.forEach(item => { - tmp.push(item.lexeme); - }); - return new TypeObject(`#${tmp.join('.')}`); - } - debug.stack(typeNode, sourceNode); - } else if (typeNode.lexeme) { - return this.resolveTypeItem(typeNode.lexeme, sourceNode); - } else if (typeNode === 'string') { - return new TypeString(); - } else if (typeNode === 'bytes') { - return new TypeBytes(); - } else if (typeNode === 'array') { - let itemType; - if (sourceNode.fieldItemType.type === 'modelBody') { - itemType = new TypeObject(`#${sourceNode.itemType}`); - } else if (sourceNode.fieldItemType.idType === 'model') { - itemType = new TypeObject(`#${sourceNode.fieldItemType.lexeme}`); - } else { - itemType = this.resolveTypeItem(sourceNode.fieldItemType, sourceNode); - } - return new TypeArray(itemType); - } else if (typeNode === 'map') { - const keyType = this.resolveTypeItem(sourceNode.keyType); - const valType = this.resolveTypeItem(sourceNode.valueType); - return new TypeMap(keyType, valType); - } else if (typeNode === 'any') { - return new TypeGeneric(); - } else if (typeNode === 'object') { - return new TypeMap(new TypeString(), new TypeGeneric()); - } else if (typeNode === 'integer') { - return new TypeInteger(); - } else if (typeNode === 'readable') { - return new TypeStream(false); - } else if (typeNode === 'writable') { - return new TypeStream(true); - } else if (typeNode === 'class') { - return new TypeObject(); - } else if (typeNode === 'void') { - return new TypeVoid(); - } else if (typeNode === 'number') { - return new TypeNumber(); - } else if (typeNode === 'boolean') { - return new TypeBool(); - } else if (typeNode === 'null') { - return new TypeNull(); - } else if (typeNode === 'float') { - return new TypeDecimal(4); - } else if (typeNode === 'double') { - return new TypeDecimal(8); - } else if (typeNode === 'long') { - return new TypeInteger(64); - } else if (typeNode === 'ulong') { - return new TypeInteger(64, true); - } else if (typeNode.indexOf('int') === 0) { - let len = typeNode.substring(3); - return new TypeInteger(parseInt(len)); - } else if (typeNode.indexOf('uint') === 0) { - let len = typeNode.substring(4); - return new TypeInteger(parseInt(len), true); - } - if (typeof typeNode === 'string' && typeNode.length > 0) { - return new TypeObject(`#${typeNode}`); - } - debug.stack('Unsupported type node', { typeNode, sourceNode }); - } -} - -module.exports = BaseResolver; diff --git a/src/resolver/client.js b/src/resolver/client.js deleted file mode 100644 index 487efef..0000000 --- a/src/resolver/client.js +++ /dev/null @@ -1,1067 +0,0 @@ -'use strict'; - -const debug = require('../lib/debug'); -const BaseResolver = require('./base'); - -const { - AnnotationItem, - ConstructItem, - ObjectItem, - FuncItem, - PropItem, - - GrammerVar, - GrammerCall, - GrammerExpr, - GrammerLoop, - GrammerBreak, - GrammerCatch, - GrammerValue, - GrammerReturn, - GrammerThrows, - GrammerFinally, - GrammerContinue, - GrammerTryCatch, - GrammerNewObject, - GrammerCondition, - GrammerException, - - BehaviorRetry, - BehaviorToMap, - BehaviorToModel, - BehaviorTimeNow, - BehaviorDoAction, - BehaviorSetMapItem, - BehaviorTamplateString, - - TypeMap, - TypeBool, - TypeVoid, - TypeItem, - TypeNull, - TypeObject, - TypeString, - TypeInteger, - TypeGeneric, -} = require('../langs/common/items'); - -const { - Symbol, - Modify, -} = require('../langs/common/enum'); - -const { - _isBasicType, is -} = require('../lib/helper'); -const assert = require('assert'); - -const systemPackage = ['Util']; - -const int16 = new TypeInteger(16); -const genericType = new TypeGeneric(); -const runtimeType = new TypeMap(new TypeString(), genericType); -const errorType = new TypeObject('$Error'); -const exceptionType = new TypeObject('$Exception'); -const requestType = new TypeObject('$Request'); -const nullType = new TypeNull(); -const unretryableType = new TypeObject('$ExceptionUnretryable'); - -class ClientResolver extends BaseResolver { - constructor(astNode, combinator, globalAst) { - super(astNode, combinator, globalAst); - this.object = new ObjectItem('client'); - this.currThrows = {}; - } - - resolve() { - const object = this.object; - const combinator = this.combinator; - const config = this.config; - const ast = this.ast; - - combinator.config.emitType = 'client'; - object.name = config.clientName || 'Client'; - - // resolve props - this.resolveProps(ast); - - // resolve global annotation - if (ast.annotation) { - this.initAnnotation(ast.annotation); - } - object.topAnnotation.push(new AnnotationItem( - object.index, - 'single', - config.generateFileInfo - )); - - // resolve extends - if (ast.extends) { - object.extends.push(`^${ast.extends.lexeme}`); - } else if (config.baseClient) { - let extendsClass = []; - if (Array.isArray(config.baseClient)) { - config.baseClient.forEach(item => extendsClass.push(`^${item}`)); - } else { - extendsClass = [`^${config.baseClient}`]; - } - object.extends = extendsClass; - } - - // resolve construct body - const [init] = ast.moduleBody.nodes.filter((item) => { - return item.type === 'init'; - }); - if (init) { - this.resolveInitBody(init); - } - - // resolve api - ast.moduleBody.nodes.filter((item) => { - return item.type === 'api'; - }).forEach(item => { - const func = new FuncItem(); - func.name = item.apiName.lexeme; - this.resolveFunc(func, item, item.apiBody); - }); - - // resolve function - ast.moduleBody.nodes.filter((item) => { - return item.type === 'function'; - }).forEach(item => { - const func = new FuncItem(); - func.name = item.functionName.lexeme; - this.resolveFunc(func, item, item.functionBody); - }); - - return object; - } - - resolveProps(ast) { - this.comments = ast.comments; - - ast.moduleBody.nodes.filter((item) => { - return item.type === 'type'; - }).forEach(item => { - const prop = new PropItem(); - prop.name = item.vid.lexeme.replace('@', '_'); - prop.type = this.resolveTypeItem(item.value, item); - prop.addModify(Modify.protected()); - if (item.tokenRange) { - let comments = this.getFrontComments(item.tokenRange[0]); - if (comments.length > 0) { - comments.forEach(c => { - this.object.addBodyNode(this.resolveAnnotation(c, this.object.index)); - }); - } - } - this.object.addBodyNode(prop); - }); - } - - resolveInitBody(init) { - const object = this.object; - - let constructNode = new ConstructItem(); - this.currThrows = {}; - if (init.params && init.params.params) { - init.params.params.forEach(param => { - let type = this.resolveTypeItem(param.paramType, param); - constructNode.addParamNode(new GrammerValue(type, param.defaultValue, param.paramName.lexeme)); - }); - } - if (init.annotation) { - constructNode.addAnnotation(this.resolveAnnotation(init.annotation, constructNode.index)); - } - if (init.initBody && init.initBody.stmts) { - init.initBody.stmts.forEach(stmt => { - this.visitStmt(constructNode, stmt, constructNode.index); - }); - } - if (Object.keys(this.currThrows).length > 0) { - constructNode.throws = Object.values(this.currThrows); - } - object.addBodyNode(constructNode); - } - - resolveFunc(func, ast, body) { - this.currThrows = {}; - if (ast.annotation) { - func.addAnnotation(this.resolveAnnotation(ast.annotation, func.index)); - } - this.addAnnotations(func, ast); - if (body === null) { - func.addBodyNode(new GrammerThrows(exceptionType, [], 'Un-implemented')); - } - - if (ast.isAsync) { - func.modify.push(Modify.async()); - } - if (ast.isStatic) { - func.modify.push(Modify.static()); - } - func.modify.push(Modify.public()); - - ast.params.params.forEach(p => { - var param = new GrammerValue(); - param.type = this.resolveTypeItem(p.paramType, p); - param.key = p.paramName.lexeme; - if (p.needValidate) { - func.addBodyNode(new GrammerCall('method', [ - { type: 'object', name: param.key }, - { type: 'call', name: 'validate' } - ], [], new TypeVoid(), true)); // validator - } - func.params.push(param); - }); - - func.return.push(this.resolveTypeItem(ast.returnType)); - - if (ast.runtimeBody) { - this.runtimeMode(func, ast, body); - } else { - if (ast.functionBody || ast.wrapBody) { - body.stmts.stmts.forEach(stmtItem => { - this.visitStmt(func, stmtItem, func.index); - }); - } else { - this.requestBody(ast, body, func); - } - } - - if (func.body.length === 0) { - this.findComments(func, body, 'between'); - } - - if (Object.keys(this.currThrows).length > 0) { - func.throws = Object.values(this.currThrows); - } - this.object.addBodyNode(func); - } - - runtimeMode(func, ast, body) { - var val = new GrammerValue('array', []); - this.renderGrammerValue(val, ast.runtimeBody); - if (ast.runtimeBody.tokenRange) { - this.resolveAnnotations(this.getFrontComments(ast.runtimeBody.tokenRange[1])).forEach(c => { - val.value.push(c); - }); - } - - // _runtime = {} - func.addBodyNode(new GrammerExpr( - new GrammerVar(this.config.runtime, runtimeType), Symbol.assign(), val - )); - - // _lastRequest = null; - func.addBodyNode(new GrammerExpr( - new GrammerVar('_lastRequest', requestType, 'var'), - Symbol.assign(), - new GrammerValue('null', null, nullType) - )); - - // _lastException = null; - func.addBodyNode(new GrammerExpr( - new GrammerVar('_lastException', exceptionType, 'var'), - Symbol.assign(), - new GrammerValue('null', null, nullType) - )); - - // _now = Date.now(); - func.addBodyNode(new GrammerExpr( - new GrammerVar('_now', int16), - Symbol.assign(), - new GrammerValue('behavior', new BehaviorTimeNow(), int16) - )); - - // let _retryTimes = 0; - func.addBodyNode(new GrammerExpr( - new GrammerVar('_retryTimes', int16, 'var'), - Symbol.assign(), - new GrammerValue('number', 0, int16) - )); - - let whileOperation = new GrammerCondition('while'); - whileOperation.addCondition( - new GrammerCall('method', [ - { type: 'object_static', name: '$Core' }, - { type: 'call_static', name: this.config.tea.core.allowRetry } - ], [ - new GrammerValue('call', new GrammerCall('key', [ - { type: 'object', name: this.config.runtime }, - { type: 'map', name: 'retry' } - ], [], genericType)), - new GrammerValue('param', '_retryTimes', int16), - new GrammerValue('param', '_now', int16), - ], new TypeBool()) - ); - - let retryTimesIf = new GrammerCondition('if'); - retryTimesIf.addCondition( - new GrammerExpr( - new GrammerVar('_retryTimes', int16), - Symbol.greater(), - new GrammerValue('number', 0, int16) - ) - ); - retryTimesIf.addBodyNode( - new GrammerExpr( - new GrammerVar('_backoffTime', int16), - Symbol.assign(), - new GrammerCall('method', [ - { type: 'object_static', name: '$Core' }, - { type: 'call_static', name: this.config.tea.core.getBackoffTime } - ], [ - new GrammerValue('call', new GrammerCall('key', [ - { type: 'object', name: this.config.runtime }, - { type: 'map', name: 'backoff' } - ]), genericType), - new GrammerValue('param', '_retryTimes', int16), - ], int16) - ) - ); - - let backoffTimeIf = new GrammerCondition('if'); - let backoffTimeValue = new GrammerValue('number', 0, int16); - backoffTimeValue.dataType = int16; - backoffTimeIf.addCondition( - new GrammerExpr( - new GrammerVar('_backoffTime', int16), - Symbol.greater(), - backoffTimeValue - ) - ); - backoffTimeIf.addBodyNode( - new GrammerCall('method', [ - { type: 'object_static', name: '$Core' }, - { type: 'call_static', name: this.config.tea.core.sleep } - ], [ - new GrammerValue('param', '_backoffTime', int16), - ]) - ); - - retryTimesIf.addBodyNode(backoffTimeIf); - whileOperation.addBodyNode(retryTimesIf); - - let retryTimesValue = new GrammerValue('number', 1, int16); - retryTimesValue.dataType = int16; - whileOperation.addBodyNode(new GrammerExpr( - new GrammerVar('_retryTimes', int16), - Symbol.assign(), - new GrammerExpr( - new GrammerVar('_retryTimes', int16), - Symbol.plus(), - retryTimesValue - ) - )); - - let requestTryCatch = new GrammerTryCatch(); - let exceptionVar = new GrammerVar('e', exceptionType); - let exceptionParam = new GrammerValue('var', exceptionVar, exceptionType); - let catchException = new GrammerException(exceptionType, exceptionVar); - - let tryCatch = new GrammerCatch([ - new GrammerCondition('if', [ - new GrammerCall('method', [ - { type: 'object_static', name: '$Core' }, - { type: 'call_static', name: this.config.tea.core.isRetryable } - ], [exceptionVar]) - ], [ - new GrammerExpr( - new GrammerVar('_lastException', exceptionType, 'var'), - Symbol.assign(), - exceptionVar - ), - new GrammerContinue(whileOperation.index) - ]), - new GrammerThrows(null, [exceptionParam]) - ], catchException); - this.currThrows['$Error'] = errorType; - this.currThrows['$Exception'] = exceptionType; - this.requestBody(ast, body, requestTryCatch); - requestTryCatch.addCatch(tryCatch); - - whileOperation.addBodyNode(requestTryCatch); - - func.addBodyNode(whileOperation); - - func.addBodyNode( - new GrammerThrows( - unretryableType, [ - new GrammerValue('var', new GrammerVar('_lastRequest', requestType), requestType), - new GrammerValue('var', new GrammerVar('_lastException', exceptionType), exceptionType) - ] - ) - ); - this.currThrows['$ExceptionUnretryable'] = unretryableType; - } - - requestBody(ast, body, func) { - if (body) { - if (body.type === 'apiBody') { - // TeaRequest _request = new TeaRequest() - func.addBodyNode( - new GrammerExpr( - new GrammerVar(this.config.request, requestType), - Symbol.assign(), - new GrammerNewObject('$Request') - ) - ); - } - - const stmt = ['declares', 'protocol', 'port', 'method', 'pathname', 'quert', 'headers', 'body', 'appendStmts']; - stmt.forEach(key => { - if (body[key] && body[key] !== 'undefined') { - if (Array.isArray(body[key])) { - body[key].forEach(stmtItem => { - this.visitStmt(func, stmtItem, func.index); - }); - } else { - this.visitStmt(func, body[key], func.index); - } - } - }); - - if (body.type === 'apiBody') { - var doActionParams = []; - doActionParams.push(new GrammerValue('param', this.config.request, requestType)); - - if (ast.runtimeBody) { - doActionParams.push(new GrammerValue('param', this.config.runtime, runtimeType)); - } - - // response = Tea.doAction - const doActionBehavior = new BehaviorDoAction( - new GrammerVar(this.config.response, new TypeObject('$Response')), doActionParams - ); - - if (body.stmts) { - body.stmts.stmts.forEach(stmt => { - this.visitStmt(func, stmt, func.index); - }); - } - - // _lastRequest = request_; - func.addBodyNode( - new GrammerExpr( - new GrammerVar('_lastRequest', requestType, 'var'), - Symbol.assign(), - new GrammerVar(this.config.request, requestType) - ) - ); - - // returns - if (ast.returns) { - if (ast.returns.stmts.stmts.length > 0) { - ast.returns.stmts.stmts.forEach(stmt => { - this.visitStmt(doActionBehavior, stmt, doActionBehavior.index); - }); - } else { - this.findComments(doActionBehavior, ast.returns, 'between'); - } - } - func.addBodyNode(doActionBehavior); - } - if (body.tokenRange) { - this.resolveAnnotations(this.getFrontComments(body.tokenRange[1], func.index)).forEach(c => { - func.addBodyNode(c); - }); - } - } - } - - renderGrammerValue(valGrammer, object, expectedType = null) { - if (!valGrammer) { - valGrammer = new GrammerValue(); - } - if (!valGrammer.value && object.type === 'object') { - valGrammer.value = []; - } - if (object.type === 'variable') { - if (object.needCast) { - let grammerVar = new GrammerVar(object.id.lexeme, this.resolveTypeItem(object.inferred)); - valGrammer.type = 'behavior'; - grammerVar.belong = valGrammer.index; - const behaviorToMap = new BehaviorToMap(grammerVar, object.inferred); - behaviorToMap.belong = valGrammer.index; - valGrammer.value = behaviorToMap; - } else { - valGrammer.type = 'var'; - let grammerVar; - if (object.id.type === 'model') { - const name = `#${object.id.lexeme}`; - const type = this.resolveTypeItem(object.inferred); - type.objectName = name; - grammerVar = new GrammerVar(object.id.lexeme, type); - grammerVar.varType = 'static_class'; - grammerVar.name = name; - } else if (object.type === 'variable') { - grammerVar = new GrammerVar(object.id.lexeme, this.resolveTypeItem(object.inferred ? object.inferred : 'string')); - grammerVar.varType = 'var'; - } - valGrammer.value = grammerVar; - } - } else if (object.type === 'object') { - object.fields.forEach(field => { - var val = null; - var type = field.expr.type; - if (field.expr.type === 'object') { - val = []; - type = 'map'; - } - var exprChild = new GrammerValue(type, val); - if (field.type === 'expandField') { - valGrammer.needCast = true; - exprChild.isExpand = true; - } - if (field.fieldName && field.fieldName.lexeme) { - exprChild.key = field.fieldName.lexeme; - } - this.renderGrammerValue(exprChild, field.expr, expectedType); - this.findComments(valGrammer, field); - valGrammer.value.push(exprChild); - this.findComments(valGrammer, field.expr, 'back'); - }); - valGrammer.type = 'map'; - valGrammer.dataType = this.resolveTypeItem(object.inferred); - valGrammer.expected = expectedType ? this.resolveTypeItem(expectedType) : null; - } else if (object.type === 'string') { - valGrammer.type = 'string'; - valGrammer.value = object.value.string; - valGrammer.dataType = this.resolveTypeItem(object.type); - } else if (object.type === 'property_access') { - let last_path_type = this.resolveTypeItem(object.id.inferred || object.inferred); - let call = new GrammerCall('prop', [], [], last_path_type); - call.addPath({ type: 'object', name: object.id.lexeme, dataType: last_path_type }); - object.propertyPath.forEach((item, i) => { - var path_name = item.lexeme; - let path_type = this.resolveTypeItem(object.propertyPathTypes[i]); - let call_type = 'prop'; - if (is.array(last_path_type)) { - call_type = 'list'; - } else if (is.map(last_path_type)) { - call_type = 'map'; - } else if (is.object(last_path_type)) { - call_type = 'prop'; - } else { - debug.stack(last_path_type); - } - call.addPath({ type: call_type, name: path_name, dataType: path_type }); - last_path_type = path_type; - }); - - valGrammer.type = 'call'; - valGrammer.value = call; - if (object.needCast) { - valGrammer.type = 'behavior'; - valGrammer.value = new BehaviorToMap(valGrammer.value, object.inferred); - } - } else if (object.type === 'number') { - valGrammer.type = 'number'; - valGrammer.value = object.value.value; - valGrammer.dataType = this.resolveTypeItem(object.inferred); - } else if (object.type === 'virtualVariable') { - valGrammer.type = 'call'; - let call = new GrammerCall('prop', [ - { type: 'parent', name: '' }, - { type: 'prop', name: object.vid.lexeme }, - ]); - valGrammer.value = call; - } else if (object.type === 'template_string') { - valGrammer.type = 'behavior'; - let behaviorTamplateString = new BehaviorTamplateString(); - object.elements.forEach(ele => { - if (ele.type !== 'element') { - behaviorTamplateString.addItem(this.renderGrammerValue(null, ele.expr)); - } else { - behaviorTamplateString.addItem(new GrammerValue('string', ele.value.string, new TypeString())); - } - }); - valGrammer.value = behaviorTamplateString; - } else if (object.type === 'null') { - valGrammer.type = 'null'; - valGrammer.value = 'null'; - } else if (object.type === 'construct_model') { - let objectName = object.aliasId.lexeme ? object.aliasId.lexeme : ''; - if (object.propertyPath && object.propertyPath.length > 0) { - if (object.propertyPath.length > 0 && objectName !== '') { - objectName = objectName + '.'; - } - object.propertyPath.forEach((p, i) => { - objectName += p.lexeme; - if (i !== object.propertyPath.length - 1) { - objectName += '.'; - } - }); - } - objectName = `#${objectName}`; - - valGrammer.type = 'instance'; - let params = []; - if (object.object) { - params = this.renderGrammerValue(null, object.object); - if (params.value.length === 0) { - this.findComments(params, object.object, 'between'); - } - if (object.object.inferred.type === 'map') { - params.type = 'model_construct_params'; - } - } - valGrammer.value = new GrammerNewObject(objectName, params); - } else if (object.type === 'call') { - let call_type = 'method'; - valGrammer.type = 'call'; - if (object.left && object.left.id && object.left.id.type === 'module') { - if (systemPackage.indexOf(object.left.id.lexeme) > -1) { - call_type = 'sys_func'; - } - } else { - valGrammer.type = 'call'; - call_type = 'method'; - } - let call = new GrammerCall(call_type); - - if (object.left) { - let isStatic = object.isStatic ? true : false; - let callType = isStatic ? '_static' : ''; - if (object.left.type === 'method_call') { - call.addPath({ type: 'parent', name: '' }); - call.addPath({ type: 'call' + callType, name: object.left.id.lexeme }); - } else if (object.left.type === 'instance_call') { - if (object.left && object.left.id && object.left.id.lexeme) { - if (object.left.id.type === 'variable') { - call.addPath({ type: 'object' + callType, name: object.left.id.lexeme }); - } else if (typeof object.left.id.type === 'undefined' && object.left.id.lexeme.indexOf('@') > -1) { - call.addPath({ type: 'parent', name: object.left.id.lexeme.replace('@', '_') }); - } else { - debug.stack('Unsupported object.left.id.type : ' + object.left.id.type, object); - } - } - } else if (object.left.type === 'static_call') { - if (object.left.id.type === 'module') { - call.addPath({ type: 'object_static', name: `^${object.left.id.lexeme}` }); - isStatic = true; - } else { - // call.addPath({ type: 'call_static', name: object.left.id.lexeme }); - debug.stack(object); - } - } else { - debug.stack(object.left); - } - - if (object.left.propertyPath) { - object.left.propertyPath.forEach(p => { - call.addPath({ - type: 'call' + callType, - name: p.lexeme - }); - }); - } - } - if (object.args) { - object.args.forEach(arg => { - const grammerValue = this.renderGrammerValue(null, arg); - grammerValue.belong = call.index; - call.addParams(grammerValue); - }); - } - call.returnType = this.resolveTypeItem(object.inferred); - valGrammer.value = call; - } else if (object.type === 'construct') { - valGrammer.type = 'instance'; - const objectName = `^${object.aliasId.lexeme}`; - valGrammer.value = new GrammerNewObject(objectName); - object.args.forEach(item => { - valGrammer.value.addParam(this.renderGrammerValue(null, item)); - }); - } else if (object.type === 'boolean') { - valGrammer.type = 'bool'; - valGrammer.value = object.value; - } else if (object.type === 'not') { - valGrammer.type = 'not'; - valGrammer.value = this.renderGrammerValue(null, object.expr); - } else if (object.type === 'array') { - valGrammer.type = 'array'; - valGrammer.value = []; - if (object.items.length > 0) { - object.items.forEach(field => { - this.findComments(valGrammer, field); - var exprChild = this.renderGrammerValue(null, field, expectedType); - valGrammer.value.push(exprChild); - this.findComments(valGrammer, field, 'back'); - }); - } else { - this.findComments(valGrammer, object, 'between'); - } - valGrammer.type = 'array'; - valGrammer.expected = expectedType ? this.resolveTypeItem(expectedType) : null; - } else if (object.type === 'property') { - object.type = 'property_access'; - this.renderGrammerValue(valGrammer, object); - } else if (object.type === 'super') { - valGrammer.type = 'call'; - let call = new GrammerCall('super'); - object.args.forEach(arg => { - call.addParams(this.renderGrammerValue(null, arg)); - }); - valGrammer.value = call; - } else if (object.type === 'map_access') { - valGrammer.type = 'call'; - let accessKey; - if (object.accessKey.inferred) { - accessKey = this.renderGrammerValue(null, object.accessKey); - } else if (object.accessKey.type === 'variable') { - accessKey = object.accessKey.id.lexeme; - } else if (object.accessKey.type === 'string') { - accessKey = object.accessKey.value.string; - } else if (object.accessKey.value && object.accessKey.value.lexeme) { - accessKey = object.accessKey.value.lexeme; - } else { - debug.stack(object); - } - let current = object.id.inferred; - let call = new GrammerCall('key'); - call.addPath({ type: 'object', name: object.id.lexeme }); - if (object.propertyPathTypes) { - for (let i = 0; i < object.propertyPath.length; i++) { - if (current.type === 'model') { - call.type = 'prop'; - call.addPath({ type: 'prop', name: object.propertyPath[i].lexeme }); - } else if (current.type === 'array') { - call.addPath({ type: 'list', name: object.propertyPath[i].lexeme }); - } else { - call.addPath({ type: 'map', name: object.propertyPath[i].lexeme }); - } - current = object.propertyPathTypes[i]; - } - } - call.addPath({ type: 'map', name: accessKey }); - if (object.inferred) { - call.returnType = this.resolveTypeItem(object.inferred); - } - valGrammer.value = call; - } else if (object.type === 'array_access') { - valGrammer.type = 'call'; - let accessKey; - if (object.accessKey.inferred) { - accessKey = this.renderGrammerValue(null, object.accessKey); - } else if (object.accessKey.type === 'number') { - accessKey = object.accessKey.value.value; - } else if (object.accessKey.type === 'variable') { - accessKey = object.accessKey.id.lexeme; - } else { - debug.stack(object); - } - let current = object.id.inferred; - let call = new GrammerCall('key'); - call.addPath({ type: 'object', name: object.id.lexeme }); - if (object.propertyPathTypes) { - for (let i = 0; i < object.propertyPath.length; i++) { - if (current.type === 'model') { - call.type = 'prop'; - call.addPath({ type: 'prop', name: object.propertyPath[i].lexeme }); - } else if (current.type === 'array') { - call.addPath({ type: 'list', name: object.propertyPath[i].lexeme }); - } else { - call.addPath({ type: 'map', name: object.propertyPath[i].lexeme }); - } - current = object.propertyPathTypes[i]; - } - } - call.addPath({ type: 'list', name: accessKey, isVar: object.accessKey.type === 'variable' }); - if (object.inferred) { - call.returnType = this.resolveTypeItem(object.inferred); - } - valGrammer.value = call; - } else if (['and', 'or', 'not'].indexOf(object.type) > -1) { - valGrammer.type = 'expr'; - valGrammer.value = this.visitIfConfition(object); - } else { - debug.stack('unimpelemented : ' + object.type, object); - } - if (object.inferred) { - valGrammer.dataType = this.resolveTypeItem(object.inferred); - } - - return valGrammer; - } - - visitStmt(obj, stmt, belong) { - let node; - let renderByGrammerValueTypes = [ - 'construct_model', - 'property_access', - 'map_access', - 'boolean', - 'super', - 'not', - ]; - if (renderByGrammerValueTypes.indexOf(stmt.type) > -1) { - node = this.renderGrammerValue(null, stmt); - } else if (stmt.type === 'declare') { - let type = null; - if (stmt.expectedType) { - type = this.resolveTypeItem(stmt.expectedType); - } else if (stmt.expr.inferred) { - type = this.resolveTypeItem(stmt.expr.inferred); - } else { - debug.stack(stmt); - } - let expectedType = stmt.expectedType ? stmt.expectedType : null; - assert.strictEqual(true, type instanceof TypeItem); - let variate = new GrammerVar(stmt.id.lexeme, type); - let value = this.renderGrammerValue(null, stmt.expr, expectedType); - node = new GrammerExpr(variate, Symbol.assign(), value); - } else if (stmt.type === 'requestAssign') { - let variate = new GrammerCall('prop', [ - { type: 'object', name: this.config.request }, - { type: 'prop', name: stmt.left.id.lexeme } - ]); - let value = this.renderGrammerValue(null, stmt.expr); - if (stmt.left.type === 'request_property_assign') { - let key = ''; - stmt.left.propertyPath.forEach((p, i) => { - if (i === stmt.left.propertyPath.length - 1) { - key = p.lexeme; - } else { - variate.addPath({ type: 'map', name: p.lexeme }); - } - }); - node = new BehaviorSetMapItem(variate, key, value); - } else { - node = new GrammerExpr(variate, Symbol.assign(), value); - } - } else if (stmt.type === 'ifRequestAssign' || stmt.type === 'if') { - node = this.visitIfElse(stmt, 'if'); - } else if (stmt.type === 'elseIfRequestAssign') { - node = this.visitIfElse(stmt, 'elseif'); - } else if (stmt.type === 'return') { - node = new GrammerReturn(); - if (typeof stmt.expr === 'undefined') { - node.type = 'null'; - } else if (stmt.expr.type === 'null') { - node.type = 'null'; - } else if (stmt.expr.type === 'call') { - let val = this.renderGrammerValue(null, stmt.expr); - node.expr = val; - node.type = 'grammer'; - } else if (_isBasicType(stmt.expr.type)) { - node.type = stmt.expr.type; - node.expr = this.renderGrammerValue(null, stmt.expr); - } else { - node.expr = this.renderGrammerValue(null, stmt.expr); - node.type = 'grammer'; - } - if (stmt.expectedType && stmt.expectedType.type === 'model') { - node.expr = new BehaviorToModel(node.expr, stmt.expectedType.name); - } - } else if (stmt.type === 'throw') { - this.currThrows['$Error'] = errorType; - node = new GrammerThrows(errorType); - if (Array.isArray(stmt.expr)) { - stmt.expr.forEach(e => { - node.addParam(this.renderGrammerValue(null, e)); - }); - } else { - node.addParam(this.renderGrammerValue(null, stmt.expr)); - } - } else if (stmt.type === 'virtualCall') { - let val = this.renderGrammerValue(null, stmt); - node = val.value; - } else if (stmt.type === 'while') { - node = new GrammerCondition('while'); - if (Array.isArray(stmt.condition)) { - stmt.condition.forEach(c => { - node.addCondition(this.renderGrammerValue(null, c)); - }); - } else { - node.addCondition(this.renderGrammerValue(null, stmt.condition)); - } - if (stmt.stmts) { - stmt.stmts.stmts.forEach(s => { - this.visitStmt(node, s, node.index); - }); - } - } else if (stmt.type === 'for') { - node = new GrammerLoop('foreach'); - node.item = new GrammerVar(stmt.id.lexeme, this.resolveTypeItem(stmt.list.inferred.itemType)); - node.source = this.renderGrammerValue(null, stmt.list); - if (stmt.stmts) { - stmt.stmts.stmts.forEach(s => { - this.visitStmt(node, s, node.index); - }); - } - } else if (stmt.type === 'assign') { - let hasMapAccess = false; - const right = this.renderGrammerValue(null, stmt.expr); - if (stmt.left.type === 'property') { - hasMapAccess = stmt.left.propertyPathTypes.some(item => item.type === 'map'); - if (hasMapAccess) { - const grammerValue = this.renderGrammerValue(null, stmt.left); - const call = grammerValue.value; - let lastIndex = 0; - for (let i = 0; i < stmt.left.propertyPathTypes.length; i++) { - const propertyPathType = stmt.left.propertyPathTypes[i]; - if (propertyPathType.type === 'map') { - lastIndex = i; - break; - } - } - if (lastIndex + 1 < stmt.left.propertyPathTypes.length) { - call.type = 'prop'; - call.path = call.path.splice(0, lastIndex + 2); - const key = stmt.left.propertyPath[lastIndex + 1].lexeme; - node = new BehaviorSetMapItem(call, key, right); - } else { - hasMapAccess = false; - } - } - } else if (stmt.left.type === 'map_access') { - hasMapAccess = true; - const grammerValue = this.renderGrammerValue(null, stmt.left); - const call = grammerValue.value; - call.type = 'prop'; - call.path = call.path.splice(0, call.path.length - 1); - node = new BehaviorSetMapItem(call, this.renderGrammerValue(null, stmt.left.accessKey), right); - } - - if (!hasMapAccess) { - const left = this.renderGrammerValue(null, stmt.left); - let isBehavior = false; - if (left.type === 'call' && left.value instanceof GrammerCall && left.value.type === 'key') { - const keyPath = left.value.path[left.value.path.length - 1]; - if (keyPath.type === 'map') { - left.value.path = left.value.path.slice(0, left.value.path.length - 1); - node = new BehaviorSetMapItem(left.value, keyPath.name, right); - isBehavior = true; - } - } - if (!isBehavior) { - node = new GrammerExpr( - left, - Symbol.assign(), - right - ); - } - } - } else if (stmt.type === 'call') { - node = this.renderGrammerValue(null, stmt).value; - } else if (stmt.type === 'break') { - node = new GrammerBreak(); - } else if (stmt.type === 'retry') { - node = new BehaviorRetry(); - } else if (stmt.type === 'try') { - const tryGram = new GrammerTryCatch(); - stmt.tryBlock.stmts.forEach(item => { - this.visitStmt(tryGram, item, tryGram.index); - }); - if (stmt.catchId) { - const exceptionGram = new GrammerException( - exceptionType, - new GrammerVar(stmt.catchId.lexeme, exceptionType) - ); - const catchGram = new GrammerCatch([], exceptionGram); - - if (stmt.catchBlock) { - stmt.catchBlock.stmts.forEach(item => { - this.visitStmt(catchGram, item, catchGram.index); - }); - } - tryGram.addCatch(catchGram); - } - if (stmt.finallyBlock) { - const finallyGram = new GrammerFinally(); - stmt.finallyBlock.stmts.forEach(item => { - this.visitStmt(finallyGram, item, finallyGram.index); - }); - tryGram.setFinally(finallyGram); - } - node = tryGram; - } else { - debug.stack(stmt); - } - if (belong) { - node.belong = belong; - } - this.findComments(obj, stmt, belong); - obj.addBodyNode(node); - this.findComments(obj, stmt, belong, 'back'); - } - - visitIfConfition(stmtCondition) { - let condition; - if (stmtCondition.left) { - let opt; - let optList = ['and', 'or', 'not']; - if (optList.indexOf(stmtCondition.type) > -1) { - switch (stmtCondition.type) { - case 'and': opt = Symbol.and(); break; - case 'or': opt = Symbol.or(); break; - case 'not': opt = Symbol.not(); break; - } - condition = new GrammerExpr( - this.renderGrammerValue(null, stmtCondition.left), - opt, - this.renderGrammerValue(null, stmtCondition.right) - ); - } else if (stmtCondition.type === 'call') { - condition = this.renderGrammerValue(null, stmtCondition); - } else { - debug.stack(stmtCondition); - } - } else { - condition = this.renderGrammerValue(null, stmtCondition); - } - return condition; - } - - visitIfElse(stmt, type = 'if') { - let node = new GrammerCondition(type); - if (stmt.condition) { - node.addCondition(this.visitIfConfition(stmt.condition)); - } - if (stmt.stmts) { - if (stmt.stmts.type && stmt.stmts.type === 'stmts') { - if (stmt.stmts.stmts.length > 0) { - stmt.stmts.stmts.forEach(item => { - this.visitStmt(node, item, node.index); - }); - } else { - this.findComments(node, stmt.stmts, 'between'); - } - } else if (stmt.type && stmt.type === 'stmts') { - if (stmt.stmts.length > 0) { - stmt.stmts.forEach(item => { - this.visitStmt(node, item, node.index); - }); - } else { - this.findComments(node, stmt, 'between'); - } - } else { - debug.stack(stmt); - } - } else { - debug.stack(stmt); - } - - if (stmt.elseIfs) { - stmt.elseIfs.forEach(elseIf => { - node.addElse(this.visitIfElse(elseIf, 'elseif')); - }); - } - - if (stmt.elseStmts) { - node.addElse(this.visitIfElse(stmt.elseStmts, 'else')); - } - - if (stmt.elseAssigns) { - stmt.elseAssigns.forEach(elseAssign => { - node.elseItem.push(this.visitIfElse(elseAssign, 'else')); - }); - } - - return node; - } -} - -module.exports = ClientResolver; diff --git a/src/resolver/model.js b/src/resolver/model.js deleted file mode 100644 index 0c45100..0000000 --- a/src/resolver/model.js +++ /dev/null @@ -1,133 +0,0 @@ -'use strict'; - -// eslint-disable-next-line no-unused-vars -const debug = require('../lib/debug'); -const assert = require('assert'); -const BaseResolver = require('./base'); - -const { - ObjectItem, - AnnotationItem, - PropItem, - NoteItem, -} = require('../langs/common/items'); - -const { - Modify, -} = require('../langs/common/enum'); - -class ModelResolver extends BaseResolver { - constructor(astNode, combinator, globalAst) { - super(astNode, combinator, globalAst); - this.object = new ObjectItem('model'); - } - - resolve() { - const object = this.object; - const combinator = this.combinator; - const config = this.config; - const ast = this.ast; - - assert.strictEqual(ast.type, 'model'); - - combinator.config.emitType = 'model'; - - object.name = ast.modelName.lexeme; - if (config.modelDirName) { - config.model.dir = config.modelDirName; - } - config.layer = config.model.dir; - - if (ast.annotation) { - this.initAnnotation(ast.annotation); - } - - object.topAnnotation.push(new AnnotationItem( - object.index, - 'single', - config.generateFileInfo - )); - - object.addExtends(combinator.addInclude('$Model')); - - this.initProp(ast.modelBody.nodes); - if (ast.modelBody.nodes.length === 0) { - if (ast.tokenRange) { - this.resolveAnnotations( - this.getBetweenComments(ast.tokenRange[0], ast.tokenRange[1]), - object.index - ).forEach(c => { - object.addBodyNode(c); - }); - } - } - - return object; - } - - initProp(nodes) { - const object = this.object; - - for (let i = 0; i < nodes.length; i++) { - const node = nodes[i]; - const prop = new PropItem(); - prop.belong = object.index; - prop.name = node.fieldName.lexeme; - prop.type = this.resolveTypeItem(node.fieldValue, node); - prop.modify.push(Modify.public()); - if (node.required) { - prop.addNote(new NoteItem('required', true)); - } - if (node.tokenRange) { - let annotations = this.resolveAnnotations( - this.getFrontComments(node.tokenRange[0]), - object.index - ); - annotations.forEach(c => { - object.addBodyNode(c); - }); - } - for (let i = 0; i < node.attrs.length; i++) { - const attr = node.attrs[i]; - let value; - if (typeof attr.attrValue.string !== 'undefined') { - value = attr.attrValue.string; - } else if (typeof attr.attrValue.value !== 'undefined') { - value = attr.attrValue.value; - } else if (typeof attr.attrValue.lexeme !== 'undefined') { - value = attr.attrValue.lexeme; - } - let note = new NoteItem( - attr.attrName.lexeme, - value - ); - prop.addNote(note); - } - object.addBodyNode(prop); - } - if (nodes[nodes.length - 1] && nodes[nodes.length - 1].tokenRange) { - let annotations = this.resolveAnnotations( - this.getBackComments(nodes[nodes.length - 1].tokenRange[1]), - object.index - ); - annotations.forEach(c => { - object.addBodyNode(c); - }); - } - } - - findSubModelsUsed(node, subModelUsed = [], pre = '') { - let name = node.fieldName.lexeme; - if (pre !== '') { - name = pre + '.' + name; - } - subModelUsed.push(name); - node.fieldValue.nodes.forEach(item => { - if (typeof item.fieldValue.fieldType === 'undefined') { - this.findSubModelsUsed(item, subModelUsed, name); - } - }); - } -} - -module.exports = ModelResolver; diff --git a/src/langs/php/files/.gitignore.tmpl b/templates/.gitignore.tmpl similarity index 100% rename from src/langs/php/files/.gitignore.tmpl rename to templates/.gitignore.tmpl diff --git a/src/langs/php/files/.php_cs.dist.tmpl b/templates/.php_cs.dist.tmpl similarity index 100% rename from src/langs/php/files/.php_cs.dist.tmpl rename to templates/.php_cs.dist.tmpl diff --git a/src/langs/php/files/autoload.php.tmpl b/templates/autoload.php.tmpl similarity index 100% rename from src/langs/php/files/autoload.php.tmpl rename to templates/autoload.php.tmpl diff --git a/src/langs/php/files/bootstrap.php.tmpl b/templates/bootstrap.php.tmpl similarity index 100% rename from src/langs/php/files/bootstrap.php.tmpl rename to templates/bootstrap.php.tmpl diff --git a/tests/common.tests.js b/tests/common.tests.js deleted file mode 100644 index b49dc34..0000000 --- a/tests/common.tests.js +++ /dev/null @@ -1,270 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const mm = require('mm'); -const expect = require('chai').expect; -require('mocha-sinon'); - -const { - Symbol, - Modify -} = require('../src/langs/common/enum'); - -const { - Counter, - Grammer, - GrammerCall, - GrammerValue, - GrammerSymbol, - GrammerThrows, - GrammerNewLine, - GrammerCondition, - NoteItem, - ObjectItem, - TypeObject, -} = require('../src/langs/common/items'); - -const PackageInfo = require('../src/langs/common/package_info'); - -const Combinator = require('../src/langs/common/combinator'); -const Emitter = require('../src/lib/emitter'); - -describe('common : enum should be ok', function () { - beforeEach(function () { - this.sinon.stub(console, 'log'); - }); - - it('enum should be ok', function () { - // test Symbol enum - expect(Symbol.eq()).to.be.eql('EQ'); - expect(Symbol.not()).to.be.eql('NOT'); - expect(Symbol.multi()).to.be.eql('MULTI'); - expect(Symbol.div()).to.be.eql('DIV'); - expect(Symbol.power()).to.be.eql('POWER'); - expect(Symbol.greaterEq()).to.be.eql('GREATER_EQ'); - expect(Symbol.less()).to.be.eql('LESS'); - expect(Symbol.lessEq()).to.be.eql('LESS_EQ'); - expect(Symbol.judge()).to.be.eql('JUDGE'); - expect(Symbol.risk()).to.be.eql('RISK'); - - // test Modify enum - expect(Modify.private()).to.be.eql('PRIVATE'); - expect(Modify.internal()).to.be.eql('INTERNAL'); - expect(Modify.final()).to.be.eql('FINAL'); - expect(Modify.abstract()).to.be.eql('ABSTRACT'); - }); -}); - -describe('common : counter should be ok', function () { - beforeEach(function () { - this.sinon.stub(console, 'log'); - }); - - it('counter should be ok', function () { - const counter = new Counter(-2); - expect(counter.index).to.be.eql(-2); - counter.step(2, 10); - expect(counter.index).to.be.eql(18); - counter.once(); - expect(counter.index).to.be.eql(19); - }); -}); - -describe('common : items should be ok', function () { - beforeEach(function () { - this.sinon.stub(console, 'log'); - }); - - it('items : Item.getItemByIndex&getParent should be ok', function () { - const parentGrammer = new Grammer(); - const childGrammer = new GrammerNewLine(); - const childGrammer2 = new GrammerSymbol(); - childGrammer.belong = parentGrammer.index; - childGrammer2.belong = parentGrammer.index; - - expect(function () { - childGrammer.getItemByIndex(-100); - }).to.be.throw('Index [-100] not exist in ItemSet'); - - expect(childGrammer.getItemByIndex(parentGrammer.index)).to.be.eql(parentGrammer); - expect(childGrammer.getParent()).to.be.eql(parentGrammer); - expect(childGrammer2.getParent()).to.be.eql(parentGrammer); - }); - - it('items : GrammerCall.addPath should be ok', function () { - const call = new GrammerCall(); - expect(function () { - call.addPath({ type: 'invalid-type' }); - }).to.be.throw('invalid-type path.type should be parent|object|object_static|call|call_static|prop|prop_static|map|list'); - }); - - it('items : NoteItem should be ok', function () { - let noteItem = new NoteItem('', null); - expect(noteItem.type).to.be.eql('null'); - expect(function () { - noteItem = new NoteItem('', {}); - }).to.be.throw('Not suppoted type : object [number,string,boolean]'); - }); - - it('items : ObjectItem should be ok', function () { - const objectItem = new ObjectItem('client'); - expect(function () { - objectItem.addBodyNode(null); - }).to.be.throw('Only suppoted PropItem | FuncItem | ObjectItem | AnnotationItem | ConstructItem'); - objectItem.addModify(Modify.private()); - expect(objectItem.modify.indexOf('PRIVATE') !== -1).to.be.true; - }); -}); - -describe('package_info should be ok', function () { - beforeEach(function () { - this.sinon.stub(console, 'log'); - }); - - it('package_info : checkParams should be ok', function () { - const packageInfo = new PackageInfo(); - const param = { key: 'value' }; - packageInfo.checkParams(param); - try { - packageInfo.checkParams(param, ['someRequeiredKey']); - } catch (e) { - expect(e.message).to.be.eql('need config packageInfo.someRequeiredKey'); - expect(console.log.calledWith(param)).to.be.true; - } - }); - - it('package_info : renderAuto should be ok', function () { - const packageInfo = new PackageInfo(); - mm(fs, 'readFileSync', function (filename) { - return '${key}'; - }); - mm(fs, 'existsSync', function (filename) { - return true; - }); - mm(fs, 'writeFileSync', function (filename, content) { - return true; - }); - // not throw exception - packageInfo.renderAuto('/tmp/template-file-path.tmpl', '/tmp/target-path.tmp', { key: 'RenderAutoKey' }); - - mm(fs, 'existsSync', function (filename) { - return false; - }); - mm(fs, 'mkdirSync', function (filename) { - return true; - }); - // not throw exception - packageInfo.renderAuto('/tmp/template-file-path.tmpl', '/tmp/target-path.tmp', { key: 'RenderAutoKey' }); - }); - - it('package_info : resolveOutputDir should be ok', function () { - const packageInfo = new PackageInfo(); - packageInfo.config = { dir: '/tmp/' }; - expect(packageInfo.resolveOutputDir({ outputDir: null }, './')).to.be.eql('/tmp/'); - - mm(fs, 'existsSync', function (filename) { - return false; - }); - expect(packageInfo.resolveOutputDir({ outputDir: 'output/' }, './')).to.be.eql('/tmp/output/'); - mm.restore(); - }); -}); - -describe('combinator should be ok', function () { - beforeEach(function () { - this.sinon.stub(console, 'log'); - }); - - it('combine should be ok', function () { - const combinator = new Combinator({ tea: {} }); - expect(function () { - combinator.combine([new ObjectItem('client'), 'not ObjectItem']); - }).to.be.throw('Only supported ObjectItem.'); - }); - - it('coreClass should be ok', function () { - const combinator = new Combinator({ tea: {} }); - expect(function () { - combinator.coreClass('test'); - }).to.be.throw('Unsupported core class name : test'); - }); - - it('combinator : findThrows should be ok', function () { - const combinator = new Combinator(); - const grammer = new GrammerCondition(); - expect(combinator.findThrows(grammer).length).to.be.eql(0); - grammer.addBodyNode(new GrammerThrows(new TypeObject('exception'))); - expect(combinator.findThrows(grammer).length).to.be.eql(1); - const childGrammer = new GrammerCondition(); - childGrammer.addBodyNode(new GrammerThrows(new TypeObject('exception'))); - grammer.addBodyNode(childGrammer); - expect(combinator.findThrows(grammer).length).to.be.eql(2); - }); - - it('combinator : unimpelemented should be ok', function () { - const combinator = new Combinator(); - expect(function () { - combinator.init({}); - }).to.be.throw('unimpelemented'); - expect(function () { - combinator.addModelInclude('foo'); - }).to.be.throw('unimpelemented'); - expect(function () { - combinator.addInclude('foo'); - }).to.be.throw('unimpelemented'); - }); - - it('combinator : systemfunc should be ok', function () { - const combinator = new Combinator(); - const emitter = new Emitter(); - const gram = new GrammerCall(); - expect(function () { - combinator.systemfunc(emitter, gram); - }).to.be.throw('Invalid path. path list cannot be empty.'); - gram.addPath({ type: 'call', name: 'test' }); - expect(function () { - combinator.systemfunc(emitter, gram); - }).to.be.throw('unimpelemented sysTest(emitter, gram){} method\n'); - - combinator.sysTest = function () { - console.log('test call combinator.sysTest'); - return true; - }; - combinator.systemfunc(emitter, gram); - expect(console.log.calledWith('test call combinator.sysTest')).to.be.true; - }); - - it('combinator : grammerNewLine should be ok', function () { - const combinator = new Combinator(); - const emitter = new Emitter(); - emitter.output = ''; - const grammerNewLine = new GrammerNewLine(2); - combinator.grammerNewLine(emitter, grammerNewLine); - expect(emitter.output).to.be.eql(emitter.eol + emitter.eol); - }); - - it('combinator : emitGrammerValue should be ok', function () { - const combinator = new Combinator(); - combinator.grammerValue = function (emitter) { - emitter.emit('test'); - }; - const grammerValue = new GrammerValue(); - expect(combinator.emitGrammerValue(grammerValue)).to.be.eql('test'); - }); - - it('combinator : grammer should be ok', function () { - const combinator = new Combinator(); - const emitter = new Emitter(); - - emitter.output = ''; - const obj = new ObjectItem('client'); - expect(function () { - combinator.grammer(emitter, obj); - }).to.be.throw('Unsupported'); - expect(console.log.calledWith(obj)).to.be.true; - - expect(function () { - combinator.grammer(emitter, new GrammerCondition()); - }).to.be.throw('Unimpelemented : grammerCondition'); - }); -}); diff --git a/tests/expected/alias/Client.php b/tests/expected/alias/Client.php index e91aac2..ee58823 100644 --- a/tests/expected/alias/Client.php +++ b/tests/expected/alias/Client.php @@ -1,18 +1,22 @@ 0) { - $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); - if ($_backoffTime > 0) { - Tea::sleep($_backoffTime); - } - } - $_retryTimes = $_retryTimes + 1; - try { - $_request = new Request(); - $_lastRequest = $_request; - $_response= Tea::send($_request, $_runtime); - return null; - } - catch (Exception $e) { - if (!($e instanceof TeaError)) { - $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); - } - if (Tea::isRetryable($e)) { - $_lastException = $e; - continue; - } - throw $e; - } + /** + * @remarks + * testAPI + * @return void + */ + public function testAPI() + { + $_runtime = [ ]; + + $_retriesAttempted = 0; + $_lastRequest = null; + $_lastResponse = null; + $_context = new RetryPolicyContext([ + 'retriesAttempted' => $_retriesAttempted, + ]); + while (Dara::shouldRetry($_runtime['retryOptions'], $_context)) { + if ($_retriesAttempted > 0) { + $_backoffTime = Dara::getBackoffDelay($_runtime['retryOptions'], $_context); + if ($_backoffTime > 0) { + Dara::sleep($_backoffTime); } - throw new TeaUnableRetryError($_lastRequest, $_lastException); - } + } - /** - * testFunc - * @return void - */ - public static function testFunc(){ + $_retriesAttempted++; + try { + $_request = new Request(); + $_response = Dara::send($_request, $_runtime); + $_lastRequest = $_request; + $_lastResponse = $_response; + + return null; + } catch (DaraException $e) { + $_context = new RetryPolicyContext([ + 'retriesAttempted' => $_retriesAttempted, + 'lastRequest' => $_lastRequest, + 'lastResponse' => $_lastResponse, + 'exception' => $e, + ]); + continue; + } } + + throw DaraUnableRetryException($_context); + } + + /** + * @remarks + * testFunc + * @return void + */ + static public function testFunc() + { + } + } diff --git a/tests/expected/annotation/Models/Test.php b/tests/expected/annotation/Models/Test.php index a9d1052..bc71e6b 100644 --- a/tests/expected/annotation/Models/Test.php +++ b/tests/expected/annotation/Models/Test.php @@ -1,42 +1,53 @@ 'test', - ]; - public function validate() { - Model::validateRequired('test', $this->test, true); - } - public function toMap() { - $res = []; - if (null !== $this->test) { - $res['test'] = $this->test; - } - return $res; + /** + * @var string + */ + public $test; + protected $_name = [ + 'test' => 'test', + ]; + + public function validate() + { + Model::validateRequired('test', $this->test, true); + parent::validate(); + } + + public function toArray($noStream = false) + { + $res = []; + if (null !== $this->test) { + $res['test'] = $this->test; } - /** - * @param array $map - * @return Test - */ - public static function fromMap($map = []) { - $model = new self(); - if(isset($map['test'])){ - $model->test = $map['test']; - } - return $model; + + return $res; + } + + public function toMap($noStream = false) + { + return $this->toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + if (isset($map['test'])) { + $model->test = $map['test']; } - /** - * @description Alichange app id - * @var string - */ - public $test; + + return $model; + } + } + diff --git a/tests/expected/api/Client.php b/tests/expected/api/Client.php index 49f769a..8e365c5 100644 --- a/tests/expected/api/Client.php +++ b/tests/expected/api/Client.php @@ -1,73 +1,78 @@ method = 'GET'; + $_reqeust->pathname = '/'; + $_reqeust->headers = [ + 'host' => 'www.test.com', + ]; + $_response = Dara::send($_request); -class Client { + return null; + } + + /** + * @return void + */ + public function helloRuntime() + { + $_runtime = [ ]; + + $_retriesAttempted = 0; + $_lastRequest = null; + $_lastResponse = null; + $_context = new RetryPolicyContext([ + 'retriesAttempted' => $_retriesAttempted, + ]); + while (Dara::shouldRetry($_runtime['retryOptions'], $_context)) { + if ($_retriesAttempted > 0) { + $_backoffTime = Dara::getBackoffDelay($_runtime['retryOptions'], $_context); + if ($_backoffTime > 0) { + Dara::sleep($_backoffTime); + } + } - /** - * @return void - */ - public function hello(){ + $_retriesAttempted++; + try { $_request = new Request(); - $_request->method = "GET"; - $_request->pathname = "/"; - $_request->headers = [ - "host" => "www.test.com" + $_reqeust->method = 'GET'; + $_reqeust->pathname = '/'; + $_reqeust->headers = [ + 'host' => 'www.test.com', ]; + $_response = Dara::send($_request, $_runtime); $_lastRequest = $_request; - $_response= Tea::send($_request); + $_lastResponse = $_response; + return null; + } catch (DaraException $e) { + $_context = new RetryPolicyContext([ + 'retriesAttempted' => $_retriesAttempted, + 'lastRequest' => $_lastRequest, + 'lastResponse' => $_lastResponse, + 'exception' => $e, + ]); + continue; + } } - /** - * @return void - * @throws TeaError - * @throws Exception - * @throws TeaUnableRetryError - */ - public function helloRuntime(){ - $_runtime = []; - $_lastRequest = null; - $_lastException = null; - $_now = time(); - $_retryTimes = 0; - while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { - if ($_retryTimes > 0) { - $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); - if ($_backoffTime > 0) { - Tea::sleep($_backoffTime); - } - } - $_retryTimes = $_retryTimes + 1; - try { - $_request = new Request(); - $_request->method = "GET"; - $_request->pathname = "/"; - $_request->headers = [ - "host" => "www.test.com" - ]; - $_lastRequest = $_request; - $_response= Tea::send($_request, $_runtime); - return null; - } - catch (Exception $e) { - if (!($e instanceof TeaError)) { - $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); - } - if (Tea::isRetryable($e)) { - $_lastException = $e; - continue; - } - throw $e; - } - } - throw new TeaUnableRetryError($_lastRequest, $_lastException); - } + throw DaraUnableRetryException($_context); + } + + } diff --git a/tests/expected/builtin/Client.php b/tests/expected/builtin/Client.php new file mode 100644 index 0000000..e6e1466 --- /dev/null +++ b/tests/expected/builtin/Client.php @@ -0,0 +1,433 @@ + 0) && \in_array('cn-hanghzou', $args)) { + $index = array_search('cn-hanghzou', $args); + $regionId = $args[$index]; + $all = implode(',', $args); + $first = array_shift($args); + $last = array_pop($args); + $length1 = array_unshift($args, $first); + $length2 = array_pop($args, $last); + $length3 = $length1 + $length2; + $longStr = 'long' . $first . $last; + $fullStr = implode(',', $args); + $newArr = [ + 'test' + ]; + $cArr = array_merge($args, $newArr); + $acsArr = sort($newArr); + $descArr = rsort($newArr); + $llArr = array_merge($descArr, $acsArr); + array_splice($llArr, 10, 0, 'test'); + array_splice($llArr, array_search('test', $llArr), 1); + } + + } + + /** + * @param string[] $args + * @return void + */ + static public function bytesTest($args) + { + $fullStr = implode(',', $args); + $data = StringUtil::toBytes($fullStr, 'utf8'); + $newFullStr = BytesUtil::toString($data); + if ($fullStr != $newFullStr) { + return null; + } + + $hexStr = bin2hex(BytesUtil::toString($data)); + $base64Str = base64_encode(BytesUtil::toString($data)); + $length = strlen($data); + $obj = BytesUtil::toString($data); + $data2 = BytesUtil::from($fullStr, 'base64'); + } + + /** + * @param string[] $args + * @return void + */ + static public function dateTest($args) + { + $date = new Date('2023-09-12 17:47:31.916000 +0800 UTC'); + $dateStr = $date->format('YYYY-MM-DD HH:mm:ss'); + $timestamp = $date->unix(); + $yesterday = $date->sub('day', 1); + $oneDay = $date->diff('day', $yesterday); + $tomorrow = $date->add('day', 1); + $twoDay = $tomorrow->diff('day', $date) + $oneDay; + $hour = $date->hour(); + $minute = $date->minute(); + $second = $date->second(); + $dayOfMonth = $date->dayOfMonth(); + $dayOfWeek = $date->dayOfWeek(); + $weekOfYear = $date->weekOfYear(); + $month = $date->month(); + $year = $date->year(); + } + + /** + * @param string[] $args + * @return void + */ + static public function envTest($args) + { + $es = getenv('TEST'); + $ma = putenv('TEST='.$es . 'test'); + $ma1 = putenv('TEST1=test1'); + $ma2 = putenv('TEST2='.$es); + } + + /** + * @param string[] $args + * @return void + */ + static public function fileTest($args) + { + if (File::exists('/tmp/test')) { + $file = new File('/tmp/test'); + $path = $file->path(); + $length = $file->length() + 10; + $createTime = $file->createTime(); + $modifyTime = $file->modifyTime(); + $timeLong = $modifyTime->diff('minute', $createTime); + $data = $file->read(300); + $file->write(BytesUtil::from('test', 'utf8')); + $rs = File::createReadStream('/tmp/test'); + $ws = File::createWriteStream('/tmp/test'); + } + + } + + /** + * @param string[] $args + * @return void + */ + static public function formTest($args) + { + $m = [ + 'key1' => 'test1', + 'key2' => 'test2', + 'key3' => 3, + 'key4' => [ + 'key5' => 123, + 'key6' => '321', + ], + ]; + $form = FormUtil::toFormString($m); + $form = $form . '&key7=23233&key8=' . FormUtil::getBoundary(); + $r = FormUtil::toFileForm($m, FormUtil::getBoundary()); + } + + /** + * @param string[] $args + * @return void + */ + static public function jsonTest($args) + { + $m = [ + 'key1' => 'test1', + 'key2' => 'test2', + 'key3' => 3, + 'key4' => [ + 'key5' => 123, + 'key6' => '321', + ], + ]; + $m1 = new M([ + 'a' => 'test', + ]); + $ms = json_encode($m, JSON_UNESCAPED_UNICODE + JSON_UNESCAPED_SLASHES); + $m1s = json_encode($m1->toArray(), JSON_UNESCAPED_UNICODE + JSON_UNESCAPED_SLASHES); + $ma = json_decode($ms, true); + $arrStr = '[1,2,3,4]'; + $arr = json_decode($arrStr, true); + } + + /** + * @param string[] $args + * @return void + */ + static public function logerTest($args) + { + Console::log('test'); + Console::info('test'); + Console::warning('test'); + Console::debug('test'); + Console::error('test'); + } + + /** + * @param string[] $args + * @return void + */ + static public function mapTestCase($args) + { + $mapTest = [ + 'key1' => 'value1', + 'key2' => 'value2', + 'key3' => 'value3', + ]; + $length = \count($mapTest); + $num = $length + 3; + $keys = array_keys($mapTest); + $allKey = ''; + + foreach($keys as $key) { + $allKey = $allKey . $key; + } + $entries = array_map(null, array_keys($mapTest), array_values($mapTest)); + $newKey = ''; + $newValue = ''; + + foreach($entries as $e) { + $newKey = $newKey . $e[0]; + $newValue = $newValue . $e[1]; + } + $json = json_encode($mapTest, JSON_UNESCAPED_UNICODE + JSON_UNESCAPED_SLASHES); + $mapTest2 = [ + 'key1' => 'value4', + 'key4' => 'value5', + ]; + $mapTest3 = array_merge($mapTest , $mapTest2); + if (@$mapTest3['key1'] == 'value4') { + return null; + } + + } + + /** + * @param string[] $args + * @return void + */ + static public function numberTest($args) + { + $num = 3.2; + $inum = intval(''.$num); + $lnum = intval(''.$num); + $fnum = floatval(''.$num); + $dnum = floatval(''.$num); + $inum = intval(''.$inum); + $lnum = intval(''.$inum); + $fnum = floatval(''.$inum); + $dnum = floatval(''.$inum); + $inum = intval(''.$lnum); + $lnum = intval(''.$lnum); + $fnum = floatval(''.$lnum); + $dnum = floatval(''.$lnum); + $inum = intval(''.$fnum); + $lnum = intval(''.$fnum); + $fnum = floatval(''.$fnum); + $dnum = floatval(''.$fnum); + $inum = intval(''.$dnum); + $lnum = intval(''.$dnum); + $fnum = floatval(''.$dnum); + $dnum = floatval(''.$dnum); + $lnum = $inum; + $inum = $lnum; + $randomNum = MathUtil::random(); + $inum = floor($inum); + $inum = round($inum); + $min = min($inum, $fnum); + $max = max($inum, $fnum); + } + + /** + * @param string[] $args + * @return void + */ + static public function streamTest($args) + { + if (File::exists('/tmp/test')) { + $rs = File::createReadStream('/tmp/test'); + $ws = File::createWriteStream('/tmp/test'); + $data = $rs->read(30); + $ws->write($data); + $rs->pipe($ws); + $data = StreamUtil::readAsBytes($rs); + $obj = StreamUtil::readAsJSON($rs); + $jsonStr = StreamUtil::readAsString($rs); + } + + } + + /** + * @param string[] $args + * @return void + */ + static public function stringTest($args) + { + $fullStr = implode(',', $args); + $args = explode($fullStr, ','); + if ((strlen($fullStr) > 0) && false !== strpos($fullStr, 'hangzhou')) { + $newStr1 = preg_replace('/hangzhou/g', 'beijing', $fullStr); + } + + if (StringUtil::hasPrefix($fullStr, 'cn')) { + $newStr2 = preg_replace('/cn/gi', 'zh', $fullStr); + } + + if (StringUtil::hasSuffix($fullStr, 'beijing')) { + $newStr3 = preg_replace('/beijing/', 'chengdu', $fullStr); + } + + $start = strpos($fullStr, 'beijing'); + $end = $start + 7; + $region = substr($fullStr, $start, $end); + $lowerRegion = strtolower($region); + $upperRegion = strtoupper($region); + if ($region === 'beijing') { + $region = $region . ' '; + $region = trim($region); + } + + $tb = StringUtil::toBytes($fullStr, 'utf8'); + $em = 'xxx'; + if (empty($em)) { + return null; + } + + $num = '32.0a'; + $inum = intval($num) + 3; + $lnum = intval($num); + $fnum = floatval($num) + 1; + $dnum = floatval($num) + 1; + } + + /** + * @param string[] $args + * @return void + */ + static public function urlTest($args) + { + $url = new URL(@$args[0]); + $path = $url->path(); + $pathname = $url->pathname(); + $protocol = $url->protocol(); + $hostname = $url->hostname(); + $port = $url->port(); + $host = $url->host(); + $hash = $url->hash(); + $search = $url->search(); + $href = $url->href(); + $auth = $url->auth(); + $url2 = URL::parse(@$args[1]); + $path = $url2->path(); + $newUrl = URL::urlEncode(@$args[2]); + $newSearch = URL::percentEncode($search); + $newPath = URL::pathEncode($pathname); + $all = 'test' . $path . $protocol . $hostname . $hash . $search . $href . $auth . $newUrl . $newSearch . $newPath; + } + + /** + * @param string[] $args + * @return void + */ + static public function xmlTest($args) + { + $m = [ + 'key1' => 'test1', + 'key2' => 'test2', + 'key3' => 3, + 'key4' => [ + 'key5' => 123, + 'key6' => '321', + ], + ]; + $xml = XML::toXML($m); + $xml = $xml . '132'; + $respMap = XML::parseXml($xml, null); + } + + /** + * @return mixed + */ + static public function returnAny() + { + throw new RuntimeException('Un-implemented!'); + } + + /** + * @param string[] $args + * @return void + */ + static public function main($args) + { + self::arrayTest($args); + self::bytesTest($args); + self::dateTest($args); + self::envTest($args); + self::fileTest($args); + self::formTest($args); + self::logerTest($args); + self::mapTestCase($args); + self::numberTest($args); + self::streamTest($args); + self::stringTest($args); + self::urlTest($args); + self::xmlTest($args); + $a = intval(@$args[0]) + 10; + $b = ''.$a . @$args[1] . ''.self::returnAny(); + $c = ($b + 0) + ($a + 0) + (self::returnAny() + 0); + $d = intval($b) + intval($a) + intval(self::returnAny()); + $e = intval($b) + intval($a) + intval(self::returnAny()); + $f = intval($b) + intval($a) + intval(self::returnAny()); + $g = intval($b) + intval($a) + intval(self::returnAny()); + $h = intval($b) + intval($a) + intval(self::returnAny()); + $i = intval($b) + intval($a) + intval(self::returnAny()); + $j = intval($b) + intval($a) + intval(self::returnAny()); + $k = intval($b) + intval($a) + intval(self::returnAny()); + $l = intval($b) + intval($a) + intval(self::returnAny()); + $m = intval($b) + intval($a) + intval(self::returnAny()); + $n = floatval($b) + floatval($a) + floatval(self::returnAny()); + $o = floatval($b) + floatval($a) + floatval(self::returnAny()); + if (boolval(@$args[2])) { + $data = unpack('C*', self::returnAny()); + $length = strlen($data); + $test = $data; + $maps = [ + 'key' => 'value', + ]; + $obj = $maps; + $ws = StreamUtil::streamFor($obj); + $rs = StreamUtil::streamFor($maps); + $data = $rs->read(30); + if (!is_null($data)) { + $ws->write($data); + } + + } + + usleep($a); + $defaultVal = ''.(@$args[0] ? @$args[0] : @$args[1]); + if ($defaultVal === $b) { + return null; + } + + } + +} diff --git a/tests/expected/comment/Client.php b/tests/expected/comment/Client.php index a9a2cb3..e5fb6d2 100644 --- a/tests/expected/comment/Client.php +++ b/tests/expected/comment/Client.php @@ -1,184 +1,208 @@ 'test', + //test declare back comment + 'test2' => 'test2', + //test2 declare back comment + ]); + $array = [ + // array string comment + 'string', + // array number comment + 300 + // array back comment + ]; + } + + //testAPI comment one + //testAPI comment two + /** + * @remarks + * testAPI + * @return void + */ + public function testAPI() + { + $_runtime = [ + // empty runtime comment + // another runtime comment + ]; + + $_retriesAttempted = 0; + $_lastRequest = null; + $_lastResponse = null; + $_context = new RetryPolicyContext([ + 'retriesAttempted' => $_retriesAttempted, + ]); + while (Dara::shouldRetry($_runtime['retryOptions'], $_context)) { + if ($_retriesAttempted > 0) { + $_backoffTime = Dara::getBackoffDelay($_runtime['retryOptions'], $_context); + if ($_backoffTime > 0) { + Dara::sleep($_backoffTime); + } + } + + $_retriesAttempted++; + try { + $_request = new Request(); // new model instance comment $modelInstance = new Test1([ - "test" => "test", - // test declare back comment - "test2" => "test2", - // test2 declare back comment + // test declare front comment + 'test' => 'test', + // test2 declare front comment + 'test2' => 'test2', + ]); + // number declare comment + $num = 123; + // static function call comment + self::staticFunc(); + $_response = Dara::send($_request, $_runtime); + $_lastRequest = $_request; + $_lastResponse = $_response; + + // static async function call + self::testFunc('test', true); + // return comment + return null; + } catch (DaraException $e) { + $_context = new RetryPolicyContext([ + 'retriesAttempted' => $_retriesAttempted, + 'lastRequest' => $_lastRequest, + 'lastResponse' => $_lastResponse, + 'exception' => $e, ]); - $array = [ - // array string comment - "string", - // array number comment - 300 - ]; + continue; + } } - /** - * testAPI - * testAPI comment one - * testAPI comment two - * @return void - * @throws TeaError - * @throws Exception - * @throws TeaUnableRetryError - */ - public function testAPI(){ - $_runtime = [ - // empty runtime comment - // another runtime comment - ]; - $_lastRequest = null; - $_lastException = null; - $_now = time(); - $_retryTimes = 0; - while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { - if ($_retryTimes > 0) { - $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); - if ($_backoffTime > 0) { - Tea::sleep($_backoffTime); - } - } - $_retryTimes = $_retryTimes + 1; - try { - $_request = new Request(); - // new model instance comment - $modelInstance = new Test1([ - // test declare front comment - "test" => "test", - // test2 declare front comment - "test2" => "test2" - ]); - // number declare comment - $num = 123; - // static function call comment - self::staticFunc(); - $_lastRequest = $_request; - $_response= Tea::send($_request, $_runtime); - // static async function call - self::testFunc("test", true); - // return comment - return null; - } - catch (Exception $e) { - if (!($e instanceof TeaError)) { - $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); - } - if (Tea::isRetryable($e)) { - $_lastException = $e; - continue; - } - throw $e; - } + throw DaraUnableRetryException($_context); + } + + // testAPI2 comment + /** + * @return void + */ + public function testAPI2() + { + $_runtime = [ + // runtime retry comment + 'retry' => true, + // runtime back comment one + // runtime back comment two + ]; + + $_retriesAttempted = 0; + $_lastRequest = null; + $_lastResponse = null; + $_context = new RetryPolicyContext([ + 'retriesAttempted' => $_retriesAttempted, + ]); + while (Dara::shouldRetry($_runtime['retryOptions'], $_context)) { + if ($_retriesAttempted > 0) { + $_backoffTime = Dara::getBackoffDelay($_runtime['retryOptions'], $_context); + if ($_backoffTime > 0) { + Dara::sleep($_backoffTime); } - throw new TeaUnableRetryError($_lastRequest, $_lastException); - } + } - /** - * testAPI2 comment - * @return void - * @throws TeaError - * @throws Exception - * @throws TeaUnableRetryError - */ - public function testAPI2(){ - $_runtime = [ - // runtime retry comment - "retry" => true, - // runtime back comment one - // runtime back comment two - ]; - $_lastRequest = null; - $_lastException = null; - $_now = time(); - $_retryTimes = 0; - while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { - if ($_retryTimes > 0) { - $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); - if ($_backoffTime > 0) { - Tea::sleep($_backoffTime); - } - } - $_retryTimes = $_retryTimes + 1; - try { - $_request = new Request(); - // new model instance comment - $modelInstance = new Test3([ - // empty model - ]); - // boolean declare comment - $bool = true; - if ($bool) { - // empty if - } - else { - // empty else - } - // api function call comment - $this->testAPI(); - $_lastRequest = $_request; - $_response= Tea::send($_request, $_runtime); - // empty return comment - // back comment - } - catch (Exception $e) { - if (!($e instanceof TeaError)) { - $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); - } - if (Tea::isRetryable($e)) { - $_lastException = $e; - continue; - } - throw $e; - } + $_retriesAttempted++; + try { + $_request = new Request(); + // new model instance comment + $modelInstance = new Test3([ + //empty model + ]); + // boolean declare comment + $bool = true; + if ($bool) { + + //empty if + } else { + //empty else + } - throw new TeaUnableRetryError($_lastRequest, $_lastException); - } - /** - * @return void - */ - public static function staticFunc(){ - $a = [ - // empty annotation comment - ]; - } + // api function call comment + $this->testAPI(); + // back comment + $_response = Dara::send($_request, $_runtime); + $_lastRequest = $_request; + $_lastResponse = $_response; - /** - * testFunc - * @param string $str description: string parameter - * @param bool $val description: boolean parameter - * @return void description for return - */ - public static function testFunc($str, $val){ - // empty comment1 - // empty comment2 + // empty return comment + } catch (DaraException $e) { + $_context = new RetryPolicyContext([ + 'retriesAttempted' => $_retriesAttempted, + 'lastRequest' => $_lastRequest, + 'lastResponse' => $_lastResponse, + 'exception' => $e, + ]); + continue; + } } + + throw DaraUnableRetryException($_context); + } + + /** + * @return void + */ + static public function staticFunc() + { + $a = [ + // empty annotation comment + ]; + } + + /** + * @remarks + * testFunc + * + * @param str - description: string parameter + * @param val - description: boolean parameter + * @returns description for return + * @param string $str + * @param boolean $val + * @return void + */ + static public function testFunc($str, $val) + { + // empty comment1 + // empty comment2 + } + } diff --git a/tests/expected/comment/Models/Test1.php b/tests/expected/comment/Models/Test1.php index 60e4662..43c4c71 100644 --- a/tests/expected/comment/Models/Test1.php +++ b/tests/expected/comment/Models/Test1.php @@ -1,59 +1,70 @@ 'test', - 'test2' => 'test2', - ]; - public function validate() { - Model::validateRequired('test', $this->test, true); - Model::validateRequired('test2', $this->test2, true); + /** + * @var string + */ + public $test; + //model的test back comment + /** + * @var string + */ + public $test2; + //model的test2 back comment + protected $_name = [ + 'test' => 'test', + 'test2' => 'test2', + ]; + + public function validate() + { + Model::validateRequired('test', $this->test, true); + Model::validateRequired('test2', $this->test2, true); + parent::validate(); + } + + public function toArray($noStream = false) + { + $res = []; + if (null !== $this->test) { + $res['test'] = $this->test; } - public function toMap() { - $res = []; - if (null !== $this->test) { - $res['test'] = $this->test; - } - if (null !== $this->test2) { - $res['test2'] = $this->test2; - } - return $res; + + if (null !== $this->test2) { + $res['test2'] = $this->test2; + } + + return $res; + } + + public function toMap($noStream = false) + { + return $this->toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + if (isset($map['test'])) { + $model->test = $map['test']; } - /** - * @param array $map - * @return Test1 - */ - public static function fromMap($map = []) { - $model = new self(); - if(isset($map['test'])){ - $model->test = $map['test']; - } - if(isset($map['test2'])){ - $model->test2 = $map['test2']; - } - return $model; + + if (isset($map['test2'])) { + $model->test2 = $map['test2']; } - /** - * @description test desc - * @var string - */ - public $test; - - // model的test back comment - /** - * @description test2 desc - * @deprecated - * @var string - */ - public $test2; - - // model的test2 back comment + + return $model; + } + + } + diff --git a/tests/expected/comment/Models/Test2.php b/tests/expected/comment/Models/Test2.php index 47eaf6f..4b8fcb7 100644 --- a/tests/expected/comment/Models/Test2.php +++ b/tests/expected/comment/Models/Test2.php @@ -1,58 +1,69 @@ 'test', - 'test2' => 'test2', - ]; - public function validate() { - Model::validateRequired('test', $this->test, true); - Model::validateRequired('test2', $this->test2, true); + // model的test front comment + /** + * @var string + */ + public $test; + // model的test2 front comment + /** + * @var string + */ + public $test2; + protected $_name = [ + 'test' => 'test', + 'test2' => 'test2', + ]; + + public function validate() + { + Model::validateRequired('test', $this->test, true); + Model::validateRequired('test2', $this->test2, true); + parent::validate(); + } + + public function toArray($noStream = false) + { + $res = []; + if (null !== $this->test) { + $res['test'] = $this->test; } - public function toMap() { - $res = []; - if (null !== $this->test) { - $res['test'] = $this->test; - } - if (null !== $this->test2) { - $res['test2'] = $this->test2; - } - return $res; + + if (null !== $this->test2) { + $res['test2'] = $this->test2; } - /** - * @param array $map - * @return Test2 - */ - public static function fromMap($map = []) { - $model = new self(); - if(isset($map['test'])){ - $model->test = $map['test']; - } - if(isset($map['test2'])){ - $model->test2 = $map['test2']; - } - return $model; + + return $res; + } + + public function toMap($noStream = false) + { + return $this->toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + if (isset($map['test'])) { + $model->test = $map['test']; + } + + if (isset($map['test2'])) { + $model->test2 = $map['test2']; } - // model的test front comment - /** - * @description test desc - * @var string - */ - public $test; - - // model的test front comment - /** - * @description test2 desc - * @var string - */ - public $test2; + + return $model; + } + } + diff --git a/tests/expected/comment/Models/Test3.php b/tests/expected/comment/Models/Test3.php index 480bb73..5b4fc90 100644 --- a/tests/expected/comment/Models/Test3.php +++ b/tests/expected/comment/Models/Test3.php @@ -1,60 +1,71 @@ 'test', - 'test1' => 'test1', - ]; - public function validate() { - Model::validateRequired('test', $this->test, true); - Model::validateRequired('test1', $this->test1, true); + // model的test front comment + /** + * @var string + */ + public $test; + // empty comment1 + // empy comment2 + /** + * @var string + */ + public $test1; + //model的test1 back comment + protected $_name = [ + 'test' => 'test', + 'test1' => 'test1', + ]; + + public function validate() + { + Model::validateRequired('test', $this->test, true); + Model::validateRequired('test1', $this->test1, true); + parent::validate(); + } + + public function toArray($noStream = false) + { + $res = []; + if (null !== $this->test) { + $res['test'] = $this->test; } - public function toMap() { - $res = []; - if (null !== $this->test) { - $res['test'] = $this->test; - } - if (null !== $this->test1) { - $res['test1'] = $this->test1; - } - return $res; + + if (null !== $this->test1) { + $res['test1'] = $this->test1; + } + + return $res; + } + + public function toMap($noStream = false) + { + return $this->toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + if (isset($map['test'])) { + $model->test = $map['test']; } - /** - * @param array $map - * @return Test3 - */ - public static function fromMap($map = []) { - $model = new self(); - if(isset($map['test'])){ - $model->test = $map['test']; - } - if(isset($map['test1'])){ - $model->test1 = $map['test1']; - } - return $model; + + if (isset($map['test1'])) { + $model->test1 = $map['test1']; } - // model的test front comment - /** - * @description test desc - * @var string - */ - public $test; - - // empty comment1 - // empy comment2 - /** - * @description test desc - * @var string - */ - public $test1; - - // model的test back comment + + return $model; + } + + } + diff --git a/tests/expected/complex/Client.php b/tests/expected/complex/Client.php index 185ec79..0489aa1 100644 --- a/tests/expected/complex/Client.php +++ b/tests/expected/complex/Client.php @@ -1,386 +1,445 @@ _configs[0] = $config; - } + public function __construct($config) + { + parent::__construct($config); + @$this->_configs[0] = $config; + } - /** - * @param ComplexRequest $request - * @param SourceClient $client - * @return RuntimeObject - * @throws TeaError - * @throws Exception - * @throws TeaUnableRetryError - */ - public function complex1($request, $client){ - $request->validate(); - $_runtime = [ - "timeouted" => "retry" - ]; - $_lastRequest = null; - $_lastException = null; - $_now = time(); - $_retryTimes = 0; - while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { - if ($_retryTimes > 0) { - $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); - if ($_backoffTime > 0) { - Tea::sleep($_backoffTime); - } - } - $_retryTimes = $_retryTimes + 1; - try { - $_request = new Request(); - $name = "complex"; - $mapVal = [ - "test" => "ok" - ]; - $moduleModelMapVal = []; - $moduleMapVal = []; - $modelMapVal = []; - $subModelMapVal = []; - $version = "/" . "2019-01-08" . "" . $this->_pathname . ""; - $mapAccess = @$this->_API[$version]; - $_request->protocol = $this->_protocol; - $_request->port = 80; - $_request->method = "GET"; - $_request->pathname = "/" . $this->_pathname . ""; - $_request->query = SourceClient::query(Tea::merge([ - "date" => "2019", - "access" => $mapAccess, - "test" => @$mapVal["test"] - ], $request->header)); - $_request->body = SourceClient::body(); - $_lastRequest = $_request; - $_response= Tea::send($_request, $_runtime); - if (true && true) { - return null; - } - else if (true || false) { - return new RuntimeObject([]); - } - $client->print_(Tea::merge($request), "1"); - $client->printAsync(Tea::merge($request), "1"); - $this->hello(Tea::merge($request), [ - "1", - "2" - ]); - $this->hello(null, null); - $this->Complex3(null); - return RuntimeObject::fromMap([]); - } - catch (Exception $e) { - if (!($e instanceof TeaError)) { - $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); - } - if (Tea::isRetryable($e)) { - $_lastException = $e; - continue; - } - throw $e; - } + /** + * @param ComplexRequest $request + * @param SourceClient $client + * @return RuntimeObject + */ + public function complex1($request, $client) + { + $_runtime = [ + 'timeouted' => 'retry', + ]; + + $_retriesAttempted = 0; + $_lastRequest = null; + $_lastResponse = null; + $_context = new RetryPolicyContext([ + 'retriesAttempted' => $_retriesAttempted, + ]); + while (Dara::shouldRetry($_runtime['retryOptions'], $_context)) { + if ($_retriesAttempted > 0) { + $_backoffTime = Dara::getBackoffDelay($_runtime['retryOptions'], $_context); + if ($_backoffTime > 0) { + Dara::sleep($_backoffTime); } - throw new TeaUnableRetryError($_lastRequest, $_lastException); - } + } - /** - * @param ComplexRequest $request - * @param string[] $str - * @param string[] $val - * @return array - */ - public function Complex2($request, $str, $val){ - $request->validate(); + $_retriesAttempted++; + try { $_request = new Request(); - $name = "complex"; - $config = new Config([]); - $client = new SourceClient($config); - $_request->protocol = "HTTP"; - $_request->port = 80; - $_request->method = "GET"; - $_request->pathname = "/"; - $_request->query = SourceClient::query([ - "date" => "2019", - "version" => "2019-01-08", - "protocol" => $_request->protocol - ]); - $_request->body = SourceClient::body(); + $name = 'complex'; + $mapVal = [ + 'test' => 'ok', + ]; + $moduleModelMapVal = [ ]; + $moduleMapVal = [ ]; + $modelMapVal = [ ]; + $subModelMapVal = [ ]; + $version = '/' . '2019-01-08' . '' . $this->_pathname . ''; + $mapAccess = @$this->_API[$version]; + $_reqeust->protocol = $this->_protocol; + $_reqeust->port = 80; + $_reqeust->method = 'GET'; + $_reqeust->pathname = '/' . $this->_pathname . ''; + $_reqeust->query = SourceClient::query(Dara::merge([ + 'date' => '2019', + 'access' => $mapAccess, + 'test' => @$mapVal['test'], + ], $request->header)); + $_reqeust->body = SourceClient::body(); + $_response = Dara::send($_request, $_runtime); $_lastRequest = $_request; - $_response= Tea::send($_request); - } + $_lastResponse = $_response; - /** - * @param ComplexRequest $request - * @return ComplexRequest - */ - public function Complex3($request){ - $request->validate(); - $_request = new Request(); - $name = "complex"; - $_request->protocol = $this->TemplateString(); - $_request->port = 80; - $_request->method = "GET"; - $_request->pathname = "/"; - $_request->query = SourceClient::query([ - "date" => "2019" + if (true && true) { + return null; + } else if (true || false) { + return new RuntimeObject([ ]); + } + + $client->print_($request->toArray(), '1'); + $client->printAsync($request->toArray(), '1'); + $this->hello($request->toArray(), [ + '1', + '2' ]); - $_request->body = SourceClient::body(); - $_request->headers["host"] = "hello"; - $_lastRequest = $_request; - $_response= Tea::send($_request); - $temp_str = "test " . (string) (100) . " " . (string) (true) . ""; - $resp = $_response; - $req = new \Source\Models\Request([ - "accesskey" => $request->accessKey, - "region" => $resp->statusMessage + $this->hello(null, null); + $this->Complex3(null); + return RuntimeObject::fromMap([ ]); + } catch (DaraException $e) { + $_context = new RetryPolicyContext([ + 'retriesAttempted' => $_retriesAttempted, + 'lastRequest' => $_lastRequest, + 'lastResponse' => $_lastResponse, + 'exception' => $e, ]); - self::array0(Tea::merge($request)); - $req->accesskey = "accesskey"; - $req->accesskey = $request->accessKey; - SourceClient::parse(ComplexRequest::class); - SourceClient::array_(Tea::merge($request), "1"); - SourceClient::asyncFunc(); - return ComplexRequest::fromMap(Tea::merge($_request->query)); + continue; + } } - /** - * @param mixed[] $request - * @param string[] $strs - * @return array - */ - public function hello($request, $strs){ - return self::array1(); - } + throw DaraUnableRetryException($_context); + } - /** - * @param Request $reqeust - * @param ComplexRequest[] $reqs - * @param Response $response - * @param string[] $val - * @return \Source\Models\Request - */ - public static function print_($reqeust, $reqs, $response, $val){ - return Request::fromMap([]); - } + /** + * @param ComplexRequest $request + * @param string[] $str + * @param string[] $val + * @return mixed[] + */ + public function Complex2($request, $str, $val) + { + $_request = new Request(); + $name = 'complex'; + $config = new Config([ ]); + $client = new SourceClient($config); + $_reqeust->protocol = 'HTTP'; + $_reqeust->port = 80; + $_reqeust->method = 'GET'; + $_reqeust->pathname = '/'; + $_reqeust->query = SourceClient::query([ + 'date' => '2019', + 'version' => '2019-01-08', + 'protocol' => $_reqeust->protocol, + ]); + $_reqeust->body = SourceClient::body(); + $_response = Dara::send($_request); - /** - * @param mixed[] $req - * @return array - */ - public static function array0($req){ - $temp = new Config([]); - $anyArr = [ - $temp - ]; - return []; - } + return []; + } - /** - * @return array - */ - public static function array1(){ - return [ - "1" - ]; - } + /** + * @param ComplexRequest $request + * @return ComplexRequest + */ + public function Complex3($request) + { + $_request = new Request(); + $name = 'complex'; + $_reqeust->protocol = $this->TemplateString(); + $_reqeust->port = 80; + $_reqeust->method = 'GET'; + $_reqeust->pathname = '/'; + $_reqeust->query = SourceClient::query([ + 'date' => '2019', + ]); + $_reqeust->body = SourceClient::body(); + @$_reqeust->headers['host'] = 'hello'; + $_response = Dara::send($_request); - /** - * @return string - */ - public static function arrayAccess(){ - $configs = [ - "a", - "b", - "c" - ]; - $config = @$configs[0]; - return $config; - } + $temp_str = 'test ' . (string)100 . ' ' . (string)true . ' ' . (string)($_reqeust->port + 4) . ' ' . @$_reqeust->headers['host'] . ''; + $resp = $_response; + $req = new \Source\Models\Request([ + 'accesskey' => $request->accessKey, + 'region' => $resp->statusMessage, + ]); + self::array0($request->toArray()); + $req->accesskey = 'accesskey'; + $req->accesskey = $request->accessKey; + SourceClient::parse(ComplexRequest::class); + SourceClient::array_($request->toArray(), '1'); + SourceClient::asyncFunc(); + return ComplexRequest::fromMap(Dara::merge([ + ], $_reqeust->query)); + } - /** - * @return string - */ - public static function arrayAccess2(){ - $data = [ - "configs" => [ - "a", - "b", - "c" - ] - ]; - $config = @$data["configs"][0]; - $i = 0; - $config = @$data["configs"][$i]; - return $config; - } + /** + * @param mixed[] $request + * @param string[] $strs + * @return string[] + */ + public function hello($request, $strs) + { + return self::array1(); + } - /** - * @param ComplexRequest $request - * @return string - */ - public static function arrayAccess3($request){ - $configVal = @$request->configs->value[0]; - return $configVal; - } + /** + * @param Request $reqeust + * @param ComplexRequest[] $reqs + * @param Response $response + * @param string[] $val + * @return \Source\Models\Request + */ + static public function print_($reqeust, $reqs, $response, $val) + { + return \Source\Models\Request::fromMap([ ]); + } - /** - * @param ComplexRequest $request - * @param string $config - * @param int $index - * @return void - */ - public static function arrayAccess4($request, $config, $index){ - @$request->configs->value[$index] = $config; - $i = 1; - @$request->configs->value[$i] = $config; - } + /** + * @param mixed[] $req + * @return mixed[] + */ + static public function array0($req) + { + $temp = new Config([ ]); + $anyArr = [ + $temp + ]; + return [ ]; + } - /** - * @param string $config - * @return array - */ - public static function arrayAssign($config){ - $configs = [ - "a", - "b", - "c" - ]; - @$configs[3] = $config; - return $configs; - } + /** + * @return string[] + */ + static public function array1() + { + return [ + '1' + ]; + } - /** - * @param string $config - * @return array - */ - public static function arrayAssign2($config){ - $data = [ - "configs" => [ - "a", - "b", - "c" - ] - ]; - @$data["configs"][3] = $config; - return @$data["configs"]; - } + /** + * @return string + */ + static public function arrayAccess() + { + $configs = [ + 'a', + 'b', + 'c' + ]; + $config = @$configs[0]; + return $config; + } - /** - * @param ComplexRequest $request - * @param string $config - * @return void - */ - public static function arrayAssign3($request, $config){ - @$request->configs->value[0] = $config; - } + /** + * @return string + */ + static public function arrayAccess2() + { + $data = [ + 'configs' => [ + 'a', + 'b', + 'c' + ], + ]; + $config = @$data['configs'][0]; + $i = 0; + $config = @$data['configs'][$i]; + return $config; + } - /** - * @param ComplexRequest $request - * @return string - */ - public static function mapAccess($request){ - $key = "name"; - $configInfo = @$request->configs->extra[$key]; - return $configInfo; - } + /** + * @param ComplexRequest $request + * @return string + */ + static public function arrayAccess3($request) + { + $configVal = @$request->configs->value[0]; + return $configVal; + } - /** - * @param \Source\Models\Request $request - * @return string - */ - public static function mapAccess2($request){ - $configInfo = @$request->configs->extra["name"]; - return $configInfo; - } + /** + * @param ComplexRequest $request + * @param string $config + * @param int $index + * @return void + */ + static public function arrayAccess4($request, $config, $index) + { + @$request->configs->value[$index] = $config; + $i = 1; + @$request->configs->value[$i] = $config; + } - /** - * @return string - */ - public static function mapAccess3(){ - $data = [ - "configs" => [ - "value" => "string" - ] - ]; - return @$data["configs"]["value"]; - } + /** + * @param string $config + * @return string[] + */ + static public function arrayAssign($config) + { + $configs = [ + 'a', + 'b', + 'c' + ]; + @$configs[3] = $config; + return $configs; + } - /** - * @param ComplexRequest $request - * @param string $name - * @return void - */ - public static function mapAssign($request, $name){ - $request->configs->extra["name"] = $name; - $key = "name"; - $request->configs->extra[$key] = $name; - } + /** + * @param string $config + * @return string[] + */ + static public function arrayAssign2($config) + { + $data = [ + 'configs' => [ + 'a', + 'b', + 'c' + ], + ]; + @$data['configs'][3] = $config; + return @$data['configs']; + } - /** - * @return string - */ - public function TemplateString(){ - return "/" . $this->_protocol . ""; - } + /** + * @param ComplexRequest $request + * @param string $config + * @return void + */ + static public function arrayAssign3($request, $config) + { + @$request->configs->value[0] = $config; + } - /** - * @return void - */ - public function emptyModel(){ - new ComplexRequest(); - new header(); - } + /** + * @param ComplexRequest $request + * @return string + */ + static public function mapAccess($request) + { + $key = 'name'; + $configInfo = @$request->configs->extra[$key]; + return $configInfo; + } + + /** + * @param \Source\Models\Request $request + * @return string + */ + static public function mapAccess2($request) + { + $configInfo = @$request->configs->extra['name']; + return $configInfo; + } + + /** + * @return string + */ + static public function mapAccess3() + { + $data = [ + 'configs' => [ + 'value' => 'string', + ], + ]; + return @$data['configs']['value']; + } + + /** + * @param ComplexRequest $request + * @param string $name + * @return void + */ + static public function mapAssign($request, $name) + { + @$request->configs->extra['name'] = $name; + $key = 'name'; + @$request->configs->extra[$key] = $name; + } + + /** + * @return string + */ + public function TemplateString() + { + return '/' . $this->_protocol . ''; + } + + /** + * @return void + */ + public function emptyModel() + { + new ComplexRequest([ ]); + new header([ ]); + } + + /** + * @return void + */ + public function tryCatch() + { + try { + $str = $this->TemplateString(); + } catch (DaraException $err) { + $error = $err; + } finally { + $final = 'ok'; + } + try { + $strNoFinal = $this->TemplateString(); + } catch (DaraException $e) { + $errorNoFinal = $e; + } + try { + $strNoCatch = $this->TemplateString(); + } finally { + $finalNoCatch = 'ok'; + } + } + + /** + * @param int $a + * @return void + */ + public function multiTryCatch($a) + { + try { + if ($a > 0) { + throw new Err1([ + 'name' => 'str', + 'code' => 'str', + 'data' => [ + 'key1' => 'str', + ], + ]); + } else if ($a == 0) { + throw new Err2([ + 'name' => 'str', + 'code' => 'str', + 'accessErrMessage' => 'str2', + ]); + } else { + throw new DaraException([ + 'name' => 'str', + 'code' => 'str', + ]); + } + + } catch (Err1 $err) { + Console::log($err->name); + } catch (Err2 $err) { + Console::log($err->name); + } catch (DaraException $err) { + Console::log($err->name); + } finally { + $final = 'ok'; + } + } - /** - * @return void - */ - public function tryCatch(){ - try { - $str = $this->TemplateString(); - } - catch (Exception $err) { - if (!($err instanceof TeaError)) { - $err = new TeaError([], $err->getMessage(), $err->getCode(), $err); - } - $error = $err; - } - finally { - $final = "ok"; - } - try { - $strNoFinal = $this->TemplateString(); - } - catch (Exception $e) { - if (!($e instanceof TeaError)) { - $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); - } - $errorNoFinal = $e; - } - try { - $strNoCatch = $this->TemplateString(); - } - finally { - $finalNoCatch = "ok"; - } - } } diff --git a/tests/expected/complex/Exceptions/Err1.php b/tests/expected/complex/Exceptions/Err1.php new file mode 100644 index 0000000..4446821 --- /dev/null +++ b/tests/expected/complex/Exceptions/Err1.php @@ -0,0 +1,27 @@ +data = $map['data']; + } + + /** + * @return string[] + */ + public function getData() + { + return $this->data; + } +} + diff --git a/tests/expected/complex/Exceptions/Err2.php b/tests/expected/complex/Exceptions/Err2.php new file mode 100644 index 0000000..043591e --- /dev/null +++ b/tests/expected/complex/Exceptions/Err2.php @@ -0,0 +1,27 @@ +accessErrMessage = $map['accessErrMessage']; + } + + /** + * @return string + */ + public function getAccessErrMessage() + { + return $this->accessErrMessage; + } +} + diff --git a/tests/expected/complex/Models/ComplexRequest.php b/tests/expected/complex/Models/ComplexRequest.php index ec47176..f4afa2c 100644 --- a/tests/expected/complex/Models/ComplexRequest.php +++ b/tests/expected/complex/Models/ComplexRequest.php @@ -1,149 +1,190 @@ 'duplicatName', + 'accessKey' => 'accessKey', + 'body' => 'Body', + 'strs' => 'Strs', + 'header' => 'header', + 'Num' => 'Num', + 'configs' => 'configs', + 'part' => 'Part', + ]; -use Tea\PHP\Tests\Models\ComplexRequest\header; -use Tea\PHP\Tests\Models\ComplexRequest\configs; -use Tea\PHP\Tests\Models\ComplexRequest\part; + public function validate() + { + if(null !== $this->duplicatName) { + $this->duplicatName->validate(); + } + Model::validateRequired('duplicatName', $this->duplicatName, true); + Model::validateRequired('accessKey', $this->accessKey, true); + Model::validateRequired('body', $this->body, true); + if(is_array($this->strs)) { + Model::validateArray($this->strs); + } + Model::validateRequired('strs', $this->strs, true); + if(null !== $this->header) { + $this->header->validate(); + } + Model::validateRequired('header', $this->header, true); + Model::validateRequired('Num', $this->Num, true); + if(null !== $this->configs) { + $this->configs->validate(); + } + Model::validateRequired('configs', $this->configs, true); + if(is_array($this->part)) { + Model::validateArray($this->part); + } + parent::validate(); + } + + public function toArray($noStream = false) + { + $res = []; + if (null !== $this->duplicatName) { + $res['duplicatName'] = null !== $this->duplicatName ? $this->duplicatName->toArray($noStream) : $this->duplicatName; + } + + if (null !== $this->accessKey) { + $res['accessKey'] = $this->accessKey; + } + + if (null !== $this->body) { + $res['Body'] = $this->body; + } + + if (null !== $this->strs) { + if(is_array($this->strs)) { + $res['Strs'] = []; + $n1 = 0; + foreach($this->strs as $item1) { + $res['Strs'][$n1++] = $item1; + } + } + } + + if (null !== $this->header) { + $res['header'] = null !== $this->header ? $this->header->toArray($noStream) : $this->header; + } + + if (null !== $this->Num) { + $res['Num'] = $this->Num; + } + + if (null !== $this->configs) { + $res['configs'] = null !== $this->configs ? $this->configs->toArray($noStream) : $this->configs; + } + + if (null !== $this->part) { + if(is_array($this->part)) { + $res['Part'] = []; + $n1 = 0; + foreach($this->part as $item1) { + $res['Part'][$n1++] = null !== $item1 ? $item1->toArray($noStream) : $item1; + } + } + } + + return $res; + } + + public function toMap($noStream = false) + { + return $this->toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + if (isset($map['duplicatName'])) { + $model->duplicatName = complexrequest::fromMap($map['duplicatName']); + } + + if (isset($map['accessKey'])) { + $model->accessKey = $map['accessKey']; + } + + if (isset($map['Body'])) { + $model->body = $map['Body']; + } + + if (isset($map['Strs'])) { + if(!empty($map['Strs'])) { + $model->strs = []; + $n1 = 0; + foreach($map['Strs'] as $item1) { + $model->strs[$n1++] = $item1; + } + } + } + + if (isset($map['header'])) { + $model->header = header::fromMap($map['header']); + } + + if (isset($map['Num'])) { + $model->Num = $map['Num']; + } + + if (isset($map['configs'])) { + $model->configs = configs::fromMap($map['configs']); + } + + if (isset($map['Part'])) { + if(!empty($map['Part'])) { + $model->part = []; + $n1 = 0; + foreach($map['Part'] as $item1) { + $model->part[$n1++] = part::fromMap($item1); + } + } + } + + return $model; + } -class ComplexRequest extends Model { - protected $_name = [ - 'body' => 'Body', - 'strs' => 'Strs', - 'header' => 'header', - 'part' => 'Part', - ]; - public function validate() { - Model::validateRequired('duplicatName', $this->duplicatName, true); - Model::validateRequired('accessKey', $this->accessKey, true); - Model::validateRequired('body', $this->body, true); - Model::validateRequired('strs', $this->strs, true); - Model::validateRequired('header', $this->header, true); - Model::validateRequired('Num', $this->Num, true); - Model::validateRequired('configs', $this->configs, true); - } - public function toMap() { - $res = []; - if (null !== $this->duplicatName) { - $res['duplicatName'] = null !== $this->duplicatName ? $this->duplicatName->toMap() : null; - } - if (null !== $this->accessKey) { - $res['accessKey'] = $this->accessKey; - } - if (null !== $this->body) { - $res['Body'] = $this->body; - } - if (null !== $this->strs) { - $res['Strs'] = $this->strs; - } - if (null !== $this->header) { - $res['header'] = null !== $this->header ? $this->header->toMap() : null; - } - if (null !== $this->Num) { - $res['Num'] = $this->Num; - } - if (null !== $this->configs) { - $res['configs'] = null !== $this->configs ? $this->configs->toMap() : null; - } - if (null !== $this->part) { - $res['Part'] = []; - if(null !== $this->part && is_array($this->part)){ - $n = 0; - foreach($this->part as $item){ - $res['Part'][$n++] = null !== $item ? $item->toMap() : $item; - } - } - } - return $res; - } - /** - * @param array $map - * @return ComplexRequest - */ - public static function fromMap($map = []) { - $model = new self(); - if(isset($map['duplicatName'])){ - $model->duplicatName = \Source\Models\complexrequest::fromMap($map['duplicatName']); - } - if(isset($map['accessKey'])){ - $model->accessKey = $map['accessKey']; - } - if(isset($map['Body'])){ - $model->body = $map['Body']; - } - if(isset($map['Strs'])){ - if(!empty($map['Strs'])){ - $model->strs = $map['Strs']; - } - } - if(isset($map['header'])){ - $model->header = header::fromMap($map['header']); - } - if(isset($map['Num'])){ - $model->Num = $map['Num']; - } - if(isset($map['configs'])){ - $model->configs = configs::fromMap($map['configs']); - } - if(isset($map['Part'])){ - if(!empty($map['Part'])){ - $model->part = []; - $n = 0; - foreach($map['Part'] as $item) { - $model->part[$n++] = null !== $item ? part::fromMap($item) : $item; - } - } - } - return $model; - } - /** - * @var \Source\Models\complexrequest - */ - public $duplicatName; - - /** - * @var string - */ - public $accessKey; - - /** - * @example Body - * @description Body - * @var Stream - */ - public $body; - - /** - * @example Strs - * @description Strs - * @var string[] - */ - public $strs; - - /** - * @description header - * @var header - */ - public $header; - - /** - * @var int - */ - public $Num; - - /** - * @var configs - */ - public $configs; - - /** - * @description Part - * @var part[] - */ - public $part; } + diff --git a/tests/expected/complex/Models/ComplexRequest/configs.php b/tests/expected/complex/Models/ComplexRequest/configs.php index 8b368e3..d6db1a5 100644 --- a/tests/expected/complex/Models/ComplexRequest/configs.php +++ b/tests/expected/complex/Models/ComplexRequest/configs.php @@ -1,61 +1,105 @@ 'key', + 'value' => 'value', + 'extra' => 'extra', + ]; -use AlibabaCloud\Tea\Model; + public function validate() + { + Model::validateRequired('key', $this->key, true); + if(is_array($this->value)) { + Model::validateArray($this->value); + } + Model::validateRequired('value', $this->value, true); + if(is_array($this->extra)) { + Model::validateArray($this->extra); + } + Model::validateRequired('extra', $this->extra, true); + parent::validate(); + } -class configs extends Model { - public function validate() { - Model::validateRequired('key', $this->key, true); - Model::validateRequired('value', $this->value, true); - Model::validateRequired('extra', $this->extra, true); - } - public function toMap() { - $res = []; - if (null !== $this->key) { - $res['key'] = $this->key; - } - if (null !== $this->value) { - $res['value'] = $this->value; - } - if (null !== $this->extra) { - $res['extra'] = $this->extra; + public function toArray($noStream = false) + { + $res = []; + if (null !== $this->key) { + $res['key'] = $this->key; + } + + if (null !== $this->value) { + if(is_array($this->value)) { + $res['value'] = []; + $n1 = 0; + foreach($this->value as $item1) { + $res['value'][$n1++] = $item1; } - return $res; - } - /** - * @param array $map - * @return configs - */ - public static function fromMap($map = []) { - $model = new self(); - if(isset($map['key'])){ - $model->key = $map['key']; + } + } + + if (null !== $this->extra) { + if(is_array($this->extra)) { + $res['extra'] = []; + foreach($this->extra as $key1 => $value1) { + $res['extra'][$key1] = $value1; } - if(isset($map['value'])){ - if(!empty($map['value'])){ - $model->value = $map['value']; - } + } + } + + return $res; + } + + public function toMap($noStream = false) + { + return $this->toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + if (isset($map['key'])) { + $model->key = $map['key']; + } + + if (isset($map['value'])) { + if(!empty($map['value'])) { + $model->value = []; + $n1 = 0; + foreach($map['value'] as $item1) { + $model->value[$n1++] = $item1; } - if(isset($map['extra'])){ - $model->extra = $map['extra']; + } + } + + if (isset($map['extra'])) { + if(!empty($map['extra'])) { + $model->extra = []; + foreach($map['extra'] as $key1 => $value1) { + $model->extra[$key1] = $value1; } - return $model; + } } - /** - * @var string - */ - public $key; - /** - * @var string[] - */ - public $value; + return $model; + } - /** - * @var string[] - */ - public $extra; } + diff --git a/tests/expected/complex/Models/ComplexRequest/header.php b/tests/expected/complex/Models/ComplexRequest/header.php index de3a809..662687e 100644 --- a/tests/expected/complex/Models/ComplexRequest/header.php +++ b/tests/expected/complex/Models/ComplexRequest/header.php @@ -1,40 +1,49 @@ 'Content', + ]; -use AlibabaCloud\Tea\Model; + public function validate() + { + Model::validateRequired('content', $this->content, true); + parent::validate(); + } -class header extends Model { - protected $_name = [ - 'content' => 'Content', - ]; - public function validate() { - Model::validateRequired('content', $this->content, true); - } - public function toMap() { - $res = []; - if (null !== $this->content) { - $res['Content'] = $this->content; - } - return $res; + public function toArray($noStream = false) + { + $res = []; + if (null !== $this->content) { + $res['Content'] = $this->content; } - /** - * @param array $map - * @return header - */ - public static function fromMap($map = []) { - $model = new self(); - if(isset($map['Content'])){ - $model->content = $map['Content']; - } - return $model; + + return $res; + } + + public function toMap($noStream = false) + { + return $this->toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + if (isset($map['Content'])) { + $model->content = $map['Content']; } - /** - * @example Content - * @description Body - * @var string - */ - public $content; + + return $model; + } + } + diff --git a/tests/expected/complex/Models/ComplexRequest/part.php b/tests/expected/complex/Models/ComplexRequest/part.php index 34d7360..0b767c4 100644 --- a/tests/expected/complex/Models/ComplexRequest/part.php +++ b/tests/expected/complex/Models/ComplexRequest/part.php @@ -1,37 +1,48 @@ 'PartNumber', + ]; -use AlibabaCloud\Tea\Model; + public function validate() + { + parent::validate(); + } -class part extends Model { - protected $_name = [ - 'partNumber' => 'PartNumber', - ]; - public function validate() {} - public function toMap() { - $res = []; - if (null !== $this->partNumber) { - $res['PartNumber'] = $this->partNumber; - } - return $res; + public function toArray($noStream = false) + { + $res = []; + if (null !== $this->partNumber) { + $res['PartNumber'] = $this->partNumber; } - /** - * @param array $map - * @return part - */ - public static function fromMap($map = []) { - $model = new self(); - if(isset($map['PartNumber'])){ - $model->partNumber = $map['PartNumber']; - } - return $model; + + return $res; + } + + public function toMap($noStream = false) + { + return $this->toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + if (isset($map['PartNumber'])) { + $model->partNumber = $map['PartNumber']; } - /** - * @description PartNumber - * @var string - */ - public $partNumber; + + return $model; + } + } + diff --git a/tests/expected/const/Client.php b/tests/expected/const/Client.php index 45068ad..4095d6b 100644 --- a/tests/expected/const/Client.php +++ b/tests/expected/const/Client.php @@ -1,14 +1,17 @@ 'value', + 'key-1' => 'value-1', + ], $m); + } - /** - * @return void - */ - public static function hello(){ - return null; - } + /** + * @return string[][] + */ + static public function helloArrayMap() + { + return [ + [ + 'key' => 'value', + ] + ]; + } - /** - * @return array - */ - public static function helloMap(){ - $m = []; - return Tea::merge([ - "key" => "value", - "key-1" => "value-1" - ], $m); + /** + * @param string $a + * @param string $b + * @return void + */ + static public function helloParams($a, $b) + { + $x = false; + $y = true; + $z = false; + if ($x && $y || !$z) { + } - /** - * @return array - */ - public static function helloArrayMap(){ - return [ - [ - "key" => "value" - ] - ]; - } + } - /** - * @param string $a - * @param string $b - * @return void - */ - public static function helloParams($a, $b){ - $x = false; - $y = true; - $z = false; - if ($x && $y || !$z) {} - } + // interface mode + /** + * @return void + */ + static public function helloInterface() + { + throw new RuntimeException('Un-implemented!'); + } - /** - * interface mode - * @return void - */ - public static function helloInterface(){ - throw new Exception('Un-implemented'); - } } diff --git a/tests/expected/import/Client.php b/tests/expected/import/Client.php index f71fbf2..06f6b0b 100644 --- a/tests/expected/import/Client.php +++ b/tests/expected/import/Client.php @@ -1,38 +1,47 @@ _id = $id; + $this->_str = $str; + throw new DaraException([ + 'code' => 'SomeError', + 'messge' => 'ErrorMessage', + ]); + } - protected $_str; - public function __construct($id, $str){ - $this->_id = $id; - $this->_str = $str; - throw new TeaError([ - "code" => "SomeError", - "messge" => "ErrorMessage" - ]); - } + /** + * @param SourceClient $client + * @return void + */ + static public function Sample($client) + { + $runtime = new RuntimeObject([ ]); + $request = new Request([ + 'accesskey' => 'accesskey', + 'region' => 'region', + ]); + $client->print_($runtime); + } - /** - * @param SourceClient $client - * @return void - */ - public static function Sample($client){ - $runtime = new RuntimeObject([]); - $request = new Request([ - "accesskey" => "accesskey", - "region" => "region" - ]); - $client->print_($runtime); - } } diff --git a/tests/expected/map/Client.php b/tests/expected/map/Client.php index 7dc23aa..1915905 100644 --- a/tests/expected/map/Client.php +++ b/tests/expected/map/Client.php @@ -1,26 +1,31 @@ _endpointRule = 'central'; + $this->_endpointMap = [ + 'ap-northeast-1' => 'cusanalytic.aliyuncs.com', + 'ap-south-1' => 'cusanalytic.aliyuncs.com', + ]; + @$this->_endpointMap['ap-northeast-1']; + @$this->_endpointMap['ap-northeast-1'] = ''; + @$this->_endpointMap['test'] = 'test'; + $b = new B([ ]); -class Client extends SourceClient { - public function __construct($config){ - parent::__construct($config); - $this->_endpointRule = "central"; - $this->_endpointMap = [ - "ap-northeast-1" => "cusanalytic.aliyuncs.com", - "ap-south-1" => "cusanalytic.aliyuncs.com" - ]; - @$this->_endpointMap["ap-northeast-1"]; - $this->_endpointMap["ap-northeast-1"] = ""; - @$this->_endpointMap["test"] = "test"; - $b = new B([]); - foreach($b->mm as $a){ - @$a->m[$a->str]; - } + foreach($b->mm as $a) { + @$a->m[$a->str]; } + } + + + } diff --git a/tests/expected/map/Models/A.php b/tests/expected/map/Models/A.php index 23f308a..232a117 100644 --- a/tests/expected/map/Models/A.php +++ b/tests/expected/map/Models/A.php @@ -1,47 +1,76 @@ m, true); - Model::validateRequired('str', $this->str, true); + /** + * @var string[] + */ + public $m; + /** + * @var string + */ + public $str; + protected $_name = [ + 'm' => 'm', + 'str' => 'str', + ]; + + public function validate() + { + if(is_array($this->m)) { + Model::validateArray($this->m); } - public function toMap() { - $res = []; - if (null !== $this->m) { - $res['m'] = $this->m; - } - if (null !== $this->str) { - $res['str'] = $this->str; + Model::validateRequired('m', $this->m, true); + Model::validateRequired('str', $this->str, true); + parent::validate(); + } + + public function toArray($noStream = false) + { + $res = []; + if (null !== $this->m) { + if(is_array($this->m)) { + $res['m'] = []; + foreach($this->m as $key1 => $value1) { + $res['m'][$key1] = $value1; } - return $res; + } } - /** - * @param array $map - * @return A - */ - public static function fromMap($map = []) { - $model = new self(); - if(isset($map['m'])){ - $model->m = $map['m']; - } - if(isset($map['str'])){ - $model->str = $map['str']; + + if (null !== $this->str) { + $res['str'] = $this->str; + } + + return $res; + } + + public function toMap($noStream = false) + { + return $this->toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + if (isset($map['m'])) { + if(!empty($map['m'])) { + $model->m = []; + foreach($map['m'] as $key1 => $value1) { + $model->m[$key1] = $value1; } - return $model; + } } - /** - * @var string[] - */ - public $m; - /** - * @var string - */ - public $str; + if (isset($map['str'])) { + $model->str = $map['str']; + } + + return $model; + } + } + diff --git a/tests/expected/map/Models/B.php b/tests/expected/map/Models/B.php index 09c01d8..8d1f7ea 100644 --- a/tests/expected/map/Models/B.php +++ b/tests/expected/map/Models/B.php @@ -1,49 +1,65 @@ mm, true); + /** + * @var A[] + */ + public $mm; + protected $_name = [ + 'mm' => 'mm', + ]; + + public function validate() + { + if(is_array($this->mm)) { + Model::validateArray($this->mm); } - public function toMap() { - $res = []; - if (null !== $this->mm) { - $res['mm'] = []; - if(null !== $this->mm && is_array($this->mm)){ - $n = 0; - foreach($this->mm as $item){ - $res['mm'][$n++] = null !== $item ? $item->toMap() : $item; - } - } + Model::validateRequired('mm', $this->mm, true); + parent::validate(); + } + + public function toArray($noStream = false) + { + $res = []; + if (null !== $this->mm) { + if(is_array($this->mm)) { + $res['mm'] = []; + $n1 = 0; + foreach($this->mm as $item1) { + $res['mm'][$n1++] = null !== $item1 ? $item1->toArray($noStream) : $item1; } - return $res; + } } - /** - * @param array $map - * @return B - */ - public static function fromMap($map = []) { - $model = new self(); - if(isset($map['mm'])){ - if(!empty($map['mm'])){ - $model->mm = []; - $n = 0; - foreach($map['mm'] as $item) { - $model->mm[$n++] = null !== $item ? A::fromMap($item) : $item; - } - } + + return $res; + } + + public function toMap($noStream = false) + { + return $this->toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + if (isset($map['mm'])) { + if(!empty($map['mm'])) { + $model->mm = []; + $n1 = 0; + foreach($map['mm'] as $item1) { + $model->mm[$n1++] = $item1; } - return $model; + } } - /** - * @var A[] - */ - public $mm; + + return $model; + } + } + diff --git a/tests/expected/model/Client.php b/tests/expected/model/Client.php index 50abc00..e005059 100644 --- a/tests/expected/model/Client.php +++ b/tests/expected/model/Client.php @@ -1,7 +1,10 @@ size = $map['size']; + $this->data = $map['data']; + $this->model = $map['model']; + } + + /** + * @return int + */ + public function getSize() + { + return $this->size; + } + /** + * @return model_[] + */ + public function getData() + { + return $this->data; + } + /** + * @return \Dara\PHP\Tests\Models\MainFileError\model_ + */ + public function getModel() + { + return $this->model; + } +} + diff --git a/tests/expected/model/Models/Class_.php b/tests/expected/model/Models/Class_.php index 83be76e..5b73c42 100644 --- a/tests/expected/model/Models/Class_.php +++ b/tests/expected/model/Models/Class_.php @@ -1,22 +1,35 @@ toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + return $model; + } -use AlibabaCloud\Tea\Model; -class Class_ extends Model { - public function validate() {} - public function toMap() { - $res = []; - return $res; - } - /** - * @param array $map - * @return Class_ - */ - public static function fromMap($map = []) { - $model = new self(); - return $model; - } } + diff --git a/tests/expected/model/Models/M.php b/tests/expected/model/Models/M.php index eba986c..04434d4 100644 --- a/tests/expected/model/Models/M.php +++ b/tests/expected/model/Models/M.php @@ -1,37 +1,53 @@ subM, true); + /** + * @var subM + */ + public $subM; + protected $_name = [ + 'subM' => 'subM', + ]; + + public function validate() + { + if(null !== $this->subM) { + $this->subM->validate(); } - public function toMap() { - $res = []; - if (null !== $this->subM) { - $res['subM'] = null !== $this->subM ? $this->subM->toMap() : null; - } - return $res; + Model::validateRequired('subM', $this->subM, true); + parent::validate(); + } + + public function toArray($noStream = false) + { + $res = []; + if (null !== $this->subM) { + $res['subM'] = null !== $this->subM ? $this->subM->toArray($noStream) : $this->subM; } - /** - * @param array $map - * @return M - */ - public static function fromMap($map = []) { - $model = new self(); - if(isset($map['subM'])){ - $model->subM = subM::fromMap($map['subM']); - } - return $model; + + return $res; + } + + public function toMap($noStream = false) + { + return $this->toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + if (isset($map['subM'])) { + $model->subM = subM::fromMap($map['subM']); } - /** - * @var subM - */ - public $subM; + + return $model; + } + } + diff --git a/tests/expected/model/Models/M/subM.php b/tests/expected/model/Models/M/subM.php index 21177ab..991f170 100644 --- a/tests/expected/model/Models/M/subM.php +++ b/tests/expected/model/Models/M/subM.php @@ -1,22 +1,35 @@ toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + return $model; + } -use AlibabaCloud\Tea\Model; -class subM extends Model { - public function validate() {} - public function toMap() { - $res = []; - return $res; - } - /** - * @param array $map - * @return subM - */ - public static function fromMap($map = []) { - $model = new self(); - return $model; - } } + diff --git a/tests/expected/model/Models/MainFileError/model/model_.php b/tests/expected/model/Models/MainFileError/model/model_.php new file mode 100644 index 0000000..c008f4c --- /dev/null +++ b/tests/expected/model/Models/MainFileError/model/model_.php @@ -0,0 +1,49 @@ + 'str', + ]; + + public function validate() + { + Model::validateRequired('str', $this->str, true); + parent::validate(); + } + + public function toArray($noStream = false) + { + $res = []; + if (null !== $this->str) { + $res['str'] = $this->str; + } + + return $res; + } + + public function toMap($noStream = false) + { + return $this->toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + if (isset($map['str'])) { + $model->str = $map['str']; + } + + return $model; + } + + +} + diff --git a/tests/expected/model/Models/MainFileError/model_.php b/tests/expected/model/Models/MainFileError/model_.php new file mode 100644 index 0000000..d309604 --- /dev/null +++ b/tests/expected/model/Models/MainFileError/model_.php @@ -0,0 +1,66 @@ + 'str', + 'model' => 'model', + ]; + + public function validate() + { + Model::validateRequired('str', $this->str, true); + if(null !== $this->model) { + $this->model->validate(); + } + Model::validateRequired('model', $this->model, true); + parent::validate(); + } + + public function toArray($noStream = false) + { + $res = []; + if (null !== $this->str) { + $res['str'] = $this->str; + } + + if (null !== $this->model) { + $res['model'] = null !== $this->model ? $this->model->toArray($noStream) : $this->model; + } + + return $res; + } + + public function toMap($noStream = false) + { + return $this->toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + if (isset($map['str'])) { + $model->str = $map['str']; + } + + if (isset($map['model'])) { + $model->model = \Dara\PHP\Tests\Models\MainFileError\model\model_::fromMap($map['model']); + } + + return $model; + } + + +} + diff --git a/tests/expected/model/Models/MyModel.php b/tests/expected/model/Models/MyModel.php index d9629f1..64f907e 100644 --- a/tests/expected/model/Models/MyModel.php +++ b/tests/expected/model/Models/MyModel.php @@ -1,540 +1,919 @@ 'model', + 'stringfield' => 'stringfield', + 'bytesfield' => 'bytesfield', + 'stringarrayfield' => 'stringarrayfield', + 'mapfield' => 'mapfield', + 'name' => 'realName', + 'submodel' => 'submodel', + 'submodelMap' => 'submodelMap', + 'mapModel' => 'mapModel', + 'subarraymodel' => 'subarraymodel', + 'subarray' => 'subarray', + 'ssubarray' => 'ssubarray', + 'ssubmarray' => 'ssubmarray', + 'ssubmmarray' => 'ssubmmarray', + 'maparray' => 'maparray', + 'mapsubmarray' => 'mapsubmarray', + 'moduleModelMap' => 'moduleModelMap', + 'subModelMap' => 'subModelMap', + 'modelMap' => 'modelMap', + 'moduleMap' => 'moduleMap', + 'object' => 'object', + 'readable' => 'readable', + 'writable' => 'writable', + 'existModel' => 'existModel', + 'request' => 'request', + 'complexList' => 'complexList', + 'numberfield' => 'numberfield', + 'integerField' => 'integerField', + 'floatField' => 'floatField', + 'doubleField' => 'doubleField', + 'longField' => 'longField', + 'ulongField' => 'ulongField', + 'int8Field' => 'int8Field', + 'int16Field' => 'int16Field', + 'int32Field' => 'int32Field', + 'int64Field' => 'int64Field', + 'uint8Field' => 'uint8Field', + 'uint16Field' => 'uint16Field', + 'uint32Field' => 'uint32Field', + 'uint64Field' => 'uint64Field', + 'link' => 'link', + ]; + + public function validate() + { + if(null !== $this->model) { + $this->model->validate(); + } + Model::validateRequired('model', $this->model, true); + Model::validateRequired('stringfield', $this->stringfield, true); + Model::validateRequired('bytesfield', $this->bytesfield, true); + if(is_array($this->stringarrayfield)) { + Model::validateArray($this->stringarrayfield); + } + Model::validateRequired('stringarrayfield', $this->stringarrayfield, true); + if(is_array($this->mapfield)) { + Model::validateArray($this->mapfield); + } + Model::validateRequired('mapfield', $this->mapfield, true); + Model::validateRequired('name', $this->name, true); + if(null !== $this->submodel) { + $this->submodel->validate(); + } + Model::validateRequired('submodel', $this->submodel, true); + if(is_array($this->submodelMap)) { + Model::validateArray($this->submodelMap); + } + Model::validateRequired('submodelMap', $this->submodelMap, true); + if(is_array($this->mapModel)) { + Model::validateArray($this->mapModel); + } + Model::validateRequired('mapModel', $this->mapModel, true); + if(is_array($this->subarraymodel)) { + Model::validateArray($this->subarraymodel); + } + Model::validateRequired('subarraymodel', $this->subarraymodel, true); + if(is_array($this->subarray)) { + Model::validateArray($this->subarray); + } + Model::validateRequired('subarray', $this->subarray, true); + if(is_array($this->ssubarray)) { + Model::validateArray($this->ssubarray); + } + Model::validateRequired('ssubarray', $this->ssubarray, true); + if(is_array($this->ssubmarray)) { + Model::validateArray($this->ssubmarray); + } + Model::validateRequired('ssubmarray', $this->ssubmarray, true); + if(is_array($this->ssubmmarray)) { + Model::validateArray($this->ssubmmarray); + } + Model::validateRequired('ssubmmarray', $this->ssubmmarray, true); + if(is_array($this->maparray)) { + Model::validateArray($this->maparray); + } + Model::validateRequired('maparray', $this->maparray, true); + if(is_array($this->mapsubmarray)) { + Model::validateArray($this->mapsubmarray); + } + Model::validateRequired('mapsubmarray', $this->mapsubmarray, true); + if(is_array($this->moduleModelMap)) { + Model::validateArray($this->moduleModelMap); + } + Model::validateRequired('moduleModelMap', $this->moduleModelMap, true); + if(is_array($this->subModelMap)) { + Model::validateArray($this->subModelMap); + } + Model::validateRequired('subModelMap', $this->subModelMap, true); + if(is_array($this->modelMap)) { + Model::validateArray($this->modelMap); + } + Model::validateRequired('modelMap', $this->modelMap, true); + if(is_array($this->moduleMap)) { + Model::validateArray($this->moduleMap); + } + Model::validateRequired('moduleMap', $this->moduleMap, true); + Model::validateRequired('object', $this->object, true); + Model::validateRequired('readable', $this->readable, true); + Model::validateRequired('writable', $this->writable, true); + if(null !== $this->existModel) { + $this->existModel->validate(); + } + Model::validateRequired('existModel', $this->existModel, true); + Model::validateRequired('request', $this->request, true); + if(is_array($this->complexList)) { + Model::validateArray($this->complexList); + } + Model::validateRequired('complexList', $this->complexList, true); + Model::validateRequired('numberfield', $this->numberfield, true); + Model::validateRequired('integerField', $this->integerField, true); + Model::validateRequired('floatField', $this->floatField, true); + Model::validateRequired('doubleField', $this->doubleField, true); + Model::validateRequired('longField', $this->longField, true); + Model::validateRequired('ulongField', $this->ulongField, true); + Model::validateRequired('int8Field', $this->int8Field, true); + Model::validateRequired('int16Field', $this->int16Field, true); + Model::validateRequired('int32Field', $this->int32Field, true); + Model::validateRequired('int64Field', $this->int64Field, true); + Model::validateRequired('uint8Field', $this->uint8Field, true); + Model::validateRequired('uint16Field', $this->uint16Field, true); + Model::validateRequired('uint32Field', $this->uint32Field, true); + Model::validateRequired('uint64Field', $this->uint64Field, true); + parent::validate(); + } + + public function toArray($noStream = false) + { + $res = []; + if (null !== $this->model) { + $res['model'] = null !== $this->model ? $this->model->toArray($noStream) : $this->model; + } -use Tea\PHP\Tests\Models\MyModel\model_; -use Tea\PHP\Tests\Models\MyModel\submodel; -use Tea\PHP\Tests\Models\MyModel\subarraymodel; -use Tea\PHP\Tests\Models\M; -use AlibabaCloud\Tea\Request; -use Tea\PHP\Tests\Models\M\subM; + if (null !== $this->stringfield) { + $res['stringfield'] = $this->stringfield; + } -class MyModel extends Model { - protected $_name = [ - 'name' => 'realName', - 'link' => 'link', - ]; - public function validate() { - Model::validateRequired('model', $this->model, true); - Model::validateRequired('stringfield', $this->stringfield, true); - Model::validateRequired('bytesfield', $this->bytesfield, true); - Model::validateRequired('stringarrayfield', $this->stringarrayfield, true); - Model::validateRequired('mapfield', $this->mapfield, true); - Model::validateRequired('name', $this->name, true); - Model::validateRequired('submodel', $this->submodel, true); - Model::validateRequired('submodelMap', $this->submodelMap, true); - Model::validateRequired('mapModel', $this->mapModel, true); - Model::validateRequired('subarraymodel', $this->subarraymodel, true); - Model::validateRequired('subarray', $this->subarray, true); - Model::validateRequired('maparray', $this->maparray, true); - Model::validateRequired('moduleModelMap', $this->moduleModelMap, true); - Model::validateRequired('subModelMap', $this->subModelMap, true); - Model::validateRequired('modelMap', $this->modelMap, true); - Model::validateRequired('moduleMap', $this->moduleMap, true); - Model::validateRequired('object', $this->object, true); - Model::validateRequired('readable', $this->readable, true); - Model::validateRequired('writable', $this->writable, true); - Model::validateRequired('existModel', $this->existModel, true); - Model::validateRequired('request', $this->request, true); - Model::validateRequired('complexList', $this->complexList, true); - Model::validateRequired('numberfield', $this->numberfield, true); - Model::validateRequired('integerField', $this->integerField, true); - Model::validateRequired('floatField', $this->floatField, true); - Model::validateRequired('doubleField', $this->doubleField, true); - Model::validateRequired('longField', $this->longField, true); - Model::validateRequired('ulongField', $this->ulongField, true); - Model::validateRequired('int8Field', $this->int8Field, true); - Model::validateRequired('int16Field', $this->int16Field, true); - Model::validateRequired('int32Field', $this->int32Field, true); - Model::validateRequired('int64Field', $this->int64Field, true); - Model::validateRequired('uint8Field', $this->uint8Field, true); - Model::validateRequired('uint16Field', $this->uint16Field, true); - Model::validateRequired('uint32Field', $this->uint32Field, true); - Model::validateRequired('uint64Field', $this->uint64Field, true); - } - public function toMap() { - $res = []; - if (null !== $this->model) { - $res['model'] = null !== $this->model ? $this->model->toMap() : null; - } - if (null !== $this->stringfield) { - $res['stringfield'] = $this->stringfield; - } - if (null !== $this->bytesfield) { - $res['bytesfield'] = $this->bytesfield; - } - if (null !== $this->stringarrayfield) { - $res['stringarrayfield'] = $this->stringarrayfield; - } - if (null !== $this->mapfield) { - $res['mapfield'] = $this->mapfield; - } - if (null !== $this->name) { - $res['realName'] = $this->name; - } - if (null !== $this->submodel) { - $res['submodel'] = null !== $this->submodel ? $this->submodel->toMap() : null; - } - if (null !== $this->submodelMap) { - $res['submodelMap'] = []; - if(null !== $this->submodelMap && is_array($this->submodelMap)){ - foreach($this->submodelMap as $key => $val){ - $res['submodelMap'][$key] = null !== $val ? $val->toMap() : $val; - } - } + if (null !== $this->bytesfield) { + $res['bytesfield'] = $this->bytesfield; + } + + if (null !== $this->stringarrayfield) { + if(is_array($this->stringarrayfield)) { + $res['stringarrayfield'] = []; + $n1 = 0; + foreach($this->stringarrayfield as $item1) { + $res['stringarrayfield'][$n1++] = $item1; } - if (null !== $this->mapModel) { - $res['mapModel'] = []; - if(null !== $this->mapModel && is_array($this->mapModel)){ - foreach($this->mapModel as $key => $val){ - $res['mapModel'][$key] = null !== $val ? $val->toMap() : $val; - } - } + } + } + + if (null !== $this->mapfield) { + if(is_array($this->mapfield)) { + $res['mapfield'] = []; + foreach($this->mapfield as $key1 => $value1) { + $res['mapfield'][$key1] = $value1; } - if (null !== $this->subarraymodel) { - $res['subarraymodel'] = []; - if(null !== $this->subarraymodel && is_array($this->subarraymodel)){ - $n = 0; - foreach($this->subarraymodel as $item){ - $res['subarraymodel'][$n++] = null !== $item ? $item->toMap() : $item; - } - } + } + } + + if (null !== $this->name) { + $res['realName'] = $this->name; + } + + if (null !== $this->submodel) { + $res['submodel'] = null !== $this->submodel ? $this->submodel->toArray($noStream) : $this->submodel; + } + + if (null !== $this->submodelMap) { + if(is_array($this->submodelMap)) { + $res['submodelMap'] = []; + foreach($this->submodelMap as $key1 => $value1) { + $res['submodelMap'][$key1] = null !== $value1 ? $value1->toArray($noStream) : $value1; } - if (null !== $this->subarray) { - $res['subarray'] = []; - if(null !== $this->subarray && is_array($this->subarray)){ - $n = 0; - foreach($this->subarray as $item){ - $res['subarray'][$n++] = null !== $item ? $item->toMap() : $item; - } - } + } + } + + if (null !== $this->mapModel) { + if(is_array($this->mapModel)) { + $res['mapModel'] = []; + foreach($this->mapModel as $key1 => $value1) { + $res['mapModel'][$key1] = null !== $value1 ? $value1->toArray($noStream) : $value1; } - if (null !== $this->maparray) { - $res['maparray'] = $this->maparray; + } + } + + if (null !== $this->subarraymodel) { + if(is_array($this->subarraymodel)) { + $res['subarraymodel'] = []; + $n1 = 0; + foreach($this->subarraymodel as $item1) { + $res['subarraymodel'][$n1++] = null !== $item1 ? $item1->toArray($noStream) : $item1; } - if (null !== $this->moduleModelMap) { - $res['moduleModelMap'] = []; - if(null !== $this->moduleModelMap && is_array($this->moduleModelMap)){ - foreach($this->moduleModelMap as $key => $val){ - $res['moduleModelMap'][$key] = null !== $val ? $val->toMap() : $val; - } - } + } + } + + if (null !== $this->subarray) { + if(is_array($this->subarray)) { + $res['subarray'] = []; + $n1 = 0; + foreach($this->subarray as $item1) { + $res['subarray'][$n1++] = null !== $item1 ? $item1->toArray($noStream) : $item1; } - if (null !== $this->subModelMap) { - $res['subModelMap'] = []; - if(null !== $this->subModelMap && is_array($this->subModelMap)){ - foreach($this->subModelMap as $key => $val){ - $res['subModelMap'][$key] = null !== $val ? $val->toMap() : $val; - } + } + } + + if (null !== $this->ssubarray) { + if(is_array($this->ssubarray)) { + $res['ssubarray'] = []; + $n1 = 0; + foreach($this->ssubarray as $item1) { + if(is_array($item1)) { + $res['ssubarray'][$n1++] = []; + $n2 = 0; + foreach($item1 as $item2) { + $res['ssubarray'][$n1++][$n2++] = null !== $item2 ? $item2->toArray($noStream) : $item2; } + } } - if (null !== $this->modelMap) { - $res['modelMap'] = []; - if(null !== $this->modelMap && is_array($this->modelMap)){ - foreach($this->modelMap as $key => $val){ - $res['modelMap'][$key] = null !== $val ? $val->toMap() : $val; - } + } + } + + if (null !== $this->ssubmarray) { + if(is_array($this->ssubmarray)) { + $res['ssubmarray'] = []; + $n1 = 0; + foreach($this->ssubmarray as $item1) { + if(is_array($item1)) { + $res['ssubmarray'][$n1++] = []; + $n2 = 0; + foreach($item1 as $item2) { + $res['ssubmarray'][$n1++][$n2++] = $item2; } + } } - if (null !== $this->moduleMap) { - $res['moduleMap'] = []; - if(null !== $this->moduleMap && is_array($this->moduleMap)){ - foreach($this->moduleMap as $key => $val){ - $res['moduleMap'][$key] = null !== $val ? $val->toMap() : $val; - } + } + } + + if (null !== $this->ssubmmarray) { + if(is_array($this->ssubmmarray)) { + $res['ssubmmarray'] = []; + $n1 = 0; + foreach($this->ssubmmarray as $item1) { + if(is_array($item1)) { + $res['ssubmmarray'][$n1++] = []; + $n2 = 0; + foreach($item1 as $item2) { + $res['ssubmmarray'][$n1++][$n2++] = null !== $item2 ? $item2->toArray($noStream) : $item2; } + } } - if (null !== $this->object) { - $res['object'] = $this->object; - } - if (null !== $this->readable) { - $res['readable'] = $this->readable; - } - if (null !== $this->writable) { - $res['writable'] = $this->writable; - } - if (null !== $this->existModel) { - $res['existModel'] = null !== $this->existModel ? $this->existModel->toMap() : null; - } - if (null !== $this->request) { - $res['request'] = null !== $this->request ? $this->request->toMap() : null; - } - if (null !== $this->complexList) { - $res['complexList'] = $this->complexList; - } - if (null !== $this->numberfield) { - $res['numberfield'] = $this->numberfield; - } - if (null !== $this->integerField) { - $res['integerField'] = $this->integerField; - } - if (null !== $this->floatField) { - $res['floatField'] = $this->floatField; - } - if (null !== $this->doubleField) { - $res['doubleField'] = $this->doubleField; - } - if (null !== $this->longField) { - $res['longField'] = $this->longField; - } - if (null !== $this->ulongField) { - $res['ulongField'] = $this->ulongField; + } + } + + if (null !== $this->maparray) { + if(is_array($this->maparray)) { + $res['maparray'] = []; + $n1 = 0; + foreach($this->maparray as $item1) { + if(is_array($item1)) { + $res['maparray'][$n1++] = []; + foreach($item1 as $key2 => $value2) { + $res['maparray'][$n1++][$key2] = $value2; + } + } } - if (null !== $this->int8Field) { - $res['int8Field'] = $this->int8Field; + } + } + + if (null !== $this->mapsubmarray) { + if(is_array($this->mapsubmarray)) { + $res['mapsubmarray'] = []; + $n1 = 0; + foreach($this->mapsubmarray as $item1) { + if(is_array($item1)) { + $res['mapsubmarray'][$n1++] = []; + foreach($item1 as $key2 => $value2) { + $res['mapsubmarray'][$n1++][$key2] = $value2; + } + } } - if (null !== $this->int16Field) { - $res['int16Field'] = $this->int16Field; + } + } + + if (null !== $this->moduleModelMap) { + if(is_array($this->moduleModelMap)) { + $res['moduleModelMap'] = []; + foreach($this->moduleModelMap as $key1 => $value1) { + $res['moduleModelMap'][$key1] = null !== $value1 ? $value1->toArray($noStream) : $value1; } - if (null !== $this->int32Field) { - $res['int32Field'] = $this->int32Field; + } + } + + if (null !== $this->subModelMap) { + if(is_array($this->subModelMap)) { + $res['subModelMap'] = []; + foreach($this->subModelMap as $key1 => $value1) { + $res['subModelMap'][$key1] = null !== $value1 ? $value1->toArray($noStream) : $value1; } - if (null !== $this->int64Field) { - $res['int64Field'] = $this->int64Field; + } + } + + if (null !== $this->modelMap) { + if(is_array($this->modelMap)) { + $res['modelMap'] = []; + foreach($this->modelMap as $key1 => $value1) { + $res['modelMap'][$key1] = null !== $value1 ? $value1->toArray($noStream) : $value1; } - if (null !== $this->uint8Field) { - $res['uint8Field'] = $this->uint8Field; + } + } + + if (null !== $this->moduleMap) { + if(is_array($this->moduleMap)) { + $res['moduleMap'] = []; + foreach($this->moduleMap as $key1 => $value1) { + $res['moduleMap'][$key1] = $value1; } - if (null !== $this->uint16Field) { - $res['uint16Field'] = $this->uint16Field; + } + } + + if (null !== $this->object) { + $res['object'] = $this->object; + } + + if (null !== $this->readable) { + $res['readable'] = $this->readable; + } + + if (null !== $this->writable) { + $res['writable'] = $this->writable; + } + + if (null !== $this->existModel) { + $res['existModel'] = null !== $this->existModel ? $this->existModel->toArray($noStream) : $this->existModel; + } + + if (null !== $this->request) { + $res['request'] = null !== $this->request ? $this->request->toArray($noStream) : $this->request; + } + + if (null !== $this->complexList) { + if(is_array($this->complexList)) { + $res['complexList'] = []; + $n1 = 0; + foreach($this->complexList as $item1) { + if(is_array($item1)) { + $res['complexList'][$n1++] = []; + $n2 = 0; + foreach($item1 as $item2) { + $res['complexList'][$n1++][$n2++] = $item2; + } + } } - if (null !== $this->uint32Field) { - $res['uint32Field'] = $this->uint32Field; + } + } + + if (null !== $this->numberfield) { + $res['numberfield'] = $this->numberfield; + } + + if (null !== $this->integerField) { + $res['integerField'] = $this->integerField; + } + + if (null !== $this->floatField) { + $res['floatField'] = $this->floatField; + } + + if (null !== $this->doubleField) { + $res['doubleField'] = $this->doubleField; + } + + if (null !== $this->longField) { + $res['longField'] = $this->longField; + } + + if (null !== $this->ulongField) { + $res['ulongField'] = $this->ulongField; + } + + if (null !== $this->int8Field) { + $res['int8Field'] = $this->int8Field; + } + + if (null !== $this->int16Field) { + $res['int16Field'] = $this->int16Field; + } + + if (null !== $this->int32Field) { + $res['int32Field'] = $this->int32Field; + } + + if (null !== $this->int64Field) { + $res['int64Field'] = $this->int64Field; + } + + if (null !== $this->uint8Field) { + $res['uint8Field'] = $this->uint8Field; + } + + if (null !== $this->uint16Field) { + $res['uint16Field'] = $this->uint16Field; + } + + if (null !== $this->uint32Field) { + $res['uint32Field'] = $this->uint32Field; + } + + if (null !== $this->uint64Field) { + $res['uint64Field'] = $this->uint64Field; + } + + if (null !== $this->link) { + $res['link'] = $this->link; + } + + return $res; + } + + public function toMap($noStream = false) + { + return $this->toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + if (isset($map['model'])) { + $model->model = model_::fromMap($map['model']); + } + + if (isset($map['stringfield'])) { + $model->stringfield = $map['stringfield']; + } + + if (isset($map['bytesfield'])) { + $model->bytesfield = $map['bytesfield']; + } + + if (isset($map['stringarrayfield'])) { + if(!empty($map['stringarrayfield'])) { + $model->stringarrayfield = []; + $n1 = 0; + foreach($map['stringarrayfield'] as $item1) { + $model->stringarrayfield[$n1++] = $item1; } - if (null !== $this->uint64Field) { - $res['uint64Field'] = $this->uint64Field; + } + } + + if (isset($map['mapfield'])) { + if(!empty($map['mapfield'])) { + $model->mapfield = []; + foreach($map['mapfield'] as $key1 => $value1) { + $model->mapfield[$key1] = $value1; } - if (null !== $this->link) { - $res['link'] = $this->link; + } + } + + if (isset($map['realName'])) { + $model->name = $map['realName']; + } + + if (isset($map['submodel'])) { + $model->submodel = submodel::fromMap($map['submodel']); + } + + if (isset($map['submodelMap'])) { + if(!empty($map['submodelMap'])) { + $model->submodelMap = []; + foreach($map['submodelMap'] as $key1 => $value1) { + $model->submodelMap[$key1] = submodel::fromMap($value1); } - return $res; + } } - /** - * @param array $map - * @return MyModel - */ - public static function fromMap($map = []) { - $model = new self(); - if(isset($map['model'])){ - $model->model = model_::fromMap($map['model']); + + if (isset($map['mapModel'])) { + if(!empty($map['mapModel'])) { + $model->mapModel = []; + foreach($map['mapModel'] as $key1 => $value1) { + $model->mapModel[$key1] = $value1; } - if(isset($map['stringfield'])){ - $model->stringfield = $map['stringfield']; + } + } + + if (isset($map['subarraymodel'])) { + if(!empty($map['subarraymodel'])) { + $model->subarraymodel = []; + $n1 = 0; + foreach($map['subarraymodel'] as $item1) { + $model->subarraymodel[$n1++] = subarraymodel::fromMap($item1); } - if(isset($map['bytesfield'])){ - $model->bytesfield = $map['bytesfield']; + } + } + + if (isset($map['subarray'])) { + if(!empty($map['subarray'])) { + $model->subarray = []; + $n1 = 0; + foreach($map['subarray'] as $item1) { + $model->subarray[$n1++] = $item1; } - if(isset($map['stringarrayfield'])){ - if(!empty($map['stringarrayfield'])){ - $model->stringarrayfield = $map['stringarrayfield']; + } + } + + if (isset($map['ssubarray'])) { + if(!empty($map['ssubarray'])) { + $model->ssubarray = []; + $n1 = 0; + foreach($map['ssubarray'] as $item1) { + if(!empty($item1)) { + $model->ssubarray[$n1++] = []; + $n2 = 0; + foreach($item1 as $item2) { + $model->ssubarray[$n1++][$n2++] = $item2; } + } } - if(isset($map['mapfield'])){ - $model->mapfield = $map['mapfield']; - } - if(isset($map['realName'])){ - $model->name = $map['realName']; - } - if(isset($map['submodel'])){ - $model->submodel = submodel::fromMap($map['submodel']); - } - if(isset($map['submodelMap'])){ - $model->submodelMap = $map['submodelMap']; - } - if(isset($map['mapModel'])){ - $model->mapModel = $map['mapModel']; - } - if(isset($map['subarraymodel'])){ - if(!empty($map['subarraymodel'])){ - $model->subarraymodel = []; - $n = 0; - foreach($map['subarraymodel'] as $item) { - $model->subarraymodel[$n++] = null !== $item ? subarraymodel::fromMap($item) : $item; - } + } + } + + if (isset($map['ssubmarray'])) { + if(!empty($map['ssubmarray'])) { + $model->ssubmarray = []; + $n1 = 0; + foreach($map['ssubmarray'] as $item1) { + if(!empty($item1)) { + $model->ssubmarray[$n1++] = []; + $n2 = 0; + foreach($item1 as $item2) { + $model->ssubmarray[$n1++][$n2++] = $item2; } + } } - if(isset($map['subarray'])){ - if(!empty($map['subarray'])){ - $model->subarray = []; - $n = 0; - foreach($map['subarray'] as $item) { - $model->subarray[$n++] = null !== $item ? M::fromMap($item) : $item; - } + } + } + + if (isset($map['ssubmmarray'])) { + if(!empty($map['ssubmmarray'])) { + $model->ssubmmarray = []; + $n1 = 0; + foreach($map['ssubmmarray'] as $item1) { + if(!empty($item1)) { + $model->ssubmmarray[$n1++] = []; + $n2 = 0; + foreach($item1 as $item2) { + $model->ssubmmarray[$n1++][$n2++] = Request::fromMap($item2); } + } } - if(isset($map['maparray'])){ - if(!empty($map['maparray'])){ - $model->maparray = $map['maparray']; + } + } + + if (isset($map['maparray'])) { + if(!empty($map['maparray'])) { + $model->maparray = []; + $n1 = 0; + foreach($map['maparray'] as $item1) { + if(!empty($item1)) { + $model->maparray[$n1++] = []; + foreach($item1 as $key2 => $value2) { + $model->maparray[$n1++][$key2] = $value2; } + } } - if(isset($map['moduleModelMap'])){ - $model->moduleModelMap = $map['moduleModelMap']; - } - if(isset($map['subModelMap'])){ - $model->subModelMap = $map['subModelMap']; - } - if(isset($map['modelMap'])){ - $model->modelMap = $map['modelMap']; - } - if(isset($map['moduleMap'])){ - $model->moduleMap = $map['moduleMap']; - } - if(isset($map['object'])){ - $model->object = $map['object']; - } - if(isset($map['readable'])){ - $model->readable = $map['readable']; - } - if(isset($map['writable'])){ - $model->writable = $map['writable']; - } - if(isset($map['existModel'])){ - $model->existModel = M::fromMap($map['existModel']); - } - if(isset($map['request'])){ - $model->request = Request::fromMap($map['request']); - } - if(isset($map['complexList'])){ - if(!empty($map['complexList'])){ - $model->complexList = $map['complexList']; + } + } + + if (isset($map['mapsubmarray'])) { + if(!empty($map['mapsubmarray'])) { + $model->mapsubmarray = []; + $n1 = 0; + foreach($map['mapsubmarray'] as $item1) { + if(!empty($item1)) { + $model->mapsubmarray[$n1++] = []; + foreach($item1 as $key2 => $value2) { + $model->mapsubmarray[$n1++][$key2] = $value2; } + } } - if(isset($map['numberfield'])){ - $model->numberfield = $map['numberfield']; - } - if(isset($map['integerField'])){ - $model->integerField = $map['integerField']; - } - if(isset($map['floatField'])){ - $model->floatField = $map['floatField']; - } - if(isset($map['doubleField'])){ - $model->doubleField = $map['doubleField']; - } - if(isset($map['longField'])){ - $model->longField = $map['longField']; - } - if(isset($map['ulongField'])){ - $model->ulongField = $map['ulongField']; - } - if(isset($map['int8Field'])){ - $model->int8Field = $map['int8Field']; - } - if(isset($map['int16Field'])){ - $model->int16Field = $map['int16Field']; - } - if(isset($map['int32Field'])){ - $model->int32Field = $map['int32Field']; - } - if(isset($map['int64Field'])){ - $model->int64Field = $map['int64Field']; - } - if(isset($map['uint8Field'])){ - $model->uint8Field = $map['uint8Field']; + } + } + + if (isset($map['moduleModelMap'])) { + if(!empty($map['moduleModelMap'])) { + $model->moduleModelMap = []; + foreach($map['moduleModelMap'] as $key1 => $value1) { + $model->moduleModelMap[$key1] = Request::fromMap($value1); } - if(isset($map['uint16Field'])){ - $model->uint16Field = $map['uint16Field']; + } + } + + if (isset($map['subModelMap'])) { + if(!empty($map['subModelMap'])) { + $model->subModelMap = []; + foreach($map['subModelMap'] as $key1 => $value1) { + $model->subModelMap[$key1] = subM::fromMap($value1); } - if(isset($map['uint32Field'])){ - $model->uint32Field = $map['uint32Field']; + } + } + + if (isset($map['modelMap'])) { + if(!empty($map['modelMap'])) { + $model->modelMap = []; + foreach($map['modelMap'] as $key1 => $value1) { + $model->modelMap[$key1] = $value1; } - if(isset($map['uint64Field'])){ - $model->uint64Field = $map['uint64Field']; + } + } + + if (isset($map['moduleMap'])) { + if(!empty($map['moduleMap'])) { + $model->moduleMap = []; + foreach($map['moduleMap'] as $key1 => $value1) { + $model->moduleMap[$key1] = $value1; } - if(isset($map['link'])){ - $model->link = $map['link']; + } + } + + if (isset($map['object'])) { + $model->object = $map['object']; + } + + if (isset($map['readable'])) { + $model->readable = $map['readable']; + } + + if (isset($map['writable'])) { + $model->writable = $map['writable']; + } + + if (isset($map['existModel'])) { + $model->existModel = M::fromMap($map['existModel']); + } + + if (isset($map['request'])) { + $model->request = \AlibabaCloud\Dara\Request::fromMap($map['request']); + } + + if (isset($map['complexList'])) { + if(!empty($map['complexList'])) { + $model->complexList = []; + $n1 = 0; + foreach($map['complexList'] as $item1) { + if(!empty($item1)) { + $model->complexList[$n1++] = []; + $n2 = 0; + foreach($item1 as $item2) { + $model->complexList[$n1++][$n2++] = $item2; + } + } } - return $model; + } + } + + if (isset($map['numberfield'])) { + $model->numberfield = $map['numberfield']; } - /** - * @var model_ - */ - public $model; - /** - * @var string - */ - public $stringfield; + if (isset($map['integerField'])) { + $model->integerField = $map['integerField']; + } + + if (isset($map['floatField'])) { + $model->floatField = $map['floatField']; + } + + if (isset($map['doubleField'])) { + $model->doubleField = $map['doubleField']; + } + + if (isset($map['longField'])) { + $model->longField = $map['longField']; + } + + if (isset($map['ulongField'])) { + $model->ulongField = $map['ulongField']; + } + + if (isset($map['int8Field'])) { + $model->int8Field = $map['int8Field']; + } + + if (isset($map['int16Field'])) { + $model->int16Field = $map['int16Field']; + } + + if (isset($map['int32Field'])) { + $model->int32Field = $map['int32Field']; + } + + if (isset($map['int64Field'])) { + $model->int64Field = $map['int64Field']; + } + + if (isset($map['uint8Field'])) { + $model->uint8Field = $map['uint8Field']; + } + + if (isset($map['uint16Field'])) { + $model->uint16Field = $map['uint16Field']; + } - /** - * @var int[] - */ - public $bytesfield; + if (isset($map['uint32Field'])) { + $model->uint32Field = $map['uint32Field']; + } + + if (isset($map['uint64Field'])) { + $model->uint64Field = $map['uint64Field']; + } + + if (isset($map['link'])) { + $model->link = $map['link']; + } + + return $model; + } - /** - * @var string[] - */ - public $stringarrayfield; - - /** - * @var string[] - */ - public $mapfield; - - /** - * @var string - */ - public $name; - - /** - * @var submodel - */ - public $submodel; - - /** - * @var submodel[] - */ - public $submodelMap; - - /** - * @var M[] - */ - public $mapModel; - - /** - * @var subarraymodel[] - */ - public $subarraymodel; - - /** - * @var M[] - */ - public $subarray; - - /** - * @var mixed[][] - */ - public $maparray; - - /** - * @var \import\Models\Request[] - */ - public $moduleModelMap; - - /** - * @var subM[] - */ - public $subModelMap; - - /** - * @var M[] - */ - public $modelMap; - - /** - * @var importClient[] - */ - public $moduleMap; - - /** - * @var mixed[] - */ - public $object; - - /** - * @var Stream - */ - public $readable; - - /** - * @var Stream - */ - public $writable; - - /** - * @var M - */ - public $existModel; - - /** - * @var Request - */ - public $request; - - /** - * @var string[][] - */ - public $complexList; - - /** - * @var int - */ - public $numberfield; - - /** - * @var int - */ - public $integerField; - - /** - * @var float - */ - public $floatField; - - /** - * @var float - */ - public $doubleField; - - /** - * @var int - */ - public $longField; - - /** - * @var int - */ - public $ulongField; - - /** - * @var int - */ - public $int8Field; - - /** - * @var int - */ - public $int16Field; - - /** - * @var int - */ - public $int32Field; - - /** - * @var int - */ - public $int64Field; - - /** - * @var int - */ - public $uint8Field; - - /** - * @var int - */ - public $uint16Field; - - /** - * @var int - */ - public $uint32Field; - - /** - * @var int - */ - public $uint64Field; - - /** - * @example http://*\/*.png - * @var string - */ - public $link; } + diff --git a/tests/expected/model/Models/MyModel/model/model_.php b/tests/expected/model/Models/MyModel/model/model_.php index a9ae372..d589f5a 100644 --- a/tests/expected/model/Models/MyModel/model/model_.php +++ b/tests/expected/model/Models/MyModel/model/model_.php @@ -1,35 +1,49 @@ 'str', + ]; -use AlibabaCloud\Tea\Model; + public function validate() + { + Model::validateRequired('str', $this->str, true); + parent::validate(); + } -class model_ extends Model { - public function validate() { - Model::validateRequired('str', $this->str, true); - } - public function toMap() { - $res = []; - if (null !== $this->str) { - $res['str'] = $this->str; - } - return $res; + public function toArray($noStream = false) + { + $res = []; + if (null !== $this->str) { + $res['str'] = $this->str; } - /** - * @param array $map - * @return model_ - */ - public static function fromMap($map = []) { - $model = new self(); - if(isset($map['str'])){ - $model->str = $map['str']; - } - return $model; + + return $res; + } + + public function toMap($noStream = false) + { + return $this->toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + if (isset($map['str'])) { + $model->str = $map['str']; } - /** - * @var string - */ - public $str; + + return $model; + } + } + diff --git a/tests/expected/model/Models/MyModel/model_.php b/tests/expected/model/Models/MyModel/model_.php index f55e0d6..ecc959e 100644 --- a/tests/expected/model/Models/MyModel/model_.php +++ b/tests/expected/model/Models/MyModel/model_.php @@ -1,47 +1,66 @@ 'str', + 'model' => 'model', + ]; -use AlibabaCloud\Tea\Model; + public function validate() + { + Model::validateRequired('str', $this->str, true); + if(null !== $this->model) { + $this->model->validate(); + } + Model::validateRequired('model', $this->model, true); + parent::validate(); + } -class model_ extends Model { - public function validate() { - Model::validateRequired('str', $this->str, true); - Model::validateRequired('model', $this->model, true); + public function toArray($noStream = false) + { + $res = []; + if (null !== $this->str) { + $res['str'] = $this->str; } - public function toMap() { - $res = []; - if (null !== $this->str) { - $res['str'] = $this->str; - } - if (null !== $this->model) { - $res['model'] = null !== $this->model ? $this->model->toMap() : null; - } - return $res; + + if (null !== $this->model) { + $res['model'] = null !== $this->model ? $this->model->toArray($noStream) : $this->model; } - /** - * @param array $map - * @return model_ - */ - public static function fromMap($map = []) { - $model = new self(); - if(isset($map['str'])){ - $model->str = $map['str']; - } - if(isset($map['model'])){ - $model->model = \Tea\PHP\Tests\Models\MyModel\model\model_::fromMap($map['model']); - } - return $model; + + return $res; + } + + public function toMap($noStream = false) + { + return $this->toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + if (isset($map['str'])) { + $model->str = $map['str']; + } + + if (isset($map['model'])) { + $model->model = \Dara\PHP\Tests\Models\MyModel\model\model_::fromMap($map['model']); } - /** - * @var string - */ - public $str; - /** - * @var \Tea\PHP\Tests\Models\MyModel\model\model_ - */ - public $model; + return $model; + } + } + diff --git a/tests/expected/model/Models/MyModel/subarraymodel.php b/tests/expected/model/Models/MyModel/subarraymodel.php index 7d64341..707740d 100644 --- a/tests/expected/model/Models/MyModel/subarraymodel.php +++ b/tests/expected/model/Models/MyModel/subarraymodel.php @@ -1,22 +1,35 @@ toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + return $model; + } -use AlibabaCloud\Tea\Model; -class subarraymodel extends Model { - public function validate() {} - public function toMap() { - $res = []; - return $res; - } - /** - * @param array $map - * @return subarraymodel - */ - public static function fromMap($map = []) { - $model = new self(); - return $model; - } } + diff --git a/tests/expected/model/Models/MyModel/submodel.php b/tests/expected/model/Models/MyModel/submodel.php index ad444e6..214a482 100644 --- a/tests/expected/model/Models/MyModel/submodel.php +++ b/tests/expected/model/Models/MyModel/submodel.php @@ -1,49 +1,67 @@ 'stringfield', + 'model' => 'model', + ]; -use AlibabaCloud\Tea\Model; + public function validate() + { + Model::validateRequired('stringfield', $this->stringfield, true); + if(null !== $this->model) { + $this->model->validate(); + } + Model::validateRequired('model', $this->model, true); + parent::validate(); + } -use Tea\PHP\Tests\Models\MyModel\submodel\model_; + public function toArray($noStream = false) + { + $res = []; + if (null !== $this->stringfield) { + $res['stringfield'] = $this->stringfield; + } -class submodel extends Model { - public function validate() { - Model::validateRequired('stringfield', $this->stringfield, true); - Model::validateRequired('model', $this->model, true); + if (null !== $this->model) { + $res['model'] = null !== $this->model ? $this->model->toArray($noStream) : $this->model; } - public function toMap() { - $res = []; - if (null !== $this->stringfield) { - $res['stringfield'] = $this->stringfield; - } - if (null !== $this->model) { - $res['model'] = null !== $this->model ? $this->model->toMap() : null; - } - return $res; + + return $res; + } + + public function toMap($noStream = false) + { + return $this->toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + if (isset($map['stringfield'])) { + $model->stringfield = $map['stringfield']; } - /** - * @param array $map - * @return submodel - */ - public static function fromMap($map = []) { - $model = new self(); - if(isset($map['stringfield'])){ - $model->stringfield = $map['stringfield']; - } - if(isset($map['model'])){ - $model->model = model_::fromMap($map['model']); - } - return $model; + + if (isset($map['model'])) { + $model->model = model_::fromMap($map['model']); } - /** - * @var string - */ - public $stringfield; - /** - * @var model_ - */ - public $model; + return $model; + } + } + diff --git a/tests/expected/model/Models/MyModel/submodel/model_.php b/tests/expected/model/Models/MyModel/submodel/model_.php index 42d86a5..31b9e4f 100644 --- a/tests/expected/model/Models/MyModel/submodel/model_.php +++ b/tests/expected/model/Models/MyModel/submodel/model_.php @@ -1,35 +1,49 @@ 'str', + ]; -use AlibabaCloud\Tea\Model; + public function validate() + { + Model::validateRequired('str', $this->str, true); + parent::validate(); + } -class model_ extends Model { - public function validate() { - Model::validateRequired('str', $this->str, true); - } - public function toMap() { - $res = []; - if (null !== $this->str) { - $res['str'] = $this->str; - } - return $res; + public function toArray($noStream = false) + { + $res = []; + if (null !== $this->str) { + $res['str'] = $this->str; } - /** - * @param array $map - * @return model_ - */ - public static function fromMap($map = []) { - $model = new self(); - if(isset($map['str'])){ - $model->str = $map['str']; - } - return $model; + + return $res; + } + + public function toMap($noStream = false) + { + return $this->toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + if (isset($map['str'])) { + $model->str = $map['str']; } - /** - * @var string - */ - public $str; + + return $model; + } + } + diff --git a/tests/expected/model/Models/model_.php b/tests/expected/model/Models/model_.php index 7145b32..43b4667 100644 --- a/tests/expected/model/Models/model_.php +++ b/tests/expected/model/Models/model_.php @@ -1,35 +1,49 @@ 'str', + ]; -use AlibabaCloud\Tea\Model; + public function validate() + { + Model::validateRequired('str', $this->str, true); + parent::validate(); + } -class model_ extends Model { - public function validate() { - Model::validateRequired('str', $this->str, true); - } - public function toMap() { - $res = []; - if (null !== $this->str) { - $res['str'] = $this->str; - } - return $res; + public function toArray($noStream = false) + { + $res = []; + if (null !== $this->str) { + $res['str'] = $this->str; } - /** - * @param array $map - * @return model_ - */ - public static function fromMap($map = []) { - $model = new self(); - if(isset($map['str'])){ - $model->str = $map['str']; - } - return $model; + + return $res; + } + + public function toMap($noStream = false) + { + return $this->toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + if (isset($map['str'])) { + $model->str = $map['str']; } - /** - * @var string - */ - public $str; + + return $model; + } + } + diff --git a/tests/expected/multi/Client.php b/tests/expected/multi/Client.php new file mode 100644 index 0000000..5aa2415 --- /dev/null +++ b/tests/expected/multi/Client.php @@ -0,0 +1,46 @@ +_user = new Info([ + 'name' => 'test', + ]); + } + + + /** + * @return string + */ + public function test3() + { + $it = UtilClient::test1(); + + foreach($it as $test) { + yield $test; + } + } + + /** + * @return int + */ + public function test4() + { + $api = new ApiClient(); + $status = $api->test3(); + return $status; + } + +} diff --git a/tests/expected/multi/api.php b/tests/expected/multi/api.php new file mode 100644 index 0000000..0c7b62f --- /dev/null +++ b/tests/expected/multi/api.php @@ -0,0 +1,74 @@ + 'retry', + ]; + + $_retriesAttempted = 0; + $_lastRequest = null; + $_lastResponse = null; + $_context = new RetryPolicyContext([ + 'retriesAttempted' => $_retriesAttempted, + ]); + while (Dara::shouldRetry($_runtime['retryOptions'], $_context)) { + if ($_retriesAttempted > 0) { + $_backoffTime = Dara::getBackoffDelay($_runtime['retryOptions'], $_context); + if ($_backoffTime > 0) { + Dara::sleep($_backoffTime); + } + } + + $_retriesAttempted++; + try { + $_request = new Request(); + $_reqeust->protocol = 'https'; + $_reqeust->method = 'DELETE'; + $_reqeust->pathname = '/'; + $_reqeust->headers = [ + 'host' => 'test.aliyun.com', + 'accept' => 'application/json', + 'test' => UserModel::test1(), + ]; + $_reqeust->query = UtilClient::getQuery(); + $_response = Dara::send($_request, $_runtime); + $_lastRequest = $_request; + $_lastResponse = $_response; + + return $_response->statusCode; + } catch (DaraException $e) { + $_context = new RetryPolicyContext([ + 'retriesAttempted' => $_retriesAttempted, + 'lastRequest' => $_lastRequest, + 'lastResponse' => $_lastResponse, + 'exception' => $e, + ]); + continue; + } + } + + throw DaraUnableRetryException($_context); + } + + +} diff --git a/tests/expected/multi/lib/util.php b/tests/expected/multi/lib/util.php new file mode 100644 index 0000000..40b9438 --- /dev/null +++ b/tests/expected/multi/lib/util.php @@ -0,0 +1,25 @@ + 'name', + 'age' => 'age', + 'runtime' => 'runtime', + ]; + + public function validate() + { + Model::validateRequired('name', $this->name, true); + Model::validateRequired('age', $this->age, true); + if(null !== $this->runtime) { + $this->runtime->validate(); + } + Model::validateRequired('runtime', $this->runtime, true); + parent::validate(); + } + + public function toArray($noStream = false) + { + $res = []; + if (null !== $this->name) { + $res['name'] = $this->name; + } + + if (null !== $this->age) { + $res['age'] = $this->age; + } + + if (null !== $this->runtime) { + $res['runtime'] = null !== $this->runtime ? $this->runtime->toArray($noStream) : $this->runtime; + } + + return $res; + } + + public function toMap($noStream = false) + { + return $this->toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + if (isset($map['name'])) { + $model->name = $map['name']; + } + + if (isset($map['age'])) { + $model->age = $map['age']; + } + + if (isset($map['runtime'])) { + $model->runtime = RuntimeOptions::fromMap($map['runtime']); + } + + return $model; + } + + +} + diff --git a/tests/expected/multi/model/user.php b/tests/expected/multi/model/user.php new file mode 100644 index 0000000..2bfe694 --- /dev/null +++ b/tests/expected/multi/model/user.php @@ -0,0 +1,32 @@ + $f; - $h = $e >= $f; - $h = $e < $f; - $h = $e <= $f; - } + /** + * @param string[] $args + * @return void + */ + static public function main($args) + { + $a = '123'; + $b = MathUtil::parseInt($a); + $c = floatval(''.$b); + $d = DaraMathUtil::random(); + } + } diff --git a/tests/expected/package/composer.json b/tests/expected/package/composer.json index 09af120..f891b83 100644 --- a/tests/expected/package/composer.json +++ b/tests/expected/package/composer.json @@ -1,12 +1,11 @@ { "name": "darabonba/package", - "description": "Darabonba Package Test", "type": "library", - "license": "Apache-2.0", + "description": "Darabonba Package Test", + "github": "", + "main": "src/Client.php", "authors": [], - "require": { - "php": ">5.5" - }, + "license": "Apache-2.0", "autoload": { "psr-4": { "Darabonba\\Package\\": "src" @@ -20,5 +19,8 @@ "preferred-install": "dist", "optimize-autoloader": true }, + "require": { + "php": ">5.5" + }, "prefer-stable": true } \ No newline at end of file diff --git a/tests/expected/package/src/Client.php b/tests/expected/package/src/Client.php index 47cdaaf..8957683 100644 --- a/tests/expected/package/src/Client.php +++ b/tests/expected/package/src/Client.php @@ -1,7 +1,10 @@ method = "GET"; - $_request->pathname = "/"; - $_request->headers = [ - "host" => "www.test.com" - ]; - if (true) { - $_request->headers["host"] = "www.test2.com"; - } - $_lastRequest = $_request; - $_response= Tea::send($_request); - if (true) { - throw new TeaError($_request, $_response); - } - else { - true; - } - self::helloIf(); - !false; - $a = null; - $a = "string"; - return null; + /** + * @return void + */ + public function hello() + { + $_request = new Request(); + $_reqeust->method = 'GET'; + $_reqeust->pathname = '/'; + $_reqeust->headers = [ + 'host' => 'www.test.com', + ]; + if (true) { + @$_reqeust->headers['host'] = 'www.test2.com'; } - /** - * @return void - */ - public static function helloIf(){ - if (true) {} - if (true) {} - else if (true) {} - else {} + $_response = Dara::send($_request); + + if (true) { + throw DaraUnableRetryException($_lastRequest, $_lastException); + } else { + true; } - /** - * @return void - * @throws TeaError - */ - public static function helloThrow(){ - throw new TeaError([]); + self::helloIf(); + !false; + $a = null; + $a = 'string'; + return null; + } + + /** + * @return void + */ + static public function helloIf() + { + if (true) { + } - /** - * @return void - */ - public static function helloForBreak(){ - foreach([] as $item){ - break; - } + if (true) { + + } else if (true) { + + } else { + } - /** - * @return void - */ - public static function helloWhile(){ - while (true) { - break; - } + } + + /** + * @return void + */ + static public function helloThrow() + { + throw new DaraException([ ]); + } + + /** + * @return void + */ + static public function helloForBreak() + { + + foreach([ ] as $item) { + break; } + } + + /** + * @return void + */ + static public function helloWhile() + { - /** - * @return void - */ - public static function helloDeclare(){ - $hello = "world"; - $helloNull = null; - $hello = "hehe"; + while (true) { + break; } + } + + /** + * @return void + */ + static public function helloDeclare() + { + $hello = 'world'; + $helloNull = null; + $hello = 'hehe'; + } + } diff --git a/tests/expected/super/Client.php b/tests/expected/super/Client.php index 51f97b3..43634b2 100644 --- a/tests/expected/super/Client.php +++ b/tests/expected/super/Client.php @@ -1,12 +1,17 @@ 5.5", - "guzzlehttp/psr7": "^1.8.5 || ^2.2.1", - "source": "^*", - "alibabacloud/tea": "^3.1.23", - "guzzlehttp/guzzle": "^6.5.6 || ^7.4.3" - }, + "license": "Apache-2.0", "autoload": { "psr-4": { "Darabonba\\Tests\\": "src" @@ -24,5 +19,12 @@ "preferred-install": "dist", "optimize-autoloader": true }, + "require": { + "php": ">5.5", + "scope/name": "1.0.0", + "guzzlehttp/psr7": "^1.8.5 || ^2.2.1", + "alibabacloud/tea": "^3.1.23", + "guzzlehttp/guzzle": "^6.5.6 || ^7.4.3" + }, "prefer-stable": true } \ No newline at end of file diff --git a/tests/expected/typedef/src/Client.php b/tests/expected/typedef/src/Client.php index 34b8371..3d3b136 100644 --- a/tests/expected/typedef/src/Client.php +++ b/tests/expected/typedef/src/Client.php @@ -1,65 +1,77 @@ _vid = $request; + $this->_model = $model; + } + - public function __construct($request, $model){ - $this->_vid = $request; - $this->_model = $model; - } + /** + * @param Request $test1 + * @param array $test2 + * @param Model $test3 + * @return void + */ + public function main($test1, $test2, $test3) + { + $oss = new SourceClient($test1); + $m = new M([ + 'a' => $test1, + 'b' => $test2, + ]); + $this->_vid = $test1; + $this->_model = $test3; + } - /** - * @param Request $test1 - * @param array $test2 - * @param Model $test3 - * @return void - */ - public function main($test1, $test2, $test3){ - $oss = new SourceClient($test1); - $m = new M([ - "a" => $test1, - "b" => $test2 - ]); - $this->_vid = $test1; - $this->_model = $test3; - } + /** + * @param Request $req + * @return Response + */ + public function testHttpRequest($req) + { + return self::testHttpRequestWith('test', $req); + } - /** - * @param Request $req - * @return Response - */ - public function testHttpRequest($req){ - return self::testHttpRequestWith("test", $req); - } + /** + * @param string $method + * @param Request $req + * @return Response + */ + static public function testHttpRequestWith($method, $req) + { + throw new RuntimeException('Un-implemented!'); + } - /** - * @param string $method - * @param Request $req - * @return Response - */ - public static function testHttpRequestWith($method, $req){ - throw new Exception('Un-implemented'); - } + /** + * @param string $method + * @param array $headers + * @return Response + */ + static public function testHttpHeader($method, $headers) + { + throw new RuntimeException('Un-implemented!'); + } - /** - * @param string $method - * @param array $headers - * @return Response - */ - public static function testHttpHeader($method, $headers){ - throw new Exception('Un-implemented'); - } } diff --git a/tests/expected/typedef/src/Models/M.php b/tests/expected/typedef/src/Models/M.php index 7c5edbc..09e90a7 100644 --- a/tests/expected/typedef/src/Models/M.php +++ b/tests/expected/typedef/src/Models/M.php @@ -1,38 +1,75 @@ 'a', + 'b' => 'b', + 'c' => 'c', + ]; -use AlibabaCloud\Tea\Model; + public function validate() + { + parent::validate(); + } -class M extends Model { - public function validate() {} - public function toMap() { - $res = []; - if (null !== $this->a) { - $res['a'] = $this->a; - } - if (null !== $this->b) { - $res['b'] = $this->b; - } - return $res; + public function toArray($noStream = false) + { + $res = []; + if (null !== $this->a) { + $res['a'] = $this->a; + } + + if (null !== $this->b) { + $res['b'] = $this->b; } - /** - * @param array $map - * @return M - */ - public static function fromMap($map = []) { - $model = new self(); - if(isset($map['a'])){ - $model->a = $map['a']; - } - if(isset($map['b'])){ - $model->b = $map['b']; - } - return $model; + + if (null !== $this->c) { + $res['c'] = $this->c; } - public $a; - public $b; + return $res; + } + + public function toMap($noStream = false) + { + return $this->toArray($noStream); + } + + public static function fromMap($map = []) + { + $model = new self(); + if (isset($map['a'])) { + $model->a = $map['a']; + } + + if (isset($map['b'])) { + $model->b = $map['b']; + } + + if (isset($map['c'])) { + $model->c = $map['c']; + } + + return $model; + } + } + diff --git a/tests/fixtures/alias/libraries/Import/Darafile b/tests/fixtures/alias/libraries/Import/Darafile index 089d438..8cc2b8f 100644 --- a/tests/fixtures/alias/libraries/Import/Darafile +++ b/tests/fixtures/alias/libraries/Import/Darafile @@ -3,6 +3,9 @@ "name": "import", "version": "0.0.1", "main": "./import.dara", + "releases": { + "php": "scope/name:1.0.0" + }, "php": { "package": "Import", "clientName": "Client", diff --git a/tests/fixtures/alias/libraries/Import/import.dara b/tests/fixtures/alias/libraries/Import/import.dara index a693551..ce3be54 100644 --- a/tests/fixtures/alias/libraries/Import/import.dara +++ b/tests/fixtures/alias/libraries/Import/import.dara @@ -1 +1,3 @@ -static function test(): void; +model M {} + +static function test(m: M): void; diff --git a/tests/fixtures/alias/libraries/Source/Darafile b/tests/fixtures/alias/libraries/Source/Darafile index d62e059..02e3ae8 100644 --- a/tests/fixtures/alias/libraries/Source/Darafile +++ b/tests/fixtures/alias/libraries/Source/Darafile @@ -3,6 +3,9 @@ "name": "source", "version": "0.0.1", "main": "./source.dara", + "releases": { + "php": "scope/name:1.0.0" + }, "php": { "package": "Source", "clientName": "Client", diff --git a/tests/fixtures/alias/libraries/Source/source.dara b/tests/fixtures/alias/libraries/Source/source.dara index a693551..ce3be54 100644 --- a/tests/fixtures/alias/libraries/Source/source.dara +++ b/tests/fixtures/alias/libraries/Source/source.dara @@ -1 +1,3 @@ -static function test(): void; +model M {} + +static function test(m: M): void; diff --git a/tests/fixtures/alias/main.dara b/tests/fixtures/alias/main.dara index dcbc363..baf24e7 100644 --- a/tests/fixtures/alias/main.dara +++ b/tests/fixtures/alias/main.dara @@ -2,6 +2,8 @@ import Source; import Import; static async function emptyModel(): void { - Import.test(); - Source.test(); + var m1 = new Source.M{}; + var m2 = new Import.M{}; + Import.test(m2); + Source.test(m1); } \ No newline at end of file diff --git a/tests/fixtures/annotation/main.dara b/tests/fixtures/annotation/main.dara index b14e575..ee0b54e 100644 --- a/tests/fixtures/annotation/main.dara +++ b/tests/fixtures/annotation/main.dara @@ -13,7 +13,7 @@ model Test{ /** Init Func */ -init(){ +init() { } /** diff --git a/tests/fixtures/builtin/Darafile b/tests/fixtures/builtin/Darafile new file mode 100644 index 0000000..3329a3a --- /dev/null +++ b/tests/fixtures/builtin/Darafile @@ -0,0 +1,6 @@ +{ + "scope": "darabonba", + "name": "main", + "version": "0.0.1", + "main": "./main.dara" +} \ No newline at end of file diff --git a/tests/fixtures/builtin/main.dara b/tests/fixtures/builtin/main.dara new file mode 100644 index 0000000..653f8c5 --- /dev/null +++ b/tests/fixtures/builtin/main.dara @@ -0,0 +1,346 @@ +static async function arrayTest(args: [string]): void { + if((args.length() > 0) && args.contains('cn-hanghzou')) { + var index = args.index('cn-hanghzou'); + var regionId: string = args.get(index); + var all = args.join(','); + var first = args.shift(); + var last = args.pop(); + var length1 = args.unshift(first); + var length2 = args.push(last); + var length3:integer = length1 + length2; + var longStr = 'long' + first + last; + var fullStr = args.join(','); + var newArr = ['test']; + var cArr: [ string ] = newArr.concat(args); + var acsArr = newArr.sort('asc'); + var descArr = newArr.sort('desc'); + var llArr: [string] = acsArr.concat(descArr); + llArr.append('test', 10); + llArr.remove('test'); + } +} + +static async function bytesTest(args: [string]): void { + var fullStr = args.join(','); + var data = fullStr.toBytes('utf8'); + var newFullStr = data.toString(); + if(fullStr != newFullStr) { + return; + } + var hexStr = data.toHex(); + + var base64Str = data.toBase64(); + + var length: integer = data.length(); + + var obj = data.toJSON(); + + var data2 = $Bytes.from(fullStr, 'base64'); +} + +static async function dateTest(args: [string]): void { + var date = new $Date('2023-09-12 17:47:31.916000 +0800 UTC'); + var dateStr = date.format('YYYY-MM-DD HH:mm:ss'); + var timestamp = date.unix(); + var yesterday = date.sub('day', 1); + var oneDay = date.diff('day', yesterday); + var tomorrow = date.add('day', 1); + var twoDay = tomorrow.diff('day', date) + oneDay; + var hour = date.hour(); + var minute = date.minute(); + var second = date.second(); + var dayOfMonth = date.dayOfMonth(); + var dayOfWeek = date.dayOfWeek(); + var weekOfYear = date.weekOfYear(); + var month = date.month(); + var year = date.year(); +} + +static async function envTest(args: [string]): void { + var es = $Env.get('TEST'); + var ma = $Env.set('TEST', es + 'test'); + var ma1 = $Env.set('TEST1', 'test1'); + var ma2 = $Env.set('TEST2', es); +} + +static async function fileTest(args: [string]): void { + if($File.exists('/tmp/test')) { + var file = new $File('/tmp/test'); + var path = file.path(); + var length = file.length() + 10; + var createTime = file.createTime(); + var modifyTime = file.modifyTime(); + var timeLong = modifyTime.diff('minute', createTime); + var data = file.read(300); + file.write($Bytes.from('test', 'utf8')); + var rs:readable = $File.createReadStream('/tmp/test'); + var ws:writable = $File.createWriteStream('/tmp/test'); + } +} + +static async function formTest(args: [string]): void { + var m = { + key1 = 'test1', + key2 = 'test2', + key3 = 3, + key4 = { + key5 = 123, + key6 = '321' + } + }; + var form = $Form.toFormString(m); + form = form + "&key7=23233&key8=" + $Form.getBoundary(); + + var r:readable = $Form.toFileForm(m, $Form.getBoundary()); +} + +model M { + a: string +} + +static async function jsonTest(args: [string]): void { + var m = { + key1 = 'test1', + key2 = 'test2', + key3 = 3, + key4 = { + key5 = 123, + key6 = '321' + } + }; + + var m1 = new M { + a = 'test', + }; + + var ms = $JSON.stringify(m); + var m1s = $JSON.stringify(m1); + var ma = $JSON.parseJSON(ms); + var arrStr = '[1,2,3,4]'; + var arr = $JSON.parseJSON(arrStr); +} + +static async function logerTest(args: [string]): void { + $Logger.log("test"); + $Logger.info("test"); + $Logger.warning("test"); + $Logger.debug("test"); + $Logger.error("test"); +} + +static async function mapTestCase(args: [string]): void { + var mapTest = { + key1 = 'value1', + key2 = 'value2', + key3 = 'value3', + }; + + var length = mapTest.length(); + var num = length + 3; + var keys = mapTest.keySet(); + var allKey = ''; + for(var key : keys) { + allKey = allKey + key; + } + var entries: [ entry[string] ] = mapTest.entries(); + var newKey = ''; + var newValue = ''; + for(var e : entries) { + newKey = newKey + e.key(); + newValue = newValue + e.value(); + } + + var json = mapTest.toJSON(); + var mapTest2 = { + key1 = 'value4', + key4 = 'value5', + }; + var mapTest3 = mapTest.merge(mapTest2); + if(mapTest3['key1'] == 'value4') { + return; + } +} + +static async function numberTest(args: [string]): void { + var num = 3.2; + var inum: integer = num.parseInt(); + var lnum: long = num.parseLong(); + var fnum: float = num.parseFloat(); + var dnum: double = num.parseDouble(); + + inum = inum.parseInt(); + lnum = inum.parseLong(); + fnum = inum.parseFloat(); + dnum = inum.parseDouble(); + + inum = lnum.parseInt(); + lnum = lnum.parseLong(); + fnum = lnum.parseFloat(); + dnum = lnum.parseDouble(); + + inum = fnum.parseInt(); + lnum = fnum.parseLong(); + fnum = fnum.parseFloat(); + dnum = fnum.parseDouble(); + + inum = dnum.parseInt(); + lnum = dnum.parseLong(); + fnum = dnum.parseFloat(); + dnum = dnum.parseDouble(); + + lnum = inum.itol(); + inum = lnum.ltoi(); + + var randomNum = $Number.random(); + inum = $Number.floor(inum); + inum = $Number.round(inum); + var min = $Number.min(inum, fnum); + var max = $Number.max(inum, fnum); +} + +static async function streamTest(args: [string]): void { + if($File.exists('/tmp/test')) { + var rs:readable = $File.createReadStream('/tmp/test'); + var ws:writable = $File.createWriteStream('/tmp/test'); + var data = rs.read(30); + ws.write(data); + rs.pipe(ws); + data = $Stream.readAsBytes(rs); + var obj = $Stream.readAsJSON(rs); + var jsonStr = $Stream.readAsString(rs); + } +} + +static async function stringTest(args: [string]): void { + var fullStr = args.join(','); + args = fullStr.split(','); + + if((fullStr.length() > 0) && fullStr.contains('hangzhou')) { + var newStr1 = fullStr.replace('/hangzhou/g', 'beijing'); + } + + if(fullStr.hasPrefix('cn')) { + var newStr2 = fullStr.replace('/cn/gi', 'zh'); + } + + if(fullStr.hasSuffix('beijing')) { + var newStr3 = fullStr.replace('/beijing/', 'chengdu'); + } + + var start = fullStr.index('beijing'); + + var end = start + 7; + + var region = fullStr.subString(start, end); + + var lowerRegion = region.toLower(); + var upperRegion = region.toUpper(); + + if(region.equals('beijing')) { + region = region + ' '; + region = region.trim(); + } + + var tb: bytes = fullStr.toBytes('utf8'); + var em = 'xxx'; + if(em.empty()) { + return; + } + var num = '32.0a'; + var inum = num.parseInt() + 3; + var lnum:long = num.parseLong(); + var fnum:float = num.parseFloat() + 1.0; + var dnum:double = num.parseDouble() + 1.0d; +} + +static async function urlTest(args: [string]): void { + var url = new $URL(args[0]); + var path = url.path(); + var pathname = url.pathname(); + var protocol = url.protocol(); + var hostname = url.hostname(); + var port = url.port(); + var host = url.host(); + var hash = url.hash(); + var search = url.search(); + var href = url.href(); + var auth = url.auth(); + var url2 = $URL.parse(args[1]); + path = url2.path(); + var newUrl = $URL.urlEncode(args[2]); + var newSearch = $URL.percentEncode(search); + var newPath = $URL.pathEncode(pathname); + var all = 'test' + path + protocol + hostname + hash + search + href + auth + newUrl + newSearch + newPath; +} + +static async function xmlTest(args: [string]): void { + var m = { + key1 = 'test1', + key2 = 'test2', + key3 = 3, + key4 = { + key5 = 123, + key6 = '321' + } + }; + var xml = $XML.toXML(m); + xml = xml + "132"; + + var respMap : map[string]any = $XML.parseXml(xml, null); +} + +static function returnAny(): any; + +static async function main(args: [string]):void { + arrayTest(args); + bytesTest(args); + dateTest(args); + envTest(args); + fileTest(args); + formTest(args); + logerTest(args); + mapTestCase(args); + numberTest(args); + streamTest(args); + stringTest(args); + urlTest(args); + xmlTest(args); + + var a: integer = $integer(args[0]) + 10; + var b: string = $string(a) + args[1] + $string(returnAny()); + var c: number = $number(b) + $number(a) + $number(returnAny()); + var d: int8 = $int8(b) + $int8(a) + $int8(returnAny()); + var e: int16 = $int16(b) + $int16(a) + $int16(returnAny()); + var f: int32 = $int32(b) + $int32(a) + $int32(returnAny()); + var g: int64 = $int64(b) + $int64(a) + $int64(returnAny()); + var h: long = $long(b) + $long(a) + $long(returnAny()); + var i: ulong = $ulong(b) + $ulong(a) + $ulong(returnAny()); + var j: uint8 = $uint8(b) + $uint8(a) + $uint8(returnAny()); + var k: uint16 = $uint16(b) + $uint16(a) + $uint16(returnAny()); + var l: uint32 = $uint32(b) + $uint32(a) + $uint32(returnAny()); + var m: uint64 = $uint64(b) + $uint64(a) + $uint64(returnAny()); + var n: float = $float(b) + $float(a) + $float(returnAny()); + var o: double = $double(b) + $double(a) + $double(returnAny()); + if($boolean(args[2])) { + var data = $bytes(returnAny()); + var length: integer = data.length(); + var test: any = $any(data); + var maps: map[string]string = { + key = 'value', + }; + var obj: object = $object(maps); + var ws = $writable(obj); + var rs = $readable(maps); + data = rs.read(30); + if(!$isNull(data)) { + ws.write(data); + } + } + + $sleep(a); + var defaultVal = $string($default(args[0], args[1])); + + if($equal(defaultVal, b)) { + return; + } +} \ No newline at end of file diff --git a/tests/fixtures/comment/libraries/Darafile b/tests/fixtures/comment/libraries/Darafile index 43b9fbb..70ae425 100644 --- a/tests/fixtures/comment/libraries/Darafile +++ b/tests/fixtures/comment/libraries/Darafile @@ -3,6 +3,9 @@ "name": "import", "version": "0.0.1", "main": "./import.dara", + "releases": { + "php": "scope/name:1.0.0" + }, "php": { "package": "import", "clientName": "Client" diff --git a/tests/fixtures/comment/main.dara b/tests/fixtures/comment/main.dara index 61a864e..a6c5008 100644 --- a/tests/fixtures/comment/main.dara +++ b/tests/fixtures/comment/main.dara @@ -21,7 +21,7 @@ model Test1{ model Test2{ // model的test front comment test: string(description='test desc', name='test'), - // model的test front comment + // model的test2 front comment test2: string(description='test2 desc', name='test2'), } @@ -35,14 +35,14 @@ model Test3{ // empty comment1 // empy comment2 - test1: string(description='test desc', name='test1'), //model的test back comment + test1: string(description='test desc', name='test1'), //model的test1 back comment } /** Init Func */ // comment between init and annotation -init(){ +init() { // string declate comment var str = 'sss'; // new model instance comment @@ -95,7 +95,7 @@ api testAPI2(): void { }; // boolean declare comment var bool = true; - if(bool){ + if(bool) { //empty if }else{ //empty else diff --git a/tests/fixtures/complex/libraries/Darafile b/tests/fixtures/complex/libraries/Darafile index 87c7c6f..6989a5f 100644 --- a/tests/fixtures/complex/libraries/Darafile +++ b/tests/fixtures/complex/libraries/Darafile @@ -3,6 +3,9 @@ "name": "import", "version": "0.0.1", "main": "./import.dara", + "releases": { + "php": "scope/name:1.0.0" + }, "php": { "package": "Source", "clientName": "SourceClient", diff --git a/tests/fixtures/complex/main.dara b/tests/fixtures/complex/main.dara index 52eea84..d1c7a8e 100644 --- a/tests/fixtures/complex/main.dara +++ b/tests/fixtures/complex/main.dara @@ -6,7 +6,17 @@ const version = '2019-01-08'; type @configs = [ Source.Config ]; -init(config: Source.Config){ + +exception Err1 = { + data: map[string]string +} + +exception Err2 = { + accessErrMessage: string +} + + +init(config: Source.Config) { super(config); @configs[0] = config; } @@ -105,7 +115,7 @@ api Complex3(request: ComplexRequest): ComplexRequest { __request.body = Source.body(); __request.headers.host = 'hello'; } returns { - var temp_str = `test ${100} ${true}`; + var temp_str = `test ${100} ${true} ${__request.port + 4} ${__request.headers.host}`; var resp = __response; var req = new Source.Request{ accesskey = request.accessKey, @@ -232,4 +242,37 @@ async function tryCatch(): void { } finally { var finalNoCatch = 'ok'; } -} \ No newline at end of file +} + +async function multiTryCatch(a: number): void { + try { + if(a > 0) { + throw new Err1 { + name = "str", + code = "str", + data = { + key1 = "str", + } + }; + } else if(a == 0) { + throw new Err2 { + name = "str", + code = "str", + accessErrMessage = "str2", + }; + } else { + throw new $Error{ + name = "str", + code = "str", + } + } + } catch(err: Err1) { + $Logger.log(err.name); + } catch(err: Err2) { + $Logger.log(err.name); + } catch(err) { + $Logger.log(err.name); + } finally { + var final = 'ok'; + } +} diff --git a/tests/fixtures/function/main.dara b/tests/fixtures/function/main.dara index 1e22a94..b131bd2 100644 --- a/tests/fixtures/function/main.dara +++ b/tests/fixtures/function/main.dara @@ -6,7 +6,7 @@ static function helloMap(): map[string]string { var m: map[string]string = {}; return { key = 'value', - key-1 = 'value-1', + 'key-1' = 'value-1', ...m, }; } diff --git a/tests/fixtures/import/libraries/Darafile b/tests/fixtures/import/libraries/Darafile index 87c7c6f..6989a5f 100644 --- a/tests/fixtures/import/libraries/Darafile +++ b/tests/fixtures/import/libraries/Darafile @@ -3,6 +3,9 @@ "name": "import", "version": "0.0.1", "main": "./import.dara", + "releases": { + "php": "scope/name:1.0.0" + }, "php": { "package": "Source", "clientName": "SourceClient", diff --git a/tests/fixtures/map/libraries/Darafile b/tests/fixtures/map/libraries/Darafile index 87c7c6f..6989a5f 100644 --- a/tests/fixtures/map/libraries/Darafile +++ b/tests/fixtures/map/libraries/Darafile @@ -3,6 +3,9 @@ "name": "import", "version": "0.0.1", "main": "./import.dara", + "releases": { + "php": "scope/name:1.0.0" + }, "php": { "package": "Source", "clientName": "SourceClient", diff --git a/tests/fixtures/map/main.dara b/tests/fixtures/map/main.dara index 40438b1..62c85c3 100644 --- a/tests/fixtures/map/main.dara +++ b/tests/fixtures/map/main.dara @@ -11,12 +11,12 @@ model B = { mm: [A] } -init(config: Source.Config){ +init(config: Source.Config) { super(config); @endpointRule = 'central'; @endpointMap = { - ap-northeast-1 = 'cusanalytic.aliyuncs.com', - ap-south-1 = 'cusanalytic.aliyuncs.com', + 'ap-northeast-1' = 'cusanalytic.aliyuncs.com', + 'ap-south-1' = 'cusanalytic.aliyuncs.com', }; @endpointMap['ap-northeast-1']; @endpointMap['ap-northeast-1'] = ""; diff --git a/tests/fixtures/model/libraries/Darafile b/tests/fixtures/model/libraries/Darafile index 30cb064..caaf15b 100644 --- a/tests/fixtures/model/libraries/Darafile +++ b/tests/fixtures/model/libraries/Darafile @@ -9,7 +9,11 @@ "csharp": { "namespace": "Darabonba.import" }, + "php": { + "package": "Darabonba.Import", + "clientName": "Client" + }, "releases": { - "ts": "@scope/name:*" + "php": "scope/name:1.0.0" } } \ No newline at end of file diff --git a/tests/fixtures/model/main.dara b/tests/fixtures/model/main.dara index 3c9a3db..622fdbd 100644 --- a/tests/fixtures/model/main.dara +++ b/tests/fixtures/model/main.dara @@ -10,6 +10,17 @@ model model = { str: string } +exception MainFileError extends $Error { + size: number, + data: map[string]model, + model: { + str: string, + model: { + str: string + }, + } +} + model MyModel = { model: { str: string, @@ -32,7 +43,11 @@ model MyModel = { mapModel: map[string]M, subarraymodel: [ {} ], subarray: [ M ], + ssubarray: [[ M ]], + ssubmarray: [[ Source ]], + ssubmmarray: [[ Source.Request ]], maparray: [ map[string]any ], + mapsubmarray: [ map[string]Source ], moduleModelMap: map[string]Source.Request, subModelMap: map[string]M.subM, modelMap: map[string]M, diff --git a/tests/fixtures/multi/.libraries.json b/tests/fixtures/multi/.libraries.json new file mode 100644 index 0000000..a1e0097 --- /dev/null +++ b/tests/fixtures/multi/.libraries.json @@ -0,0 +1,3 @@ +{ + "darabonba:Util:*": "libraries/darabonba_Util_0.2.11" +} \ No newline at end of file diff --git a/tests/fixtures/multi/Darafile b/tests/fixtures/multi/Darafile new file mode 100644 index 0000000..8dcfeb4 --- /dev/null +++ b/tests/fixtures/multi/Darafile @@ -0,0 +1,9 @@ +{ + "scope": "darabonba", + "name": "Util", + "version": "0.2.10", + "main": "./sdk.dara", + "libraries": { + "DARAUtil": "darabonba:Util:*" + } +} \ No newline at end of file diff --git a/tests/fixtures/multi/api.dara b/tests/fixtures/multi/api.dara new file mode 100644 index 0000000..fcde1b7 --- /dev/null +++ b/tests/fixtures/multi/api.dara @@ -0,0 +1,21 @@ +import "./model/user" User; +import "./lib/util" Util; + +init() { +} + +api test3(): number { + __request.protocol = "https"; + __request.method = 'DELETE'; + __request.pathname = "/"; + __request.headers = { + host = "test.aliyun.com", + accept = 'application/json', + test = User.test1(), + }; + __request.query = Util.getQuery(); +} returns { + return __response.statusCode; +} runtime { + timeouted = 'retry' +} diff --git a/tests/fixtures/multi/lib/util.dara b/tests/fixtures/multi/lib/util.dara new file mode 100644 index 0000000..1814ba5 --- /dev/null +++ b/tests/fixtures/multi/lib/util.dara @@ -0,0 +1,3 @@ +static function test1(): iterator[string]; + +static function getQuery(): map[string]string; \ No newline at end of file diff --git a/tests/fixtures/multi/libraries/darabonba_Util_0.2.11/Teafile b/tests/fixtures/multi/libraries/darabonba_Util_0.2.11/Teafile new file mode 100644 index 0000000..3c1b802 --- /dev/null +++ b/tests/fixtures/multi/libraries/darabonba_Util_0.2.11/Teafile @@ -0,0 +1,62 @@ +{ + "scope": "darabonba", + "name": "Util", + "version": "0.2.11", + "main": "./main.tea", + "releases": { + "go": "github.com/alibabacloud-go/tea-utils/v2/service:v2.0.4", + "ts": "@alicloud/tea-util:^1.4.7", + "csharp": "AlibabaCloud.TeaUtil:0.1.17", + "java": "com.aliyun:tea-util:0.2.21", + "php": "alibabacloud/tea-utils:^0.2.19", + "python": "alibabacloud_tea_util:0.3.11", + "python2": "alibabacloud_tea_util_py2:0.0.9", + "swift": "alibabacloud-sdk-swift/tea-utils:1.0.3", + "cpp": "alibabacloud-sdk-cpp/dara-util:master" + }, + "java": { + "package": "com.aliyun.teautil", + "className": "Common" + }, + "csharp": { + "namespace": "AlibabaCloud.TeaUtil", + "className": "Common" + }, + "php": { + "package": "AlibabaCloud.Tea.Utils", + "clientName": "Utils", + "modelDirName": "Utils" + }, + "python": { + "package": "alibabacloud_tea_util", + "clientName": "client" + }, + "python2": { + "package": "alibabacloud_tea_util", + "clientName": "client" + }, + "cpp": { + "packageInfo": { + "git": { + "scope": "alibabacloud-sdk-cpp", + "project": "dara-util" + } + } + }, + "swift": { + "clientName": "Client", + "packageInfo": { + "name": "TeaUtils", + "desc": "Alibaba Cloud Tea Util for Swift", + "github": "https://github.com/alibabacloud-sdk-swift/tea-utils", + "author": "Alibaba Cloud SDK", + "email": "sdk-team@alibabacloud.com" + } + }, + "releaselog": { + "changelog": [ + "[java]fix: enable getNonce() on Android platform." + ], + "compatible": true + } +} \ No newline at end of file diff --git a/tests/fixtures/multi/libraries/darabonba_Util_0.2.11/main.tea b/tests/fixtures/multi/libraries/darabonba_Util_0.2.11/main.tea new file mode 100644 index 0000000..a08b6cf --- /dev/null +++ b/tests/fixtures/multi/libraries/darabonba_Util_0.2.11/main.tea @@ -0,0 +1,244 @@ +/** + * This is a utility module + */ + +/** + * The common runtime options model + */ +model RuntimeOptions { + autoretry?: boolean(description='whether to try again', name='autoretry'), + ignoreSSL?: boolean(description='ignore SSL validation', name='ignoreSSL'), + key?: string(description='privite key for client certificate', name='key'), + cert?: string(description='client certificate', name='cert'), + ca?: string(description='server certificate', name='ca'), + maxAttempts?: number(description='maximum number of retries', name='max_attempts'), + backoffPolicy?: string(description='backoff policy', name='backoff_policy'), + backoffPeriod?: number(description='backoff period', name='backoff_period'), + readTimeout?: number(description='read timeout', name='readTimeout'), + connectTimeout?: number(description='connect timeout', name='connectTimeout'), + httpProxy?: string(description='http proxy url', name='httpProxy'), + httpsProxy?: string(description='https Proxy url', name='httpsProxy'), + noProxy?: string(description='agent blacklist', name='noProxy'), + maxIdleConns?: number(description='maximum number of connections', name='maxIdleConns'), + localAddr?: string(description='local addr', name='localAddr'), + socks5Proxy?: string(description='SOCKS5 proxy', name='socks5Proxy'), + socks5NetWork?: string(description='SOCKS5 netWork', name='socks5NetWork'), + keepAlive?: boolean(description='whether to enable keep-alive', name='keepAlive'), +} + +/** + * Convert a string(utf8) to bytes + * @return the return bytes + */ +static function toBytes(val: string): bytes; + +/** + * Convert a bytes to string(utf8) + * @return the return string + */ +static function toString(val: bytes): string; + +/** + * Parse it by JSON format + * @return the parsed result + */ +static function parseJSON(val: string): any; + +/** + * Read data from a readable stream, and compose it to a bytes + * @param stream the readable stream + * @return the bytes result + */ +static async function readAsBytes(stream: readable): bytes; + +/** + * Read data from a readable stream, and compose it to a string + * @param stream the readable stream + * @return the string result + */ +static async function readAsString(stream: readable): string { + var buff = readAsBytes(stream); + return toString(buff); +} + +/** + * Read data from a readable stream, and parse it by JSON format + * @param stream the readable stream + * @return the parsed result + */ +static async function readAsJSON(stream: readable): any { + return parseJSON(readAsString(stream)); +} + +/** + * Generate a nonce string + * @return the nonce string + */ +static function getNonce(): string; + +/** + * Get an UTC format string by current date, e.g. 'Thu, 06 Feb 2020 07:32:54 GMT' + * @return the UTC format string + */ +static function getDateUTCString(): string; + +/** + * If not set the real, use default value + * @return the return string + */ +static function defaultString(real: string, default: string): string; + +/** + * If not set the real, use default value + * @return the return number + */ +static function defaultNumber(real: number, default: number): number; + +/** + * Format a map to form string, like a=a%20b%20c + * @return the form string + */ +static function toFormString(val: object): string; + +/** + * Stringify a value by JSON format + * @return the JSON format string + */ +static function toJSONString(val: any): string; + +/** + * Check the string is empty? + * @return if string is null or zero length, return true + */ +static function empty(val: string): boolean; + +/** + * Check one string equals another one? + * @return if equals, return true + */ +static function equalString(val1: string, val2: string): boolean; + +/** + * Check one number equals another one? + * @return if equals, return true + */ +static function equalNumber(val1: number, val2: number): boolean; + +/** + * Check one value is unset + * @return if unset, return true + */ +static function isUnset(value: any): boolean; + +/** + * Stringify the value of map + * @return the new stringified map + */ +static function stringifyMapValue(m: map[string]any): map[string]string; + +/** + * Anyify the value of map + * @return the new anyfied map + */ +static function anyifyMapValue(m: map[string]string): map[string]any; + +/** + * Assert a value, if it is a boolean, return it, otherwise throws + * @return the boolean value + */ +static function assertAsBoolean(value: any)throws : boolean; + +/** + * Assert a value, if it is a string, return it, otherwise throws + * @return the string value + */ +static function assertAsString(value: any)throws : string; + +/** + * Assert a value, if it is a bytes, return it, otherwise throws + * @return the bytes value + */ +static function assertAsBytes(value: any)throws : bytes; + +/** + * Assert a value, if it is a number, return it, otherwise throws + * @return the number value + */ +static function assertAsNumber(value: any)throws : number; + +/** + * Assert a value, if it is a integer, return it, otherwise throws + * @return the integer value + */ +static function assertAsInteger(value: any)throws : integer; + +/** + * Assert a value, if it is a map, return it, otherwise throws + * @return the map value + */ +static function assertAsMap(value: any)throws : map[string]any; + +/** + * Assert a value, if it is a array, return it, otherwise throws + * @return the array value + */ +static function assertAsArray(value: any)throws : [ any ]; + +/** + * Get user agent, if it userAgent is not null, splice it with defaultUserAgent and return, otherwise return defaultUserAgent + * @return the string value + */ +static function getUserAgent(userAgent: string): string; + +/** + * If the code between 200 and 300, return true, or return false + * @return boolean + */ +static function is2xx(code: number): boolean; + +/** + * If the code between 300 and 400, return true, or return false + * @return boolean + */ +static function is3xx(code: number): boolean; + +/** + * If the code between 400 and 500, return true, or return false + * @return boolean + */ +static function is4xx(code: number): boolean; + +/** + * If the code between 500 and 600, return true, or return false + * @return boolean + */ +static function is5xx(code: number): boolean; + +/** + * Validate model + * @return void + */ +static function validateModel(m: $Model) throws: void; + +/** + * Model transforms to map[string]any + * @return map[string]any + */ +static function toMap(in: $Model): map[string]any; + + +/** + * Suspends the current thread for the specified number of milliseconds. + */ +static async function sleep(millisecond: number): void; + +/** + * Transform input as array. + */ +static function toArray(input: any): [ map[string]any ]; + +/** + * Assert a value, if it is a readable, return it, otherwise throws + * @return the readable value + */ +static function assertAsReadable(value: any)throws : readable; \ No newline at end of file diff --git a/tests/fixtures/multi/model/user.dara b/tests/fixtures/multi/model/user.dara new file mode 100644 index 0000000..32bd5e2 --- /dev/null +++ b/tests/fixtures/multi/model/user.dara @@ -0,0 +1,24 @@ +@clientName("UserModel"); +import DARAUtil; +import "../lib/util" Util; + +model Info { + name: string, + age: integer, + runtime: DARAUtil.RuntimeOptions, +} + + +static async function test(): asyncIterator[string]{ + var a = DARAUtil.getNonce(); + yield a; + var it:iterator[string] = Util.test1(); + for(var test : it) { + yield test; + } + +} + +static function test1(): string { + return 'test1'; +} \ No newline at end of file diff --git a/tests/fixtures/multi/sdk.dara b/tests/fixtures/multi/sdk.dara new file mode 100644 index 0000000..ad3720e --- /dev/null +++ b/tests/fixtures/multi/sdk.dara @@ -0,0 +1,25 @@ +import "./model/user" User; +import "./lib/util" Util; +import "./api" API; + +type @user = User.Info + +init() { + @user = new User.Info{ + name = 'test' + }; +} + +async function test3(): asyncIterator[string]{ + var it:iterator[string] = Util.test1(); + for(var test : it) { + yield test; + } +} + + +async function test4(): number{ +var api = new API(); + var status = api.test3(); +return status; +} \ No newline at end of file diff --git a/tests/fixtures/number/libraries/darabonba_Number_0.0.0/Darafile b/tests/fixtures/number/libraries/darabonba_Number_0.0.0/Darafile index 21d9bd1..0648cb5 100644 --- a/tests/fixtures/number/libraries/darabonba_Number_0.0.0/Darafile +++ b/tests/fixtures/number/libraries/darabonba_Number_0.0.0/Darafile @@ -2,5 +2,13 @@ "scope": "darabonba", "name": "Number", "version": "0.0.0", - "main": "./main.tea" + "main": "./main.tea", + "releases": { + "php": "scope/name:1.0.0" + }, + "php": { + "package": "Number.math", + "clientName": "MathUtil", + "modelDirName": "Models" + } } \ No newline at end of file diff --git a/tests/fixtures/number/main.dara b/tests/fixtures/number/main.dara index 709ea69..81656f4 100644 --- a/tests/fixtures/number/main.dara +++ b/tests/fixtures/number/main.dara @@ -3,16 +3,6 @@ import Number; static async function main(args: [string]): void { var a = "123"; var b = Number.parseInt(a); - var c = Number.parseFloat(a); - var d = Number.parseDouble(a); - var e = Number.itol(b); - var f = Number.parseLong(a); - var g = Number.add(e,f); - g = Number.sub(e,f); - g = Number.mul(e,f); - var z = Number.div(e,f); - var h = Number.gt(e,f); - h = Number.gte(e,f); - h = Number.lt(e,f); - h = Number.lte(e,f); + var c = b.parseFloat(); + var d = $Number.random(); } diff --git a/tests/fixtures/super/libraries/Darafile b/tests/fixtures/super/libraries/Darafile index 87c7c6f..5c5a20e 100644 --- a/tests/fixtures/super/libraries/Darafile +++ b/tests/fixtures/super/libraries/Darafile @@ -3,6 +3,9 @@ "name": "import", "version": "0.0.1", "main": "./import.dara", + "releases": { + "php": "scope/name:1.0.0" + }, "php": { "package": "Source", "clientName": "SourceClient", diff --git a/tests/fixtures/super/main.dara b/tests/fixtures/super/main.dara index 0385cd1..e29978f 100644 --- a/tests/fixtures/super/main.dara +++ b/tests/fixtures/super/main.dara @@ -2,6 +2,6 @@ import Source; extends Source; -init(config: Source.Config){ +init(config: Source.Config) { super(config); } \ No newline at end of file diff --git a/tests/fixtures/typedef/.libraries.json b/tests/fixtures/typedef/.libraries.json index c3fe47f..5a541f2 100644 --- a/tests/fixtures/typedef/.libraries.json +++ b/tests/fixtures/typedef/.libraries.json @@ -1,3 +1,3 @@ { - "alibabacloud:OSS:*": "libraries/alibabacloud-OSS-0.0.1" + "alibabacloud:OSS:*": "libraries/" } \ No newline at end of file diff --git a/tests/fixtures/typedef/Darafile b/tests/fixtures/typedef/Darafile index 5bde294..b0a3f28 100644 --- a/tests/fixtures/typedef/Darafile +++ b/tests/fixtures/typedef/Darafile @@ -25,7 +25,7 @@ "package": null }, "TeaModel": { - "import": "AlibabaCloud\\Tea", + "import": "AlibabaCloud\\Dara", "type": "Model", "package": "alibabacloud/tea:^3.1.23" }, diff --git a/tests/fixtures/typedef/libraries/alibabacloud-OSS-0.0.1/Darafile b/tests/fixtures/typedef/libraries/Darafile similarity index 88% rename from tests/fixtures/typedef/libraries/alibabacloud-OSS-0.0.1/Darafile rename to tests/fixtures/typedef/libraries/Darafile index 8a485d9..8025357 100644 --- a/tests/fixtures/typedef/libraries/alibabacloud-OSS-0.0.1/Darafile +++ b/tests/fixtures/typedef/libraries/Darafile @@ -1,6 +1,9 @@ { "name": "OSS", "main": "./oss.dara", + "releases": { + "php": "scope/name:1.0.0" + }, "libraries": {}, "php": { "package": "Source", diff --git a/tests/fixtures/typedef/libraries/alibabacloud-OSS-0.0.1/oss.dara b/tests/fixtures/typedef/libraries/oss.dara similarity index 69% rename from tests/fixtures/typedef/libraries/alibabacloud-OSS-0.0.1/oss.dara rename to tests/fixtures/typedef/libraries/oss.dara index 3c19949..dc848ae 100644 --- a/tests/fixtures/typedef/libraries/alibabacloud-OSS-0.0.1/oss.dara +++ b/tests/fixtures/typedef/libraries/oss.dara @@ -1,6 +1,6 @@ typedef HttpRequest type @vid=HttpRequest -init(test: HttpRequest){ +init(test: HttpRequest) { @vid = test; } \ No newline at end of file diff --git a/tests/fixtures/typedef/main.dara b/tests/fixtures/typedef/main.dara index 0ee0a19..58a2d66 100644 --- a/tests/fixtures/typedef/main.dara +++ b/tests/fixtures/typedef/main.dara @@ -9,14 +9,15 @@ typedef Guzzle; type @vid=OSS.HttpRequest; type @model=TeaModel; -init(request: OSS.HttpRequest, model: TeaModel){ +init(request: OSS.HttpRequest, model: TeaModel) { @vid = request; @model = model; } model M { a?: OSS.HttpRequest, - b?: HttpHeader + b?: HttpHeader, + c?: TeaModel } async function main(test1: OSS.HttpRequest, test2: HttpHeader, test3: TeaModel) : void { @@ -35,4 +36,4 @@ async function testHttpRequest(req: OSS.HttpRequest): HttpResponse { static function testHttpRequestWith(method: string, req: OSS.HttpRequest): HttpResponse -static function testHttpHeader(method: string, headers: HttpHeader): HttpResponse +static function testHttpHeader(method: string, headers: HttpHeader): HttpResponse \ No newline at end of file diff --git a/tests/lib.tests.js b/tests/lib.tests.js deleted file mode 100644 index 38381aa..0000000 --- a/tests/lib.tests.js +++ /dev/null @@ -1,256 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const path = require('path'); -const debug = require('../src/lib/debug'); -const mm = require('mm'); -const expect = require('chai').expect; -const Emitter = require('../src/lib/emitter'); -const os = require('os'); - -require('mocha-sinon'); - -const { - _camelCase, - _subModelName, - _string, - _upperFirst, - _config, - _avoidKeywords, - _modify, - _symbol, - _toSnakeCase, - _dir -} = require('../src/lib/helper'); - -describe('debug should be ok', function () { - beforeEach(function () { - this.sinon.stub(console, 'log'); - this.sinon.stub(process, 'exit'); - this.sinon.stub(fs, 'mkdirSync'); - this.sinon.stub(fs, 'writeFileSync'); - this.sinon.stub(fs, 'appendFileSync'); - this.sinon.stub(fs, 'existsSync'); - }); - - it('dump should be ok', function () { - debug.dump(null, 1, '1', 1.11111); - expect(console.log.calledWith('foo')).to.be.false; - expect(console.log.calledWith(null)).to.be.true; - expect(console.log.calledWith(1)).to.be.true; - expect(console.log.calledWith('1')).to.be.true; - expect(console.log.calledWith(1.11111)).to.be.true; - expect(process.exit.calledWith(-1)).to.be.false; - }); - - it('halt should be ok', function () { - debug.halt(null, 1, '1', 1.11111); - expect(console.log.calledWith('foo')).to.be.false; - expect(console.log.calledWith(null)).to.be.true; - expect(console.log.calledWith(1)).to.be.true; - expect(console.log.calledWith('1')).to.be.true; - expect(console.log.calledWith(1.11111)).to.be.true; - expect(process.exit.calledWith(-1)).to.be.true; - }); - - it('jump should be ok', function () { - for (let i = 0; i < 3; i++) { - debug.jump(1, `jump output : ${i}`); - } - expect(console.log.calledWith('jump output : 0')).to.be.false; - expect(console.log.calledWith('jump output : 1')).to.be.true; - expect(console.log.calledWith('jump output : 2')).to.be.false; - expect(process.exit.calledWith(-1)).to.be.true; - }); - - it('warning should be ok', function () { - debug.warning('this is warning message'); - expect(console.log.calledWith(`\x1b[33m${os.EOL}[WARNING] this is warning message\x1b[0m${os.EOL}`)).to.be.false; - expect(process.exit.calledWith(-1)).to.be.false; - }); - - it('stack should be ok', function () { - try { - debug.stack('called debug stack with message', 'data1', 'data2'); - } catch (e) { - expect(e.message).to.be.eql('called debug stack with message'); - expect(console.log.calledWith('called debug stack with message')).to.be.false; - expect(console.log.calledWith('data1')).to.be.true; - expect(console.log.calledWith('data2')).to.be.true; - expect(process.exit.calledWith(-1)).to.be.false; - } - - try { - debug.stack(1, 'called debug stack without message', 'some data'); - } catch (e) { - expect(e.message).to.be.eql(''); - expect(console.log.calledWith(1)).to.be.true; - expect(console.log.calledWith('called debug stack without message')).to.be.true; - expect(console.log.calledWith('some data')).to.be.true; - expect(process.exit.calledWith(-1)).to.be.false; - } - }); -}); - -describe('emitter should be ok', function () { - beforeEach(function () { - this.sinon.stub(console, 'log'); - this.sinon.stub(process, 'exit'); - this.sinon.stub(fs, 'mkdirSync'); - this.sinon.stub(fs, 'writeFileSync'); - this.sinon.stub(fs, 'appendFileSync'); - this.sinon.stub(fs, 'existsSync'); - }); - - it('indent should be ok', function () { - const emitter = new Emitter(); - expect(emitter.indent(1)).to.be.eql(' '); - }); - - it('emit should be ok', function () { - const emitter = new Emitter(); - emitter.emit('emit some string'); - expect(emitter.output).to.be.eql('emit some string'); - }); - - it('emitln should be ok', function () { - const emitter = new Emitter(); - emitter.emitln('emitln some string'); - expect(emitter.output).to.be.eql('emitln some string' + emitter.eol); - }); - - it('emits should be ok', function () { - const emitter = new Emitter(); - emitter.emits(1); - expect(emitter.output).to.be.eql(''); - emitter.emits(0, 'row1', 'row2'); - expect(emitter.output).to.be.eql('row1' + emitter.eol + 'row2' + emitter.eol); - }); - - it('currRow should be ok', function () { - const emitter = new Emitter(); - emitter.emit('row one'); - expect(emitter.currRow()).to.be.eql('row one'); - emitter.emitln(); - expect(emitter.currRow()).to.be.eql('row one'); - emitter.emit('row two'); - expect(emitter.currRow()).to.be.eql('row two'); - }); - - it('savePath should be ok', function () { - const emitter = new Emitter({ - dir: '/tmp/', - layer: 'a.b.c', - filename: 'filename', - ext: '.tmp' - }); - expect(emitter.savePath()).to.be.eql('/tmp/a/b/c/filename.tmp'); - }); - - it('save should be ok', function () { - const emitter = new Emitter(); - try { - emitter.save(); - } catch (e) { - expect(e.message).to.be.eql('`option.dir` should not be empty'); - } - emitter.config.dir = '/tmp/'; - try { - emitter.save(); - } catch (e) { - expect(e.message).to.be.eql('filename cannot be empty'); - } - emitter.config.filename = 'filename'; - emitter.config.ext = '.tmp'; - - emitter.emit('test'); - - emitter.save(); - emitter.emit(); - mm(fs, 'existsSync', function (filename) { - return true; - }); - emitter.save(true); - mm.restore(); - - // show emit info - emitter.config.showInfo = true; - emitter.emit('test'); - emitter.save(); - const filename = emitter.savePath(); - - expect(filename).to.be.eql('/tmp/filename.tmp'); - }); -}); - -describe('helper tests', function () { - it('_upperFirst should be ok', function () { - expect(_upperFirst(null)).to.be.eql(''); - }); - - it('_camelCase should be ok', function () { - expect(_camelCase('test_camel_case')).to.be.eql('testCamelCase'); - }); - - it('_subModelName should be ok', function () { - expect(_subModelName('test.model.name')).to.be.eql('TestModelName'); - }); - - it('_string should be ok', function () { - const obj = { - string: 'test' - }; - expect(_string(obj)).to.be.eql('test'); - }); - - it('_avoidKeywords should be ok', function () { - _config({ keywords: ['key'] }); - expect(_avoidKeywords('key')).to.be.eql('key_'); - }); - - it('_modify should be ok', function () { - _config({ - modifyOrder: [ - 'PRIVATE', - 'PROTECTED', - 'PUBLIC', - 'FINAL', - 'ABSTRACT', - 'STATIC' - ] - }); - expect(_modify('PRIVATE')).to.be.eql('private'); - }); - - it('_symbol should be ok', function () { - _config({ symbolMap: { 'ASSIGN': '=' } }); - expect(function () { - _symbol('InvalidSymbol'); - }).to.be.throw('Unsupported symbol : InvalidSymbol'); - - expect(_symbol('ASSIGN')).to.be.eql('='); - }); - - it('_toSnakeCase should be ok', function () { - expect(_toSnakeCase('TestABC')).to.be.eql('test_abc'); - expect(_toSnakeCase(null)).to.be.eql(''); - expect(_toSnakeCase('SLS')).to.be.eql('sls'); - expect(_toSnakeCase('_runtime')).to.be.eql('_runtime'); - expect(_toSnakeCase('TT123')).to.be.eql('tt123'); - expect(_toSnakeCase('fooBar')).to.be.eql('foo_bar'); - }); - - it('_dir should be ok', function () { - mm(fs, 'existsSync', function (filename) { - return false; - }); - mm(path, 'dirname', function (filename) { - return ''; - }); - mm(fs, 'mkdirSync', function (filename, option = {}) { - return true; - }); - _dir('some/path'); - mm.restore(); - }); -}); diff --git a/tests/main.test.js b/tests/main.test.js new file mode 100644 index 0000000..ee28796 --- /dev/null +++ b/tests/main.test.js @@ -0,0 +1,255 @@ +'use strict'; + +const path = require('path'); +const fs = require('fs'); +const assert = require('assert'); + +const DSL = require('@darabonba/parser'); + +let Generator = require('../lib/generator'); + +function compareDirectories(expectedDir, outputDir) { + const expectedFiles = fs.readdirSync(expectedDir); + const outputFiles = fs.readdirSync(outputDir); + for (let fileName of expectedFiles) { + if (!outputFiles.includes(fileName)) { + assert.ok(false); + } + const expectedPath = path.join(outputDir, fileName); + const actualPath = path.join(expectedDir, fileName); + const expectedStat = fs.statSync(expectedPath); + const actualStat = fs.statSync(actualPath); + + // 如果两个文件都是文件夹,则递归进行比较 + if (expectedStat.isDirectory() && actualStat.isDirectory()) { + compareDirectories(expectedPath, actualPath); + } + // 如果是文件,则比较文件内容 + else if (expectedStat.isFile() && actualStat.isFile()) { + const expectedContent = fs.readFileSync(expectedPath, 'utf8'); + const acutalContent = fs.readFileSync(actualPath, 'utf8'); + + assert.deepStrictEqual(expectedContent, acutalContent); + } + } +} + +function check(mainFilePath, outputDir, expectedPath, pkgInfo = {}) { + const php = pkgInfo.php || { + package: 'Dara.PHP.Tests', + clientName: 'Client', + modelDirName: 'Models' + }; + const generator = new Generator({ + outputDir, + ...php, + ...pkgInfo + }); + + const dsl = fs.readFileSync(mainFilePath, 'utf8'); + const ast = DSL.parse(dsl, mainFilePath); + generator.visit(ast); + if(!pkgInfo.allCheck) { + outputDir = path.join(outputDir , 'src'); + } + compareDirectories(expectedPath, outputDir); +} + +describe('new Generator', function() { + it('must pass in outputDir', function () { + assert.throws(function () { + new Generator({}); + }, function(err) { + assert.deepStrictEqual(err.message, '`option.outputDir` should not empty'); + return true; + }); + }); + + it('empty module should ok', function () { + const outputDir = path.join(__dirname, 'output/empty'); + const mainFilePath = path.join(__dirname, 'fixtures/empty/main.dara'); + check(mainFilePath, outputDir, path.join(__dirname, 'expected/empty')); + }); + + it('one model should ok', function () { + const outputDir = path.join(__dirname, 'output/model'); + const mainFilePath = path.join(__dirname, 'fixtures/model/main.dara'); + const pkgContent = fs.readFileSync(path.join(__dirname, 'fixtures/model/Darafile'), 'utf8'); + const pkg = JSON.parse(pkgContent); + check(mainFilePath, outputDir, path.join(__dirname, 'expected/model'), { + pkgDir: path.join(__dirname, 'fixtures/model'), + ...pkg + }); + }); + + it('one api should ok', function () { + const outputDir = path.join(__dirname, 'output/api'); + const mainFilePath = path.join(__dirname, 'fixtures/api/main.dara'); + check(mainFilePath, outputDir, path.join(__dirname, 'expected/api')); + }); + + it('one function should ok', function () { + const outputDir = path.join(__dirname, 'output/function'); + const mainFilePath = path.join(__dirname, 'fixtures/function/main.dara'); + check(mainFilePath, outputDir, path.join(__dirname, 'expected/function')); + }); + + it('const should ok', function () { + const outputDir = path.join(__dirname, 'output/const'); + const mainFilePath = path.join(__dirname, 'fixtures/const/main.dara'); + check(mainFilePath, outputDir, path.join(__dirname, 'expected/const')); + }); + + it('statements should ok', function () { + const outputDir = path.join(__dirname, 'output/statements'); + const mainFilePath = path.join(__dirname, 'fixtures/statements/main.dara'); + check(mainFilePath, outputDir, path.join(__dirname, 'expected/statements')); + }); + + it('import should ok', function () { + const outputDir = path.join(__dirname, 'output/import'); + const mainFilePath = path.join(__dirname, 'fixtures/import/main.dara'); + const pkgContent = fs.readFileSync(path.join(__dirname, 'fixtures/import/Darafile'), 'utf8'); + const pkg = JSON.parse(pkgContent); + check(mainFilePath, outputDir, path.join(__dirname, 'expected/import'), { + pkgDir: path.join(__dirname, 'fixtures/import'), + ...pkg + }); + }); + + it('complex should ok', function () { + const outputDir = path.join(__dirname, 'output/complex'); + const mainFilePath = path.join(__dirname, 'fixtures/complex/main.dara'); + const pkgContent = fs.readFileSync(path.join(__dirname, 'fixtures/complex/Darafile'), 'utf8'); + const pkg = JSON.parse(pkgContent); + check(mainFilePath, outputDir, path.join(__dirname, 'expected/complex'), { + pkgDir: path.join(__dirname, 'fixtures/complex'), + ...pkg + }); + }); + + it('add annotation should ok', function () { + const outputDir = path.join(__dirname, 'output/annotation'); + const mainFilePath = path.join(__dirname, 'fixtures/annotation/main.dara'); + check(mainFilePath, outputDir, path.join(__dirname, 'expected/annotation'), {editable: true}); + }); + + it('add comments should ok', function () { + const outputDir = path.join(__dirname, 'output/comment'); + const mainFilePath = path.join(__dirname, 'fixtures/comment/main.dara'); + const pkgContent = fs.readFileSync(path.join(__dirname, 'fixtures/comment/Darafile'), 'utf8'); + const pkg = JSON.parse(pkgContent); + check(mainFilePath, outputDir, path.join(__dirname, 'expected/comment'), { + pkgDir: path.join(__dirname, 'fixtures/comment'), + ...pkg, + editable: 'true' + }); + }); + + it('add builtin should ok', function () { + const outputDir = path.join(__dirname, 'output/builtin'); + const mainFilePath = path.join(__dirname, 'fixtures/builtin/main.dara'); + check(mainFilePath, outputDir, path.join(__dirname, 'expected/builtin'), {editable: 1}); + }); + + it('multi dara should ok', function () { + const outputDir = path.join(__dirname, 'output/multi'); + const mainFilePath = path.join(__dirname, 'fixtures/multi/sdk.dara'); + const pkgContent = fs.readFileSync(path.join(__dirname, 'fixtures/multi/Darafile'), 'utf8'); + const pkg = JSON.parse(pkgContent); + check(mainFilePath, outputDir, path.join(__dirname, 'expected/multi'), { + pkgDir: path.join(__dirname, 'fixtures/multi'), + ...pkg, + editable: 'true' + }); + }); + + it('alias should ok', function () { + const outputDir = path.join(__dirname, 'output/alias'); + const mainFilePath = path.join(__dirname, 'fixtures/alias/main.dara'); + const pkgContent = fs.readFileSync(path.join(__dirname, 'fixtures/alias/Darafile'), 'utf8'); + const pkg = JSON.parse(pkgContent); + check(mainFilePath, outputDir, path.join(__dirname, 'expected/alias'), { + pkgDir: path.join(__dirname, 'fixtures/alias'), + ...pkg, + editable: 'true' + }); + }); + + it('exec should ok', function () { + const outputDir = path.join(__dirname, 'output/exec'); + const mainFilePath = path.join(__dirname, 'fixtures/exec/main.dara'); + const pkgContent = fs.readFileSync(path.join(__dirname, 'fixtures/exec/Darafile'), 'utf8'); + const pkg = JSON.parse(pkgContent); + check(mainFilePath, outputDir, path.join(__dirname, 'expected/exec'), { + pkgDir: path.join(__dirname, 'fixtures/exec'), + ...pkg, + exec: true, + editable: 'true' + }); + }); + + it('map should ok', function () { + const outputDir = path.join(__dirname, 'output/map'); + const mainFilePath = path.join(__dirname, 'fixtures/map/main.dara'); + const pkgContent = fs.readFileSync(path.join(__dirname, 'fixtures/map/Darafile'), 'utf8'); + const pkg = JSON.parse(pkgContent); + check(mainFilePath, outputDir, path.join(__dirname, 'expected/map'), { + pkgDir: path.join(__dirname, 'fixtures/map'), + ...pkg, + editable: 'true' + }); + }); + + it('number should ok', function () { + const outputDir = path.join(__dirname, 'output/number'); + const mainFilePath = path.join(__dirname, 'fixtures/number/main.dara'); + const pkgContent = fs.readFileSync(path.join(__dirname, 'fixtures/number/Darafile'), 'utf8'); + const pkg = JSON.parse(pkgContent); + check(mainFilePath, outputDir, path.join(__dirname, 'expected/number'), { + pkgDir: path.join(__dirname, 'fixtures/number'), + ...pkg, + editable: 'true' + }); + }); + + it('super should ok', function () { + const outputDir = path.join(__dirname, 'output/super'); + const mainFilePath = path.join(__dirname, 'fixtures/super/main.dara'); + const pkgContent = fs.readFileSync(path.join(__dirname, 'fixtures/super/Darafile'), 'utf8'); + const pkg = JSON.parse(pkgContent); + check(mainFilePath, outputDir, path.join(__dirname, 'expected/super'), { + pkgDir: path.join(__dirname, 'fixtures/super'), + ...pkg, + editable: 'true' + }); + }); + + + it('package should ok', function () { + const outputDir = path.join(__dirname, 'output/package'); + const mainFilePath = path.join(__dirname, 'fixtures/package/main.dara'); + const pkgContent = fs.readFileSync(path.join(__dirname, 'fixtures/package/Darafile'), 'utf8'); + const pkg = JSON.parse(pkgContent); + check(mainFilePath, outputDir, path.join(__dirname, 'expected/package'), { + pkgDir: path.join(__dirname, 'fixtures/package'), + ...pkg, + editable: 'true', + allCheck: true, + }); + }); + + + it('typedef should ok', function () { + const outputDir = path.join(__dirname, 'output/typedef'); + const mainFilePath = path.join(__dirname, 'fixtures/typedef/main.dara'); + const pkgContent = fs.readFileSync(path.join(__dirname, 'fixtures/typedef/Darafile'), 'utf8'); + const pkg = JSON.parse(pkgContent); + check(mainFilePath, outputDir, path.join(__dirname, 'expected/typedef'), { + pkgDir: path.join(__dirname, 'fixtures/typedef'), + ...pkg, + editable: false, + allCheck: true, + }); + }); +}); diff --git a/tests/php.tests.js b/tests/php.tests.js deleted file mode 100644 index a53dca7..0000000 --- a/tests/php.tests.js +++ /dev/null @@ -1,170 +0,0 @@ -'use strict'; - -const path = require('path'); -const fs = require('fs'); -const assert = require('assert'); -require('mocha-sinon'); - -const DSL = require('@darabonba/parser'); - -const Generator = require('../src/generator'); - -const lang = 'php'; - -const expectedDir = path.join(__dirname, 'expected/'); -const fixturesDir = path.join(__dirname, 'fixtures/'); -const outputDir = path.join(__dirname, '../', 'output/tests/'); - -function check(moduleName, expectedFiles = []) { - const mainFilePath = path.join(fixturesDir, moduleName, 'main.dara'); - const moduleOutputDir = path.join(outputDir, moduleName); - const prefixDir = path.join(fixturesDir, moduleName); - const pkgContent = fs.readFileSync( - fs.existsSync(path.join(prefixDir, 'Darafile')) ? path.join(prefixDir, 'Darafile') : path.join(prefixDir, 'Teafile'), 'utf8'); - const pkgInfo = JSON.parse(pkgContent); - const config = { - outputDir: moduleOutputDir, - pkgDir: path.join(fixturesDir, moduleName), - php: { - package: 'Tea.PHP.Tests', - clientName: 'Client', - modelDirName: 'Models' - }, - ...pkgInfo - }; - const generator = new Generator(config, lang); - - const dsl = fs.readFileSync(mainFilePath, 'utf8'); - const ast = DSL.parse(dsl, mainFilePath); - generator.visit(ast); - expectedFiles.forEach(element => { - const outputFilePath = path.join(outputDir, moduleName, element); - const expectedFilePath = path.join(expectedDir, moduleName, element); - const expected = fs.readFileSync(expectedFilePath, 'utf8'); - assert.deepStrictEqual(fs.readFileSync(outputFilePath, 'utf8'), expected); - }); -} - -describe('PHP Generator', function () { - it('add annotation should ok', function () { - check('annotation', [ - 'Client.php', - 'Models/Test.php' - ]); - }); - - it('api should ok', function () { - check('api', [ - 'Client.php' - ]); - }); - - it('add comments should ok', function () { - check('comment', [ - 'Client.php', - 'Models/Test1.php', - 'Models/Test2.php', - 'Models/Test3.php' - ]); - }); - - it('complex should ok', function () { - check('complex', [ - 'Client.php', - 'Models/ComplexRequest.php', - 'Models/ComplexRequest/header.php', - 'Models/ComplexRequest/part.php' - ]); - }); - - it('const should ok', function () { - check('const', [ - 'Client.php' - ]); - }); - - it('empty should ok', function () { - check('empty', [ - 'Client.php' - ]); - }); - - it('function should ok', function () { - check('function', [ - 'Client.php' - ]); - }); - - it('import should ok', function () { - check('import', [ - 'Client.php' - ]); - }); - - it('map should ok', function () { - check('map', [ - 'Client.php' - ]); - }); - - it('model should ok', function () { - check('model', [ - 'Client.php', - 'Models/M.php', - 'Models/MyModel.php', - 'Models/MyModel/model_.php', - 'Models/MyModel/model/model_.php', - 'Models/MyModel/subarraymodel.php', - 'Models/MyModel/submodel.php', - 'Models/MyModel/submodel/model_.php', - 'Models/Class_.php', - 'Models/model_.php', - ]); - }); - - it('statements should ok', function () { - check('statements', [ - 'Client.php' - ]); - }); - - it('super should ok', function () { - check('super', [ - 'Client.php' - ]); - }); - - it('alias should ok', function () { - check('alias', [ - 'Client.php' - ]); - }); - - it('number should ok', function () { - check('number', [ - 'Client.php' - ]); - }); - - it('exec should ok', function () { - check('exec', [ - 'Client.php' - ]); - }); - - it('package should ok', function () { - check('package', [ - 'autoload.php', - 'composer.json', - 'src/Client.php' - ]); - }); - - it('typedef should ok', function () { - check('typedef', [ - 'autoload.php', - 'composer.json', - 'src/Client.php' - ]); - }); -}); diff --git a/tests/resolver.tests.js b/tests/resolver.tests.js deleted file mode 100644 index b29c300..0000000 --- a/tests/resolver.tests.js +++ /dev/null @@ -1,408 +0,0 @@ -'use strict'; - -const mm = require('mm'); -const expect = require('chai').expect; -require('mocha-sinon'); - -const ModelResolver = require('../src/resolver/model'); -const ClientResolver = require('../src/resolver/client'); - -const { - PropItem, - AnnotationItem, - BehaviorDoAction, - GrammerValue, - FuncItem -} = require('../src/langs/common/items'); -const { _deepClone } = require('../src/lib/helper'); - -const lang = 'php'; -const Combinator = require(`../src/langs/${lang}/combinator.js`); -const config = require(`../src/langs/${lang}/config.js`); -Object.assign(config, { - scope: 'test', - name: 'main' -}); - -describe('client resolver should be ok', function () { - beforeEach(function () { - this.sinon.stub(console, 'log'); - }); - - it('resolve should be ok', function () { - const combinator = new Combinator(Object.assign(_deepClone(config), { - package: 'test', model: { dir: 'Models' } - }), {}); - const code = new ClientResolver({ moduleBody: { nodes: [] } }, combinator, {}); - mm(code, 'initAnnotation', function () { return; }); - mm(code, 'resolveProps', function () { return; }); - mm(code.combinator, 'addInclude', function (className) { return className; }); - code.config.baseClient = 'BaseClient'; - code.resolve(); - expect(code.object.extends).to.be.eql(['^BaseClient']); - - mm.restore(); - }); - - it('resolveInitBody should be ok', function () { - const combinator = new Combinator(Object.assign(_deepClone(config), { - package: 'test', model: { dir: 'Models' } - }), {}); - const code = new ClientResolver({}, combinator, {}); - mm(code.combinator, 'addModelInclude', function (modelName) { - expect(modelName).to.be.eql('modelType'); - }); - mm(code.combinator, 'addInclude', function (className) { - return className; - }); - code.config.baseClient = 'BaseClient'; - let init = { - type: 'init', params: { - params: [{ - paramType: { - idType: 'model', - lexeme: 'modelType' - }, - paramName: { - lexeme: 'modelName' - } - }, { - paramType: { - idType: 'module', - lexeme: 'moduleType' - }, - paramName: { - lexeme: 'moduleName' - } - }] - } - }; - code.resolveInitBody(init); - mm.restore(); - }); - - it('code : requestBody should be ok', function () { - const combinator = new Combinator(Object.assign(_deepClone(config), { - package: 'test', model: { dir: 'Models' } - }), {}); - const code = new ClientResolver({}, combinator, {}); - mm(code, 'visitStmt', function (func) { - expect(func.name).to.be.eql('testFuncName'); - }); - const funcItem = new FuncItem(); - funcItem.name = 'testFuncName'; - code.requestBody({}, { - body: {}, - }, funcItem); - mm.restore(); - mm(code, 'visitStmt', function (func, item) { - expect(item).to.be.eql('https'); - }); - code.requestBody({}, { - protocol: ['https'] - }, funcItem); - }); - - it('renderGrammerValue should be ok', function () { - const combinator = new Combinator(Object.assign(_deepClone(config), { - package: 'test', model: { dir: 'Models' } - }), {}); - const code = new ClientResolver({}, combinator, {}); - expect(function () { - code.renderGrammerValue(null, { type: 'invalid' }); - }).to.be.throw('unimpelemented : invalid'); - - expect(function () { - code.renderGrammerValue(null, { - type: 'map_access', - accessKey: { - id: '', - value: { lexeme: '' } - }, - inferred: { type: 'basic', name: 'string' } - }); - }).to.be.throw(''); - - let grammerValue = code.renderGrammerValue(null, { - type: 'map_access', - id: { lexeme: 'test' }, - accessKey: { - id: 'test', - value: { lexeme: 'test' } - }, - inferred: { type: 'basic', name: 'string' } - }); - expect(grammerValue.value.path.length).to.be.eql(2); - - expect(function () { - code.renderGrammerValue(null, { - type: 'call', - left: { - type: 'invalid' - } - }); - }).to.be.throw(''); - - expect(function () { - code.renderGrammerValue(null, { - type: 'call', - left: { - type: 'static_call', - id: { type: 'invalid' } - } - }); - }).to.be.throw(''); - - expect(function () { - code.renderGrammerValue(null, { - type: 'call', - left: { - type: 'instance_call', - id: { type: 'invalid', lexeme: 'test' } - } - }); - }).to.be.throw('Unsupported object.left.id.type : invalid'); - - grammerValue = code.renderGrammerValue(null, { - type: 'call', - left: { - type: 'instance_call', - id: { lexeme: '@test' } - }, - inferred: { type: 'basic', name: 'string' } - }); - expect(grammerValue.value.path.length).to.be.eql(1); - - grammerValue = code.renderGrammerValue(null, { - type: 'call', - left: { - type: 'method_call', - id: { type: 'module', lexeme: 'Util' } - }, - inferred: { type: 'basic', name: 'string' } - }); - expect(grammerValue.value.path.length).to.be.eql(2); - - mm(code.combinator, 'addModelInclude', function (modelName) { - return modelName; - }); - grammerValue = code.renderGrammerValue(null, { - type: 'construct_model', - aliasId: { - lexeme: 'test' - }, - propertyPath: [{ lexeme: 'a' }, { lexeme: 'b' }], - inferred: { - type: 'model', - name: 'ComplexRequest.header', - } - }); - expect(grammerValue.value.name).to.be.eql('#test.a.b'); - - grammerValue = code.renderGrammerValue(null, { - type: 'property_access', - id: { - inferred: { - type: 'map', - keyType: { type: 'basic', name: 'string' }, - valueType: { type: 'basic', name: 'string' } - }, - lexeme: '__module' - }, - propertyPath: [{ lexeme: 'test' }], - propertyPathTypes: [{ type: 'basic', name: 'any' }], - needCast: true, - inferred: { type: 'basic', name: 'string' } - }); - expect(grammerValue.type).to.be.eql('behavior'); - - mm.restore(); - }); - - it('visitStmt should be ok', function () { - const combinator = new Combinator(Object.assign(_deepClone(config), { - package: 'test', model: { dir: 'Models' } - }), {}); - const code = new ClientResolver({}, combinator, {}); - const obj = new BehaviorDoAction(); - - expect(function () { - code.visitStmt(obj, {}); - }).to.be.throw(''); - expect(console.log.calledWith({})).to.be.true; - - let stmt = { type: 'while', condition: [{}] }; - mm(code, 'renderGrammerValue', function () { - return new GrammerValue('string', 'test'); - }); - code.visitStmt(obj, stmt); - expect(obj.body.length).to.be.eql(1); - - stmt = { type: 'virtualCall' }; - code.visitStmt(obj, stmt); - expect(obj.body.length).to.be.eql(2); - - stmt = { type: 'throw', expr: [{}] }; - mm(code.combinator, 'addInclude', function (className) { - return className; - }); - code.visitStmt(obj, stmt); - expect(obj.body.length).to.be.eql(3); - - stmt = { type: 'elseIfRequestAssign' }; - mm(code, 'visitIfElse', function () { return 'visitIfElse'; }); - code.visitStmt(obj, stmt); - expect(obj.body.length).to.be.eql(4); - - stmt = { - type: 'requestAssign', - left: { - id: { lexeme: 'test' }, - } - }; - code.predefined = { - '$Request': { - modelBody: { nodes: [{ fieldName: { lexeme: 'test' }, fieldValue: '' }] } - } - }; - code.visitStmt(obj, stmt); - expect(obj.body.length).to.be.eql(5); - - stmt = { - type: 'requestAssign', - left: { - type: 'request_property_assign', - id: { lexeme: 'test' }, - propertyPath: [{ lexeme: 'a' }, { lexeme: 'b' }] - } - }; - code.visitStmt(obj, stmt); - expect(obj.body.length).to.be.eql(6); - mm.restore(); - }); - - it('visitIfConfition should be ok', function () { - const combinator = new Combinator(Object.assign(_deepClone(config), { - package: 'test', model: { dir: 'Models' } - }), {}); - const code = new ClientResolver({}, combinator, {}); - const stmtCondition = { left: {}, type: 'invalid' }; - expect(function () { - code.visitIfConfition(stmtCondition); - }).to.be.throw(''); - expect(console.log.calledWith(stmtCondition)).to.be.true; - - stmtCondition.type = 'call'; - mm(code, 'renderGrammerValue', function () { - return 'render grammer value'; - }); - expect(code.visitIfConfition(stmtCondition)).to.be.eql('render grammer value'); - - stmtCondition.type = 'not'; - expect(code.visitIfConfition(stmtCondition).opt).to.be.eql('NOT'); - mm.restore(); - }); - - it('visitIfElse should be ok', function () { - const combinator = new Combinator(Object.assign(_deepClone(config), { - package: 'test', model: { dir: 'Models' } - }), {}); - const code = new ClientResolver({}, combinator, {}); - expect(function () { - code.visitIfElse({}); - }).to.be.throw(''); - expect(console.log.calledWith({})).to.be.true; - - let stmt = { stmts: [] }; - expect(function () { - code.visitIfElse(stmt); - }).to.be.throw(''); - expect(console.log.calledWith(stmt)).to.be.true; - - stmt = { - stmts: { type: 'stmts', stmts: [{ type: 'return', expr: { type: 'null' } }] }, - elseAssigns: [{ stmts: { type: 'stmts', stmts: [{ type: 'return', expr: { type: 'null' } }] } }] - }; - const grammer = code.visitIfElse(stmt); - expect(grammer.elseItem.length).to.be.eql(1); - }); -}); - -describe('model resolver should be ok', function () { - it('resolve should be ok', function () { - const combinator = new Combinator(Object.assign(_deepClone(config), { - package: 'test', model: { dir: 'Models' } - }), {}); - const model = new ModelResolver({ - type: 'model', - modelName: { lexeme: 'test' }, - modelBody: { nodes: [] }, - tokenRange: [1, 100] - }, combinator, {}); - mm(model, 'initAnnotation', function () { return; }); - mm(model.combinator, 'addInclude', function (modelName) { return modelName; }); - mm(model, 'initProp', function () { return; }); - mm(model, 'resolveAnnotations', function () { return [new AnnotationItem()]; }); - mm(model, 'getBetweenComments', function () { return; }); - model.resolve(); - expect(model.object.body.length).to.be.eql(1); - }); - - it('initProp should be ok', function () { - const combinator = new Combinator(Object.assign(_deepClone(config), { - package: 'test', model: { dir: 'Models' } - }), {}); - const model = new ModelResolver({}, combinator, {}); - expect(function () { - model.initProp([{ - fieldValue: { - fieldType: null - } - }]); - }).to.be.throw(''); - - mm(model.combinator, 'addModelInclude', function (modelName) { - expect(modelName).to.be.eql('a'); - }); - model.initProp([{ - fieldValue: { - type: 'fieldType', - fieldType: { type: 'moduleModel', path: [{ lexeme: 'a' }] } - }, - fieldName: { - lexeme: 'test' - }, - attrs: [{ attrValue: { value: 'test' }, attrName: { lexeme: 'name' } }] - }]); - mm.restore(); - mm(model, 'findSubModelsUsed', function () { - return; - }); - model.initProp([{ - type: 'modelField', - fieldValue: { type: 'fieldType', fieldType: 'array', fieldItemType: { lexeme: 'string' } }, - fieldName: { lexeme: 'test' }, - attrs: [] - }]); - expect(model.object.body.filter(item => item instanceof PropItem).length).to.be.eql(2); - mm.restore(); - }); - - it('findSubModelsUsed should be ok', function () { - const combinator = new Combinator(Object.assign(_deepClone(config), { - package: 'test', model: { dir: 'Models' } - }), {}); - const model = new ModelResolver({}, combinator, {}); - const subModelUsed = []; - model.findSubModelsUsed({ - fieldName: { lexeme: 'test' }, - fieldValue: { - nodes: [{ - fieldValue: { nodes: [] }, - fieldName: { lexeme: 'foo' }, - }] - } - }, subModelUsed); - expect(subModelUsed.length).to.be.eql(2); - }); -});