@darabonba/python-generator 1.2.19 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/ChangeLog.md +0 -158
  2. package/lib/builtin.js +818 -0
  3. package/lib/generator.js +2704 -0
  4. package/lib/helper.js +422 -0
  5. package/package.json +6 -5
  6. package/tests/expected/alias/setup.py +79 -0
  7. package/tests/expected/alias/tea_python_tests/__init__.py +1 -0
  8. package/tests/expected/alias/tea_python_tests/client.py +35 -0
  9. package/tests/expected/annotation/tea_python_tests/__init__.py +1 -0
  10. package/tests/expected/annotation/tea_python_tests/client.py +93 -0
  11. package/tests/expected/annotation/tea_python_tests/models.py +37 -0
  12. package/tests/expected/api/tea_python_tests/__init__.py +1 -0
  13. package/tests/expected/api/tea_python_tests/client.py +106 -0
  14. package/tests/expected/builtin/tea_python_tests/client.py +685 -0
  15. package/tests/expected/comment/tea_python_tests/__init__.py +1 -0
  16. package/tests/expected/comment/tea_python_tests/client.py +288 -0
  17. package/tests/expected/comment/tea_python_tests/models.py +195 -0
  18. package/tests/expected/complex/tea_python_tests/__init__.py +1 -0
  19. package/tests/expected/complex/tea_python_tests/client.py +1168 -0
  20. package/tests/expected/complex/tea_python_tests/exceptions.py +39 -0
  21. package/tests/expected/complex/tea_python_tests/models.py +570 -0
  22. package/tests/expected/const/tea_python_tests/__init__.py +1 -0
  23. package/tests/expected/const/tea_python_tests/client.py +14 -0
  24. package/tests/expected/empty/setup.py +74 -0
  25. package/tests/expected/empty/tea_python_tests/__init__.py +1 -0
  26. package/tests/expected/empty/tea_python_tests/client.py +10 -0
  27. package/tests/expected/exec/tea_python_tests/__init__.py +1 -0
  28. package/tests/expected/exec/tea_python_tests/exec_client.py +21 -0
  29. package/tests/expected/function/tea_python_tests/__init__.py +1 -0
  30. package/tests/expected/function/tea_python_tests/client.py +64 -0
  31. package/tests/expected/import/setup.py +78 -0
  32. package/tests/expected/import/tea_python_tests/__init__.py +1 -0
  33. package/tests/expected/import/tea_python_tests/client.py +29 -0
  34. package/tests/expected/map/tea_python_tests/__init__.py +1 -0
  35. package/tests/expected/map/tea_python_tests/client.py +39 -0
  36. package/tests/expected/model/tea_python_tests/__init__.py +1 -0
  37. package/tests/expected/model/tea_python_tests/client.py +10 -0
  38. package/tests/expected/model/tea_python_tests/exceptions.py +28 -0
  39. package/tests/expected/model/tea_python_tests/models.py +780 -0
  40. package/tests/expected/multi/tea_python_tests/api.py +95 -0
  41. package/tests/expected/multi/tea_python_tests/client.py +40 -0
  42. package/tests/expected/multi/tea_python_tests/lib/util.py +19 -0
  43. package/tests/expected/multi/tea_python_tests/model/user.py +23 -0
  44. package/tests/expected/multi/tea_python_tests/model/user_exceptions.py +83 -0
  45. package/tests/expected/multi/tea_python_tests/model/user_models.py +145 -0
  46. package/tests/expected/statements/tea_python_tests/__init__.py +1 -0
  47. package/tests/expected/statements/tea_python_tests/client.py +86 -0
  48. package/tests/expected/super/tea_python_tests/__init__.py +1 -0
  49. package/tests/expected/super/tea_python_tests/client.py +16 -0
  50. package/tests/expected/typedef/setup.py +77 -0
  51. package/tests/expected/typedef/tea_python_tests/__init__.py +1 -0
  52. package/tests/expected/typedef/tea_python_tests/client.py +74 -0
  53. package/tests/expected/typedef/tea_python_tests/models.py +42 -0
  54. package/tests/fixtures/alias/Darafile +11 -0
  55. package/tests/fixtures/alias/libraries/Alias/Darafile +11 -0
  56. package/tests/fixtures/alias/libraries/Alias-Symbol/Darafile +11 -0
  57. package/tests/fixtures/builtin/Darafile +6 -0
  58. package/tests/fixtures/builtin/main.dara +333 -0
  59. package/tests/fixtures/complex/libraries/import.dara +18 -11
  60. package/tests/fixtures/complex/main.dara +451 -103
  61. package/tests/fixtures/import/libraries/Darafile +1 -1
  62. package/tests/fixtures/import/pack/Darafile +3 -0
  63. package/tests/fixtures/map/libraries/Darafile +3 -0
  64. package/tests/fixtures/map/libraries/import.dara +4 -0
  65. package/tests/fixtures/map/main.dara +17 -2
  66. package/tests/fixtures/model/.libraries.json +3 -0
  67. package/tests/fixtures/model/Darafile +5 -2
  68. package/tests/fixtures/model/libraries/Darafile +20 -0
  69. package/tests/fixtures/model/libraries/import.dara +27 -0
  70. package/tests/fixtures/model/main.dara +60 -42
  71. package/tests/fixtures/multi/.libraries.json +3 -0
  72. package/tests/fixtures/multi/Darafile +12 -0
  73. package/tests/fixtures/multi/api.dara +20 -0
  74. package/tests/fixtures/multi/lib/util.dara +5 -0
  75. package/tests/fixtures/multi/libraries/darabonba_Util_0.2.11/Teafile +62 -0
  76. package/tests/fixtures/multi/libraries/darabonba_Util_0.2.11/main.tea +244 -0
  77. package/tests/fixtures/multi/main.dara +32 -0
  78. package/tests/fixtures/multi/model/user.dara +33 -0
  79. package/tests/{python3.tests.js → main.tests.js} +107 -65
  80. package/tests/output/alias/setup.py +79 -0
  81. package/tests/output/alias/tea_python_tests/client.py +35 -0
  82. package/tests/output/annotation/setup.py +77 -0
  83. package/tests/output/annotation/tea_python_tests/client.py +93 -0
  84. package/tests/output/annotation/tea_python_tests/models.py +37 -0
  85. package/tests/output/api/setup.py +77 -0
  86. package/tests/output/api/tea_python_tests/client.py +106 -0
  87. package/tests/output/builtin/setup.py +77 -0
  88. package/tests/output/builtin/tea_python_tests/client.py +685 -0
  89. package/tests/output/comment/setup.py +77 -0
  90. package/tests/output/comment/tea_python_tests/client.py +288 -0
  91. package/tests/output/comment/tea_python_tests/models.py +195 -0
  92. package/tests/output/complex/setup.py +77 -0
  93. package/tests/output/complex/tea_python_tests/client.py +1168 -0
  94. package/tests/output/complex/tea_python_tests/exceptions.py +39 -0
  95. package/tests/output/complex/tea_python_tests/models.py +570 -0
  96. package/tests/output/const/setup.py +77 -0
  97. package/tests/output/const/tea_python_tests/client.py +14 -0
  98. package/tests/output/empty/setup.py +77 -0
  99. package/tests/output/empty/tea_python_tests/client.py +10 -0
  100. package/tests/output/exec/setup.py +77 -0
  101. package/tests/output/exec/tea_python_tests/exec_client.py +21 -0
  102. package/tests/output/function/setup.py +77 -0
  103. package/tests/output/function/tea_python_tests/client.py +64 -0
  104. package/tests/output/import/setup.py +78 -0
  105. package/tests/output/import/tea_python_tests/client.py +29 -0
  106. package/tests/output/map/setup.py +77 -0
  107. package/tests/output/map/tea_python_tests/client.py +39 -0
  108. package/tests/output/model/setup.py +77 -0
  109. package/tests/output/model/tea_python_tests/client.py +10 -0
  110. package/tests/output/model/tea_python_tests/exceptions.py +28 -0
  111. package/tests/output/model/tea_python_tests/models.py +780 -0
  112. package/tests/output/multi/setup.py +77 -0
  113. package/tests/output/multi/tea_python_tests/api.py +95 -0
  114. package/tests/output/multi/tea_python_tests/client.py +40 -0
  115. package/tests/output/multi/tea_python_tests/lib/util.py +19 -0
  116. package/tests/output/multi/tea_python_tests/model/user.py +23 -0
  117. package/tests/output/multi/tea_python_tests/model/user_exceptions.py +83 -0
  118. package/tests/output/multi/tea_python_tests/model/user_models.py +145 -0
  119. package/tests/output/statements/setup.py +77 -0
  120. package/tests/output/statements/tea_python_tests/client.py +86 -0
  121. package/tests/output/super/setup.py +77 -0
  122. package/tests/output/super/tea_python_tests/client.py +16 -0
  123. package/tests/output/typedef/setup.py +78 -0
  124. package/tests/output/typedef/tea_python_tests/client.py +74 -0
  125. package/tests/output/typedef/tea_python_tests/models.py +42 -0
  126. package/tests/common.tests.js +0 -244
  127. package/tests/lib.tests.js +0 -269
  128. package/tests/python2.tests.js +0 -283
  129. package/tests/resolver.tests.js +0 -434
@@ -0,0 +1,2704 @@
1
+ 'use strict';
2
+
3
+ const assert = require('assert');
4
+
5
+ const path = require('path');
6
+ const fs = require('fs');
7
+
8
+ const DSL = require('@darabonba/parser');
9
+ const {
10
+ _name, _vid, _string, _upperFirst, _type, _escape,
11
+ _subModelName, _camelCase, _snakeCase, _getImport,
12
+ _isBinaryOp, _adaptedQuotes, CORE, REQUEST, RESPONSE
13
+ } = require('./helper');
14
+ const getBuiltin = require('./builtin');
15
+ const { Tag } = require('@darabonba/parser/lib/tag');
16
+ const Annotation = require('@darabonba/annotation-parser');
17
+
18
+ function avoidReserveName(name) {
19
+ const reserves = [
20
+ 'function'
21
+ ];
22
+
23
+ if (reserves.indexOf(name) !== -1) {
24
+ return `_${name}`;
25
+ }
26
+
27
+ return name;
28
+ }
29
+
30
+ class Visitor {
31
+
32
+ static get supportGenerateTest() {
33
+ return true;
34
+ }
35
+
36
+ constructor(option = {}) {
37
+ this.config = Object.assign({
38
+ outputDir: '',
39
+ indent: ' ',
40
+ clientName: option.python.clientName || 'Client',
41
+ className: option.className || 'Client',
42
+ }, option);
43
+ assert.ok(this.config.outputDir, '`option.outputDir` should not empty');
44
+ assert.ok(this.config.package, `Darafile -> python -> package should not empty, please add python option into Darafile.
45
+ example:
46
+ "pthon": {
47
+ "package": "darabonba.core",
48
+ "className": "Client"
49
+ }`);
50
+
51
+ this.typedef = this.config.typedef || {};
52
+ this.imports = [];
53
+ this.outputDir = this.config.outputDir;
54
+ this.setupPath = path.join(this.outputDir, 'setup.py');
55
+ this.modelPath = path.join(this.outputDir, this.config.package, 'models.py');
56
+ this.exceptionPath = path.join(this.outputDir, this.config.package, 'exceptions.py');
57
+ this.config.clientPath = path.join(this.outputDir, this.config.package, `${_snakeCase(this.config.clientName)}.py`);
58
+ this.classNamespace = new Map();
59
+ // 新增:用于存储已使用的类型
60
+ this.isAsyncFunction = false; // 新增:用于标记是否为异步函数
61
+ this.isStaticFunction = true; // 新增:用于标记是否为非静态函数
62
+ this.clientName = new Map(); // 新增:用于存储importName
63
+ // this.moduleDir = this.config.modelDirName || 'Models'; // 新增,用于存储models文件
64
+
65
+ this.output = '';
66
+ if (!fs.existsSync(this.outputDir)) {
67
+ fs.mkdirSync(this.outputDir, {
68
+ recursive: true
69
+ });
70
+ }
71
+
72
+ if (!this.outputDir) {
73
+ throw new Error('`option.outputDir` should not empty');
74
+ }
75
+
76
+ if (!fs.existsSync(this.outputDir)) {
77
+ fs.mkdirSync(this.outputDir, {
78
+ recursive: true
79
+ });
80
+ }
81
+ this.package = {};
82
+ this.initSetupPy();
83
+ }
84
+
85
+ initSetupPy() {
86
+ // 初始化包信息
87
+ this.package.name = this.package.name || this.config.package;
88
+ this.package.version = this.package.version || '1.0.0';
89
+ this.package.description = this.package.description || '';
90
+ this.package.author = this.package.author || 'Alibaba';
91
+ this.package.author_email = this.package.author_email || 'sdk-team@alibabacloud.com';
92
+ this.package.url = this.package.url || 'https://github.com/';
93
+ this.package.license = this.package.license || 'Apache License 2.0';
94
+ this.package.requires = this.package.requires || [];
95
+
96
+ // 收集依赖信息
97
+ if (!this.package.dependencies) {
98
+ this.package.dependencies = {};
99
+ }
100
+
101
+ Object.keys(this.typedef).forEach(type => {
102
+ if (this.typedef[type].package) {
103
+ let [pkgName, version] = this.typedef[type].package.split(':');
104
+ if (!this.package.dependencies[pkgName]) {
105
+ this.package.dependencies[pkgName] = version;
106
+ }
107
+ }
108
+ });
109
+
110
+ // 创建 setup.py 内容
111
+ const setupPyContent = `
112
+ # -*- coding: utf-8 -*-
113
+ """
114
+ Licensed to the Apache Software Foundation (ASF) under one
115
+ or more contributor license agreements. See the NOTICE file
116
+ distributed with this work for additional information
117
+ regarding copyright ownership. The ASF licenses this file
118
+ to you under the Apache License, Version 2.0 (the
119
+ "License"); you may not use this file except in compliance
120
+ with the License. You may obtain a copy of the License at
121
+
122
+ http://www.apache.org/licenses/LICENSE-2.0
123
+
124
+ Unless required by applicable law or agreed to in writing,
125
+ software distributed under the License is distributed on an
126
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
127
+ KIND, either express or implied. See the License for the
128
+ specific language governing permissions and limitations
129
+ under the License.
130
+ """
131
+
132
+ import os
133
+ from setuptools import setup, find_packages
134
+
135
+ """
136
+ setup module for tea_python_tests.
137
+
138
+ Created on *
139
+
140
+ @author: Alibaba
141
+ """
142
+
143
+ PACKAGE = "${this.package.name}"
144
+ NAME = "${this.package.name}"
145
+ DESCRIPTION = "${this.package.description}"
146
+ AUTHOR = "${this.package.author}"
147
+ AUTHOR_EMAIL = "${this.package.author_email}"
148
+ URL = "${this.package.url}"
149
+ VERSION = __import__(PACKAGE).__version__
150
+ REQUIRES = [
151
+ "darabonba-core>=1.0.0, <2.0.0",
152
+ ${Object.keys(this.package.dependencies).map(pkg => {
153
+ if(this.package.dependencies[pkg].includes('rc')) {
154
+ return ` "${pkg}==${this.package.dependencies[pkg]}"`;
155
+ }
156
+ return ` "${pkg}>=${this.package.dependencies[pkg]}, <${+this.package.dependencies[pkg].split('.')[0] + 1}.0.0"`;
157
+ }).join(',\n')}
158
+ ]
159
+
160
+ LONG_DESCRIPTION = ''
161
+ if os.path.exists('./README.md'):
162
+ with open("README.md", encoding='utf-8') as fp:
163
+ LONG_DESCRIPTION = fp.read()
164
+
165
+ setup(
166
+ name=NAME,
167
+ version=VERSION,
168
+ description=DESCRIPTION,
169
+ long_description=LONG_DESCRIPTION,
170
+ long_description_content_type='text/markdown',
171
+ author=AUTHOR,
172
+ author_email=AUTHOR_EMAIL,
173
+ license="Apache License 2.0",
174
+ url=URL,
175
+ keywords=["tea","python","tests"],
176
+ packages=find_packages(exclude=["tests*"]),
177
+ include_package_data=True,
178
+ platforms="any",
179
+ install_requires=REQUIRES,
180
+ python_requires=">=3.6",
181
+ classifiers=(
182
+ "Development Status :: 4 - Beta",
183
+ "Intended Audience :: Developers",
184
+ "License :: OSI Approved :: Apache Software License",
185
+ "Programming Language :: Python",
186
+ "Programming Language :: Python :: 3",
187
+ "Programming Language :: Python :: 3.6",
188
+ "Programming Language :: Python :: 3.7",
189
+ "Programming Language :: Python :: 3.8",
190
+ "Programming Language :: Python :: 3.9",
191
+ "Topic :: Software Development"
192
+ )
193
+ )
194
+ `.trim();
195
+
196
+ // 将内容写入 setup.py 文件
197
+ const setupPath = path.join(this.outputDir, 'setup.py');
198
+ fs.writeFileSync(setupPath, setupPyContent);
199
+ }
200
+
201
+
202
+
203
+
204
+ saveInnerModule(ast) {
205
+ const keys = ast.innerModule.keys();
206
+ let data = keys.next();
207
+ while (!data.done) {
208
+ const aliasId = data.value;
209
+ const moduleAst = ast.innerDep.get(aliasId);
210
+ this.ast = ast;
211
+ // this.modelPath = path.join(this.outputDir, this.config.package, 'models.py');
212
+ // this.exceptionPath = path.join(this.outputDir, this.config.package, 'exceptions.py');
213
+ const filepath = ast.innerModule.get(aliasId);
214
+ this.className = this.getInnerClient(aliasId);
215
+ this.modelPath = filepath.replace('.py', '_models.py');
216
+ this.exceptionPath = filepath.replace('.py', '_exceptions.py');
217
+ this.visitModule(moduleAst, filepath, false, 0);
218
+ data = keys.next();
219
+ }
220
+ }
221
+
222
+ save(filepath) {
223
+ let targetPath = filepath;
224
+ if(path.resolve(filepath).startsWith(path.resolve(this.outputDir))) {
225
+ const baseDir = path.join(this.outputDir, path.sep);
226
+ filepath = filepath.replace(baseDir, '');
227
+ }
228
+ targetPath = path.join(this.outputDir, filepath);
229
+ fs.mkdirSync(path.dirname(targetPath), {
230
+ recursive: true
231
+ });
232
+ this.emitImports();
233
+ fs.writeFileSync(targetPath, this.output);
234
+ this.initSetupPy();
235
+ this.output = '';
236
+ this.imports = [];
237
+ this.usedClass = new Map();
238
+ }
239
+
240
+ emit(str, level) {
241
+ this.output += ' '.repeat(level * 2) + str;
242
+ }
243
+
244
+ visit(ast, level = 0) {
245
+ this.visitModule(ast, this.config.clientPath, level);
246
+ }
247
+
248
+ overwrite(ast, filepath) {
249
+ if(!ast.moduleBody.nodes || !ast.moduleBody.nodes.length) {
250
+ return;
251
+ }
252
+ const beginNotes = DSL.note.getNotes(this.notes, 0, ast.moduleBody.nodes[0].tokenRange[0]);
253
+ const overwirte = beginNotes.find(note => note.note.lexeme === '@overwrite');
254
+ let targetPath = filepath;
255
+ if(path.resolve(filepath).startsWith(path.resolve(this.outputDir))) {
256
+ const baseDir = path.join(this.outputDir, path.sep);
257
+ filepath = filepath.replace(baseDir, '');
258
+ }
259
+ targetPath = path.join(this.outputDir, filepath);
260
+ if(overwirte && overwirte.arg.value === false && fs.existsSync(targetPath)) {
261
+ return false;
262
+ }
263
+ return true;
264
+ }
265
+
266
+ visitModule(ast, filepath, level) {
267
+ assert.equal(ast.type, 'module');
268
+ this.ast = ast;
269
+ this.predefined = ast.models;
270
+ this.usedExternException = ast.usedExternException;
271
+ this.usedExternModel = ast.usedExternModel;
272
+ this.parentModule = ast.extends;
273
+ this.comments = ast.comments;
274
+ this.notes = ast.notes;
275
+ this.builtin = getBuiltin(this);
276
+ ast.innerModule = new Map();
277
+ this.packageInfo = {};
278
+ this.usedTypes = [];
279
+ this.imports = [];
280
+ if(this.overwrite(ast, filepath) === false) {
281
+ return;
282
+ }
283
+
284
+ if(!this.className) {
285
+ let clientName = this.config.clientName.replace(/(?:^|_)([a-z])/g, (_, c) => (c ? c.toUpperCase() : ''));
286
+ this.className = clientName;
287
+ }
288
+
289
+
290
+ this.eachImport(ast.imports, ast.usedExternModel, ast.innerModule, filepath, level);
291
+
292
+ const subModels = Object.keys(this.predefined).filter((key) => {
293
+ return !key.startsWith('$') && this.predefined[key].type === 'model' && key.indexOf('.') !== -1;
294
+ }).map((key) => {
295
+ return this.predefined[key];
296
+ });
297
+
298
+ for (let i = 0; i < subModels.length; i++) {
299
+ // sub model
300
+ // TODO: 生成model class之前需要判断属性是否为自定义类型,如果属性是自定义类型,需要先定义自定义类型
301
+ this.eachSubModel(subModels[i], level);
302
+ }
303
+
304
+ const models = ast.moduleBody.nodes.filter((item) => {
305
+ return item.type === 'model';
306
+ });
307
+
308
+ this.modelBefore(ast, level);
309
+ for (let i = 0; i < models.length; i++) {
310
+ this.eachModel(models[i], level);
311
+ }
312
+ if (models.length > 0) {
313
+ // 存一笔 models
314
+
315
+ this.save(this.modelPath);
316
+ this.usedTypes = [];
317
+ this.imports = [];
318
+ }
319
+
320
+ const exceptions = ast.moduleBody.nodes.filter((item) => {
321
+ return item.type === 'exception';
322
+ });
323
+
324
+
325
+ if (exceptions.length > 0) {
326
+ this.exceptionsBody = true;
327
+ for (let i = 0; i < exceptions.length; i++) {
328
+ this.eachException(exceptions[i], level);
329
+ }
330
+ this.exceptionsBody = false;
331
+ this.save(this.exceptionPath);
332
+ this.usedTypes = [];
333
+ this.imports = [];
334
+ }
335
+
336
+
337
+ this.moduleBefore(ast, level);
338
+
339
+ this.visitAnnotation(ast.annotation, level);
340
+
341
+
342
+
343
+ // models definition
344
+ this.apiBefore(level);
345
+ // TODO: 这个types里有type对应的类型,在这块加上一个非基础类型筛选,然后根据类型引入对应的模块
346
+ const types = ast.moduleBody.nodes.filter((item) => {
347
+ return item.type === 'type';
348
+ });
349
+
350
+ const inits = ast.moduleBody.nodes.filter((item) => {
351
+ return item.type === 'init';
352
+ });
353
+
354
+ const [init] = inits;
355
+ if (init) {
356
+ this.visitInit(init, types, level);
357
+ } else {
358
+ // 没有 init 的时候,也要处理 types
359
+ this.emit('\n');
360
+ types.forEach((type) => {
361
+ let comments = DSL.comment.getFrontComments(this.comments, type.tokenRange[0]);
362
+ this.visitComments(comments, level + 2);
363
+ this.emit(`${_snakeCase(_vid(type.vid))}: `, level + 2);
364
+ this.visitType(type.value);
365
+ this.emit(' = None\n');
366
+ });
367
+ this.emit('\n');
368
+ this.emit(` def __init__(self):
369
+ pass\n`);
370
+ }
371
+
372
+ const apis = ast.moduleBody.nodes.filter((item) => {
373
+ return item.type === 'api';
374
+ });
375
+
376
+ for (let i = 0; i < apis.length; i++) {
377
+ // 每个API都需要 Tea.request import TeaRequest
378
+ // from Tea.core import TeaCore
379
+ // 但是不需要重复引入
380
+ this.imports.push({
381
+ className: `${CORE}Core`,
382
+ packageName: 'darabonba.core'
383
+ });
384
+ this.eachAPI(apis[i], level + 2);
385
+ }
386
+
387
+ // this.functionBefore();
388
+ const functions = ast.moduleBody.nodes.filter((item) => {
389
+ return item.type === 'function';
390
+ });
391
+
392
+ for (let i = 0; i < functions.length; i++) {
393
+ this.eachFunction(functions[i], level + 2);
394
+ }
395
+
396
+ if (this.config.exec) {
397
+ this.emitExec();
398
+ }
399
+ // 最后处理import
400
+ this.save(filepath);
401
+ this.saveInnerModule(ast, filepath);
402
+ }
403
+
404
+ emitExec() {
405
+ this.pushImports('sys');
406
+ this.emit(`\n\nif __name__ == '__main__':
407
+ ${this.config.clientName.replace(/(?:^|_)([a-z])/g, (_, c) => (c ? c.toUpperCase() : ''))}.main(sys.argv[1:])\n`);
408
+ }
409
+
410
+ visitComments(comments, level) {
411
+ comments.forEach(comment => {
412
+ // 移除注释标记“// ”
413
+ const uncommented = comment.value.slice(3).trim();
414
+ // TODO: 这个地方需要判断什么场景用三引号 什么时候用#
415
+ // 使用三引号包裹并缩进
416
+ // this.emit(`"""\n`,level);
417
+ // this.emit(`${uncommented}\n`, level);
418
+ // this.emit(`"""\n`, level);
419
+ this.emit(`# ${uncommented}\n`, level);
420
+ });
421
+ }
422
+
423
+
424
+ visitAnnotation(annotation, level) {
425
+ if (!annotation || !annotation.value) {
426
+ return;
427
+ }
428
+ let comments = DSL.comment.getFrontComments(this.comments, annotation.index);
429
+ this.visitComments(comments, level);
430
+ var ast = Annotation.parse(annotation.value);
431
+ var description = ast.items.find((item) => {
432
+ return item.type === 'description';
433
+ });
434
+ var summary = ast.items.find((item) => {
435
+ return item.type === 'summary';
436
+ });
437
+ var _return = ast.items.find((item) => {
438
+ return item.type === 'return';
439
+ });
440
+ var deprecated = ast.items.find((item) => {
441
+ return item.type === 'deprecated';
442
+ });
443
+ var params = ast.items.filter((item) => {
444
+ return item.type === 'param';
445
+ }).map((item) => {
446
+ return {
447
+ name: item.name.id,
448
+ text: item.text.text.trimEnd()
449
+ };
450
+ });
451
+ var throws = ast.items.filter((item) => {
452
+ return item.type === 'throws';
453
+ }).map((item) => {
454
+ return item.text.text.trimEnd();
455
+ });
456
+
457
+ const descriptionText = description ? description.text.text.trimEnd() : '';
458
+ const summaryText = summary ? summary.text.text.trimEnd() : '';
459
+ const returnText = _return ? _return.text.text.trimEnd() : '';
460
+ let hasNextSection = false;
461
+
462
+ this.emit('"""\n', level);
463
+ if (summaryText !== '') {
464
+ summaryText.split('\n').forEach((line) => {
465
+ this.emit(` * ${line}\n`, level);
466
+ });
467
+ hasNextSection = true;
468
+ }
469
+ if (descriptionText !== '') {
470
+ if (hasNextSection) {
471
+ this.emit(' * \n', level);
472
+ }
473
+ this.emit(' * @remarks\n', level);
474
+ descriptionText.split('\n').forEach((line) => {
475
+ this.emit(` * ${line}\n`, level);
476
+ });
477
+ hasNextSection = true;
478
+ }
479
+ if (deprecated) {
480
+ if (hasNextSection) {
481
+ this.emit(' * \n', level);
482
+ }
483
+ const deprecatedText = deprecated.text.text.trimEnd();
484
+ this.emit(' * @deprecated', level);
485
+ deprecatedText.split('\n').forEach((line, index) => {
486
+ if (index === 0) {
487
+ this.emit(` ${line}\n`);
488
+ } else {
489
+ this.emit(` * ${line}\n`, level);
490
+ }
491
+ });
492
+ hasNextSection = true;
493
+ }
494
+ if (params.length > 0) {
495
+ if (hasNextSection) {
496
+ this.emit(' * \n', level);
497
+ }
498
+ params.forEach((item) => {
499
+ this.emit(` * @param ${item.name} - `, level);
500
+ const items = item.text.trimEnd().split('\n');
501
+ items.forEach((line, index) => {
502
+ if (index === 0) {
503
+ this.emit(`${line}\n`);
504
+ } else {
505
+ this.emit(` * ${line}\n`, level);
506
+ }
507
+ });
508
+ });
509
+ }
510
+ if (returnText !== '') {
511
+ this.emit(' * @returns', level);
512
+ const returns = returnText.split('\n');
513
+ returns.forEach((line, index) => {
514
+ if (index === 0) {
515
+ this.emit(` ${line}\n`);
516
+ } else {
517
+ this.emit(` * ${line}\n`, level);
518
+ }
519
+ });
520
+ }
521
+ if (throws.length > 0) {
522
+ this.emit(' * \n', level);
523
+ throws.forEach((item) => {
524
+ this.emit(' * @throws', level);
525
+ const items = item.trimEnd().split('\n');
526
+ items.forEach((line, index) => {
527
+ if (index === 0) {
528
+ this.emit(` ${line}\n`);
529
+ } else {
530
+ this.emit(` * ${line}\n`, level);
531
+ }
532
+ });
533
+ });
534
+ }
535
+ this.emit('"""', level);
536
+ this.emit('\n');
537
+ }
538
+
539
+ visitInit(ast, types, level) {
540
+ assert.equal(ast.type, 'init');
541
+ this.emit('\n');
542
+ types.forEach((item) => {
543
+ let comments = DSL.comment.getFrontComments(this.comments, item.tokenRange[0]);
544
+ this.visitComments(comments, level + 2);
545
+ this.emit(`${_snakeCase(_vid(item.vid))}: `, level + 2);
546
+ this.visitType(item.value);
547
+ this.emit(' = None\n', level);
548
+ });
549
+ if(ast.params.params.length !== 0) {
550
+ this.emit('\n');
551
+ this.emit('def __init__(\n', level + 2);
552
+ this.emit('self,\n', level + 4);
553
+ for (var i = 0; i < ast.params.params.length; i++) {
554
+ const node = ast.params.params[i];
555
+ assert.equal(node.type, 'param');
556
+ const name = _snakeCase(_name(node.paramName));
557
+ this.emit(`${avoidReserveName(name)}: `, level + 4);
558
+ this.visitType(node.paramType, level);
559
+ this.emit(',');
560
+ if (i !== ast.params.length - 1) {
561
+ this.emit('\n');
562
+ }
563
+ }
564
+ this.emit('):\n', level + 2);
565
+ } else {
566
+ this.emit('def __init__(self):\n', level + 2);
567
+ }
568
+ if (ast.initBody && ast.initBody.stmts.length !==0 ) {
569
+ this.visitStmts(ast.initBody, level + 4);
570
+ } else {
571
+ this.emit('pass\n', level + 4);
572
+ }
573
+ }
574
+
575
+ eachImport(imports, usedModels, innerModule, filepath, level) {
576
+ this.moduleTypedef = {};
577
+ if (imports.length > 0) {
578
+ const lockPath = path.join(this.config.pkgDir, '.libraries.json');
579
+ const lock = fs.existsSync(lockPath) ? JSON.parse(fs.readFileSync(lockPath, 'utf8')) : {};
580
+ for (let i = 0; i < imports.length; i++) {
581
+ const item = imports[i];
582
+ let comments = DSL.comment.getFrontComments(this.comments, item.tokenRange[0]);
583
+ this.visitComments(comments, level);
584
+ const aliasId = item.lexeme;
585
+ const main = item.mainModule;
586
+ const inner = item.module;
587
+ const moduleDir = main ? this.config.libraries[main] : this.config.libraries[aliasId];
588
+ const innerPath = item.innerPath;
589
+ if (!moduleDir && innerPath) {
590
+ let pyPath = innerPath.replace(/(\.tea)$|(\.spec)$|(\.dara)$/gi, '') + '.py';
591
+ if (pyPath.startsWith('./') || pyPath.startsWith('../')) {
592
+ pyPath = pyPath.split('/').map(dir => _snakeCase(dir)).join(path.sep);
593
+ pyPath = path.join(path.dirname(filepath), `${pyPath}`);
594
+ } else if (pyPath.startsWith('/')) {
595
+ pyPath = pyPath.split('/').map(dir => _snakeCase(dir)).join(path.sep);
596
+ pyPath = `${pyPath}`;
597
+ }
598
+
599
+ const classNamespace = this.getClassNamespace(pyPath);
600
+ const className = this.getInnerClient(aliasId, pyPath);
601
+ const aliasName = this.getAliasName(className, aliasId);
602
+ const filename = _snakeCase(path.basename(pyPath, '.py'));
603
+ this.packageInfo[aliasId] = {
604
+ aliasName: aliasName || className,
605
+ clientName: className,
606
+ namemespace: classNamespace,
607
+ fileName: filename,
608
+ models: `${filename}_models`,
609
+ exceptions: `${filename}_exceptions`,
610
+ };
611
+
612
+ innerModule.set(aliasId, pyPath);
613
+ continue;
614
+ }
615
+ let targetPath = '';
616
+ if (moduleDir.startsWith('./') || moduleDir.startsWith('../')) {
617
+ targetPath = path.join( this.config.pkgDir, moduleDir);
618
+ } else if (moduleDir.startsWith('/')) {
619
+ targetPath = moduleDir;
620
+ } else {
621
+ targetPath = path.join(this.config.pkgDir, lock[moduleDir]);
622
+ }
623
+ const pkgPath = fs.existsSync(path.join(targetPath, 'Teafile')) ? path.join(targetPath, 'Teafile') : path.join(targetPath, 'Darafile');
624
+ const pkg = JSON.parse(fs.readFileSync(pkgPath));
625
+ // 这部分是import
626
+ const pyPkg = pkg.python;
627
+ if (!pyPkg) {
628
+ throw new Error(`The '${aliasId}' has no Python supported.`);
629
+ }
630
+ let className = _camelCase(pyPkg.clientName || 'client');
631
+ let classNamespace = pyPkg.package;
632
+ let models = 'models';
633
+ let exceptions = 'exceptions';
634
+ if(inner && pkg.exports[inner]) {
635
+ let pyPath = pkg.exports[inner];
636
+ const [ filename ] = pyPath.split(path.sep).slice(-1);
637
+ models = filename.replace(/(\.tea)$|(\.spec)$|(\.dara)$/gi, '') + '_models';
638
+ exceptions = filename.replace(/(\.tea)$|(\.spec)$|(\.dara)$/gi, '') + '_exceptions';
639
+ const arr = pyPath.split(path.sep).slice(1, -1);
640
+ arr.map(key => {
641
+ classNamespace += '.' + _snakeCase(key);
642
+ });
643
+ const exportClientName = pyPkg.exports && pyPkg.exports[inner];
644
+ className = _camelCase(exportClientName || 'Client');
645
+ }
646
+ const aliasName = this.getAliasName(className, aliasId);
647
+ this.packageInfo[aliasId] = {
648
+ aliasName: aliasName || className,
649
+ fileName: _snakeCase(className),
650
+ clientName: className,
651
+ namemespace: classNamespace,
652
+ models: models,
653
+ exceptions: exceptions,
654
+ };
655
+ // 这部分处理setup.py
656
+ if (pkg.releases && pkg.releases.python) {
657
+ const REQUIRE = pkg.releases.python ;
658
+ const [pkgName, version] = REQUIRE.split(':');
659
+ this.package.dependencies[pkgName] = `${version}`;
660
+ }
661
+ const typedef = pkg.python && pkg.python.typedef || {};
662
+ this.moduleTypedef[aliasId] = typedef;
663
+ Object.keys(typedef).forEach(type => {
664
+ if (typedef[type].package) {
665
+ let [pack, ver] = typedef[type].package.split(':');
666
+ if (!this.package.dependencies[pack]) {
667
+ this.package.dependencies[pack] = ver;
668
+ }
669
+ }
670
+ });
671
+ }
672
+ this.emit('\n\n');
673
+ this.__externModule = usedModels;
674
+ }
675
+ }
676
+
677
+ visitTypedef(type, module) {
678
+ if (module && module.idType === 'module') {
679
+ const aliasId = _name(module);
680
+ if (this.moduleTypedef[aliasId] && this.moduleTypedef[aliasId][type]) {
681
+ if (this.moduleTypedef[aliasId][type].import) {
682
+ this.imports.push({
683
+ packageName: this.moduleTypedef[aliasId][type].import,
684
+ className: this.moduleTypedef[aliasId][type].type,
685
+ });
686
+ }
687
+
688
+ return this.getTypedefType(this.moduleTypedef[aliasId][type].type);
689
+ }
690
+ }
691
+
692
+ if (type.idType === 'typedef' && this.typedef[type.lexeme]) {
693
+ if (this.typedef[type.lexeme]) {
694
+ if (this.typedef[type.lexeme].import) {
695
+ this.imports.push({
696
+ packageName: this.typedef[type.lexeme].import,
697
+ className: this.typedef[type.lexeme].type,
698
+ });
699
+ }
700
+
701
+ return this.getTypedefType(this.typedef[type.lexeme].type);
702
+ }
703
+ }
704
+ }
705
+
706
+ getTypedefType(type) {
707
+ if(/\bDict\b/.test(type)) {
708
+ this.usedTypes.push('Dict');
709
+ }
710
+
711
+ if(/\bList\b/.test(type)) {
712
+ this.usedTypes.push('List');
713
+ }
714
+
715
+ if(/\bAny\b/.test(type)) {
716
+ this.usedTypes.push('Any');
717
+ }
718
+
719
+ if(/\bBinaryIO\b/.test(type)) {
720
+ this.usedTypes.push('BinaryIO');
721
+ }
722
+
723
+ return type;
724
+ }
725
+
726
+ visitParams(ast, level, instanceFunc) {
727
+ level += 2;
728
+ assert.equal(ast.type, 'params');
729
+ if (ast.params.length === 0) {
730
+ this.emit(`(${instanceFunc ? 'self' : ''})`);
731
+ return;
732
+ }
733
+ this.emit('(\n');
734
+ if (instanceFunc){
735
+ this.emit('self,\n', level);
736
+ }
737
+ for (var i = 0; i < ast.params.length; i++) {
738
+ const node = ast.params[i];
739
+ assert.equal(node.type, 'param');
740
+ const name = _snakeCase(_name(node.paramName));
741
+ this.emit(`${avoidReserveName(name)}: `, level);
742
+ this.visitType(node.paramType, level);
743
+ this.emit(',');
744
+ if (i !== ast.params.length - 1) {
745
+ this.emit('\n');
746
+ }
747
+ }
748
+ this.emit('\n');
749
+ this.emit(')',level - 2);
750
+ }
751
+
752
+ visitType(ast, level) {
753
+ if (ast.type === 'array') {
754
+ this.pushImports('array');
755
+ this.emit('List[');
756
+ this.visitType(ast.subType, level);
757
+ this.emit(']');
758
+ } else if (ast.type === 'moduleModel') {
759
+ const [moduleId, ...rest] = ast.path;
760
+ const modelName = _subModelName(rest.map((item) => item.lexeme).join('.'));
761
+ this.emit(this.getModelName(modelName, _name(moduleId)));
762
+ } else if (ast.type === 'subModel') {
763
+ const [moduleId, ...rest] = ast.path;
764
+ this.emit('main_models.');
765
+ this.emit(_subModelName([moduleId.lexeme, ...rest.map((item) => {
766
+ return item.lexeme;
767
+ })].join('.')));
768
+ } else if (ast.type === 'moduleTypedef') {
769
+ const [moduleId, ...rest] = ast.path;
770
+ const type = rest.map((item) => { return item.lexeme; }).join('.');
771
+ this.emit(this.visitTypedef(type, moduleId));
772
+ } else if (ast.type === 'typedef' || ast.idType === 'typedef') {
773
+ this.emit(this.visitTypedef(ast));
774
+ } else if (ast.type === 'map') {
775
+ // 记录使用了Dict
776
+ this.pushImports('map');
777
+ this.emit('Dict[');
778
+ this.visitType(ast.keyType, level);
779
+ this.emit(', ');
780
+ this.visitType(ast.valueType, level);
781
+ this.emit(']');
782
+ } else if (ast.type === 'model') {
783
+ this.emit(this.getModelName(_upperFirst(_name(ast)), ast.moduleName));
784
+ } else if (ast.idType === 'model') {
785
+ this.emit(this.getModelName(_upperFirst(_name(ast)), ast.moduleName));
786
+ } else if (ast.type === 'module') {
787
+ this.emit(this.getModelName('', _name(ast), 'module'));
788
+ } else if (ast.idType === 'module') {
789
+ this.emit(this.getModelName('', _name(ast), 'module'));
790
+ } else if (this.isIterator(ast)) {
791
+ this.visitType(ast.valueType);
792
+ } else if (ast.type === 'entry') {
793
+ this.emit('[str, ');
794
+ this.visitType(ast.valueType);
795
+ this.emit(']');
796
+ } else {
797
+ const typeName = _type(_name(ast));
798
+ this.pushImports(typeName);
799
+ this.emit(typeName);
800
+ }
801
+ }
802
+
803
+ visitTypeWithNone(ast, level) {
804
+ this.visitType(ast, level);
805
+ this.emit(' = None');
806
+ }
807
+
808
+
809
+ visitReturnType(ast, level) {
810
+ this.emit(' -> ');
811
+ if(this.isIterator(ast.returnType)) {
812
+ if(this.isAsyncFunction) {
813
+ this.usedTypes.push('AsyncGenerator');
814
+ this.emit('AsyncGenerator[');
815
+ } else {
816
+ this.usedTypes.push('Generator');
817
+ this.emit('Generator[');
818
+ }
819
+ }
820
+
821
+ this.visitType(ast.returnType, level);
822
+ if (this.isIterator(ast.returnType)) {
823
+ this.emit(', None, None]');
824
+ }
825
+ }
826
+
827
+ visitAPIBody(ast, level) {
828
+ assert.equal(ast.type, 'apiBody');
829
+ this.pushImports(`${CORE}Request`);
830
+ this.emit(`${REQUEST} = ${CORE}Request()\n`, level);
831
+ this.visitStmts(ast.stmts, level);
832
+ }
833
+
834
+ visitRuntimeBefore(ast, level) {
835
+ assert.equal(ast.type, 'object');
836
+ this.emit('_runtime = {\n', level + 2);
837
+ if(ast.fields.length !== 0){
838
+ ast.fields.forEach((field) => {
839
+ this.emit(`'${field.fieldName.lexeme}': `, level + 4);
840
+ this.visitExpr(field.expr);
841
+ this.emit(',\n');
842
+ });
843
+ }
844
+ this.emit('}\n', level +2);
845
+ this.emit('_last_request = None\n', level+2);
846
+ this.emit('_last_response = None\n', level+2);
847
+ this.emit('_retries_attempted = 0\n', level + 2);
848
+ this.emit(`_context = RetryPolicyContext(
849
+ retries_attempted= _retries_attempted
850
+ )\n`, level + 2);
851
+ this.emit(`while ${CORE}Core.should_retry(_runtime.get('retryOptions'), _context):\n`, level + 2);
852
+ this.emit('if _retries_attempted > 0:\n', level + 4);
853
+ this.emit(`_backoff_time = ${CORE}Core.get_backoff_time(_runtime.get('retryOptions'), _context)\n`, level + 6);
854
+ this.emit('if _backoff_time > 0:\n', level + 6);
855
+ this.emit(`${CORE}Core.sleep(_backoff_time)\n`, level + 8);
856
+ this.emit('_retries_attempted = _retries_attempted + 1\n', level + 4);
857
+ this.emit('try:\n', level + 4);
858
+ }
859
+
860
+ visitStmt(ast, level) {
861
+ let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
862
+ this.visitComments(comments, level);
863
+ if (ast.type === 'return') {
864
+ this.visitReturn(ast, level);
865
+ } else if (ast.type === 'yield') {
866
+ this.visitYield(ast, level);
867
+ } else if (ast.type === 'if') {
868
+ this.visitIf(ast, level);
869
+ } else if (ast.type === 'throw') {
870
+ this.visitThrow(ast, level);
871
+ } else if (ast.type === 'assign') {
872
+ this.visitAssign(ast, level);
873
+ } else if (ast.type === 'retry') {
874
+ this.visitRetry(ast, level);
875
+ } else if (ast.type === 'break') {
876
+ this.emit('break\n', level);
877
+ } else if (ast.type === 'declare') {
878
+ this.visitDeclare(ast, level);
879
+ } else if (ast.type === 'while') {
880
+ this.visitWhile(ast, level);
881
+ } else if (ast.type === 'for') {
882
+ this.visitFor(ast, level);
883
+ } else if (ast.type === 'try') {
884
+ this.visitTry(ast, level);
885
+ } else {
886
+ this.emit('', level);
887
+ this.visitExpr(ast, level);
888
+ this.emit('\n');
889
+ }
890
+ }
891
+
892
+ visitFieldType(value, level, modelName, fieldName) {
893
+ if (value.type === 'modelBody') {
894
+ if(this.exceptionsBody) {
895
+ this.emit('main_models.');
896
+ }
897
+ this.emit(`${_subModelName([modelName, fieldName].join('.'))}`);
898
+ } else if (value.type === 'array') {
899
+ this.visitType(value);
900
+ } else if (value.fieldType === 'array') {
901
+ this.pushImports('array');
902
+ this.emit('List[');
903
+ this.visitFieldType(value.fieldItemType, level, modelName, fieldName);
904
+ this.emit(']');
905
+ } else if (value.fieldType === 'map') {
906
+ this.pushImports('map');
907
+ this.emit('Dict[');
908
+ this.emit(`${_type(_name(value.keyType))}, `);
909
+ this.visitFieldType(value.valueType);
910
+ this.emit(']');
911
+ } else if (value.type === 'map') {
912
+ this.pushImports('map');
913
+ this.emit('Dict[');
914
+ this.emit(`${_type(_name(value.keyType))}, `);
915
+ this.visitFieldType(value.valueType);
916
+ this.emit(']');
917
+ } else if (value.tag === Tag.TYPE) {
918
+ const type = _type(value.lexeme);
919
+ this.pushImports(type);
920
+ this.emit(`${type}`);
921
+ } else if (value.tag === Tag.ID) {
922
+ this.visitType(value);
923
+ } else if (value.type === 'moduleModel') {
924
+ let type = 'model';
925
+ const [moduleId, ...models] = value.path;
926
+ const modelName = _subModelName(models.map((item) => item.lexeme).join('.'));
927
+ const externEx = this.usedExternException.get(_name(moduleId.lexeme));
928
+ if (externEx && externEx.has(modelName)) {
929
+ type = 'exception';
930
+ }
931
+
932
+ this.emit(this.getModelName(modelName, _name(moduleId)), type);
933
+
934
+ } else if (value.type === 'subModel') {
935
+ const [moduleId, ...rest] = value.path;
936
+ const modelName = _subModelName([moduleId.lexeme, ...rest.map((item) => {
937
+ return item.lexeme;
938
+ })].join('.'));
939
+ this.emit(this.getModelName(modelName));
940
+ } else if (typeof value.fieldType === 'string'){
941
+ const type = _type(value.fieldType);
942
+ this.pushImports(type);
943
+ this.emit(type);
944
+ } else if (value.fieldType.type === 'moduleModel') {
945
+ let type = 'model';
946
+ const [moduleId, ...models] = value.fieldType.path;
947
+ const modelName = _subModelName(models.map((item) => item.lexeme).join('.'));
948
+ const externEx = this.usedExternException.get(_name(moduleId.lexeme));
949
+ if (externEx && externEx.has(modelName)) {
950
+ type = 'exception';
951
+ }
952
+ this.emit(this.getModelName(modelName, _name(moduleId), type));
953
+
954
+ } else if (value.fieldType.type === 'moduleTypedef') {
955
+ const [moduleId, ...rest] = value.fieldType.path;
956
+ const type = rest.map((item) => { return item.lexeme; }).join('.');
957
+ this.emit(this.visitTypedef(type, moduleId));
958
+ } else if (value.fieldType.type === 'typedef' || value.fieldType.idType === 'typedef') {
959
+ this.emit(this.visitTypedef(value.fieldType));
960
+ } else if (value.fieldType.type === 'subModel') {
961
+ const [moduleId, ...rest] = value.fieldType.path;
962
+ const modelName = _subModelName([moduleId.lexeme, ...rest.map((item) => {
963
+ return item.lexeme;
964
+ })].join('.'));
965
+ this.emit(this.getModelName(modelName));
966
+ } else if (value.fieldType.type) {
967
+ const type = _type(value.fieldType.lexeme);
968
+ this.pushImports(type);
969
+ this.emit(`${type}`);
970
+ } else if (value.fieldType.idType === 'model') {
971
+ let type = 'model';
972
+ if (this.predefined[_name(type)] && this.predefined[_name(type)].isException) {
973
+ type = 'exception';
974
+ }
975
+ this.emit(this.getModelName(_name(value.fieldType), value.fieldType.moduleName, type));
976
+ } else if (value.fieldType.idType === 'module') {
977
+ this.emit(this.getModelName('', _type(_name(value.fieldType)), 'module'));
978
+ } else if (value.fieldType.idType === 'builtin_model') {
979
+ const type = _type(value.fieldType.lexeme);
980
+ this.pushImports(type);
981
+ this.emit(`${type}`);
982
+ }
983
+ }
984
+
985
+ visitModelBody(ast, level, modelName) {
986
+ assert.equal(ast.type, 'modelBody');
987
+ this.visitFieldsInit(ast, level, modelName);
988
+ let node;
989
+
990
+ for (let i = 0; i < ast.nodes.length; i++) {
991
+ node = ast.nodes[i];
992
+ let comments = DSL.comment.getFrontComments(this.comments, node.tokenRange[0]);
993
+ this.visitComments(comments, level);
994
+ let param = _snakeCase(_escape(_name(node.fieldName)));
995
+ const description = this.getAttributes(node, 'description');
996
+ if (description) {
997
+ const descriptions = description.trimEnd().split('\n');
998
+ for (let j = 0; j < descriptions.length; j++) {
999
+ this.emit(`# ${descriptions[j]}\n`, level + 2);
1000
+ }
1001
+ }
1002
+ this.emit(`self.${param} = ${param}\n`, level + 2);
1003
+ }
1004
+ this.emit('\n');
1005
+ // validate
1006
+ this.emit('def validate(self):\n', level);
1007
+ if(ast.nodes.length > 0) {
1008
+ this.visitModelValidate(ast, level);
1009
+ } else {
1010
+ this.emit('pass\n', level + 2);
1011
+ }
1012
+
1013
+ this.emit('\n');
1014
+
1015
+ // to_map
1016
+ this.visitToMap(ast, level);
1017
+
1018
+
1019
+ // from_map
1020
+ this.visitFromMap(ast, modelName, level);
1021
+
1022
+ if (node) {
1023
+ //find the last node's back comment
1024
+ let comments = DSL.comment.getBetweenComments(this.comments, node.tokenRange[0], ast.tokenRange[1]);
1025
+ this.visitComments(comments, level);
1026
+ }
1027
+
1028
+ if (ast.nodes.length === 0) {
1029
+ //empty block's comment
1030
+ let comments = DSL.comment.getBetweenComments(this.comments, ast.tokenRange[0], ast.tokenRange[1]);
1031
+ this.visitComments(comments, level);
1032
+ }
1033
+
1034
+ }
1035
+
1036
+ visitModelValidate(ast, level) {
1037
+ let notPass = false;
1038
+ for (let i = 0; i < ast.nodes.length; i++) {
1039
+ const node = ast.nodes[i];
1040
+ const pattern = this.getAttributes(node, 'pattern') || '';
1041
+ const maxLength = this.getAttributes(node, 'maxLength') || 0;
1042
+ const minLength = this.getAttributes(node, 'minLength') || 0;
1043
+ const maximum = this.getAttributes(node, 'maximum') || 0;
1044
+ const minimum = this.getAttributes(node, 'minimum') || 0;
1045
+ let comments = DSL.comment.getFrontComments(this.comments, node.tokenRange[0]);
1046
+ this.visitComments(comments, level);
1047
+ let param = _snakeCase(_escape(_name(node.fieldName)));
1048
+ // 这里判断类中属性是否是必填
1049
+ if (node.required) {
1050
+ notPass = true;
1051
+ this.emit(`self.validate_required(self.${param}, '${param}')\n`, level + 2);
1052
+ }
1053
+ // 这里判断类中属性的结构
1054
+ if(node.fieldValue.fieldType === 'array' && node.fieldValue.fieldItemType.type !== 'map' && node.fieldValue.fieldItemType.lexeme !== 'string') {
1055
+ // 最底下是string的就不需要validate
1056
+ if(this.checkFieldItemTypeAllString(node.fieldValue)){
1057
+ continue;
1058
+ }
1059
+ notPass = true;
1060
+ this.emit(`if self.${param}:\n`, level + 2);
1061
+ this.emit(`for k in self.${param}:\n`, level + 4);
1062
+ let baseLevel = level + 6;
1063
+ // 二层数组
1064
+ if(node.fieldValue.fieldItemType && node.fieldValue.fieldItemType.fieldType === 'array' || node.fieldValue.fieldItemType.fieldType === 'string') {
1065
+ this.emit('for k1 in k:\n', baseLevel);
1066
+ this.emit('if k1:\n', baseLevel += 2);
1067
+ this.emit('k1.validate()\n', baseLevel += 2);
1068
+ } else {
1069
+ this.emit('if k:\n', baseLevel);
1070
+ this.emit('k.validate()\n', baseLevel + 2);
1071
+ }
1072
+ } else if(node.fieldValue.fieldType === 'map' && node.fieldValue.valueType.lexeme !== 'string') {
1073
+ // TODO: 这里为array的时候不做validate
1074
+ // $dara.Model.validateMap
1075
+ if(this.checkFieldItemTypeAllString(node.fieldValue)){
1076
+ continue;
1077
+ }
1078
+ notPass = true;
1079
+ this.emit(`if self.${param}:\n`, level + 2);
1080
+ this.emit(`for v in self.${param}.values():\n`, level + 4);
1081
+ let baseLevel = level + 6;
1082
+ // 二层map 或 array 特殊操作
1083
+ if(node.fieldValue.fieldItemType && node.fieldValue.fieldItemType.fieldType === 'array') {
1084
+ this.emit('for v1 in k:\n', baseLevel);
1085
+ this.emit('if v1:\n', baseLevel += 2);
1086
+ this.emit('v1.validate()\n', baseLevel += 2);
1087
+ } else if(node.fieldValue.valueType.type === 'array'){
1088
+ this.emit('for k1 in v:\n', baseLevel);
1089
+ this.emit('if k1:\n', baseLevel += 2);
1090
+ this.emit('k1.validate()\n', baseLevel += 2);
1091
+ } else {
1092
+ this.emit('if v:\n', baseLevel);
1093
+ this.emit('v.validate()\n', baseLevel + 2);
1094
+ }
1095
+ } else if(node.fieldValue.fieldType && node.fieldValue.fieldType.idType === 'model' || node.fieldValue.type === 'modelBody'){
1096
+ notPass = true;
1097
+ this.emit(`if self.${param}:\n`, level + 2);
1098
+ this.emit(`self.${param}.validate()\n`, level + 4);
1099
+ } else if(pattern !== ''){
1100
+ notPass = true;
1101
+ this.emit(`if self.${param} is not None:\n`, level + 2);
1102
+ this.emit(`self.validate_pattern(self.${param}, '${param}', '${pattern}')\n`, level + 4);
1103
+ } else if(maxLength > 0 && maxLength <= 2147483647){
1104
+ notPass = true;
1105
+ this.emit(`if self.${param} is not None:\n`, level + 2);
1106
+ this.emit(`self.validate_max_length(self.${param}, '${param}', ${maxLength})\n`, level + 4);
1107
+ } else if(minLength > 0 && minLength <= 2147483647){
1108
+ notPass = true;
1109
+ this.emit(`if self.${param} is not None:\n`, level + 2);
1110
+ this.emit(`self.validate_min_length(self.${param}, '${param}', ${minLength})\n`, level + 4);
1111
+ } else if(maximum > 0 && maximum <= Number.MAX_SAFE_INTEGER){
1112
+ notPass = true;
1113
+ this.emit(`if self.${param} is not None:\n`, level + 2);
1114
+ this.emit(`self.validate_maximum(self.${param}, '${param}', ${maximum})\n`, level + 4);
1115
+ } else if(minimum > 0 && minimum <= Number.MAX_SAFE_INTEGER){
1116
+ notPass = true;
1117
+ this.emit(`if self.${param} is not None:\n`, level + 2);
1118
+ this.emit(`self.validate_minimum(self.${param}, '${param}', ${minimum})\n`, level + 4);
1119
+ }
1120
+ }
1121
+
1122
+ if(!notPass) {
1123
+ this.emit('pass\n', level + 2);
1124
+ }
1125
+ }
1126
+
1127
+ visitToMapField(fieldValue, key, value, level) {
1128
+ const deep = Math.floor(level / 4);
1129
+ if (fieldValue.type === 'modelBody' || fieldValue.type === 'moduleModel' ||
1130
+ fieldValue.type === 'subModel' || fieldValue.idType === 'model' ||
1131
+ (fieldValue.fieldType && (fieldValue.fieldType.type === 'moduleModel' ||
1132
+ fieldValue.fieldType.idType === 'model' || fieldValue.fieldType.idType === 'builtin_model'))) {
1133
+ this.emit(`${key} = ${value}.to_map()`, level);
1134
+ if(deep > 1) {
1135
+ this.emit(` if ${value} else None\n`);
1136
+ }
1137
+ this.emit('\n');
1138
+ } else if (fieldValue.type === 'array' || fieldValue.fieldType === 'array') {
1139
+ this.emit(`l${deep} = 0\n`, level);
1140
+ this.emit(`${key} = []\n`, level);
1141
+ this.emit(`for k${deep} in ${value}:\n`, level);
1142
+ this.emit(`l${deep} += 1\n`, level + 2);
1143
+ this.visitToMapField(fieldValue.fieldItemType || fieldValue.subType, `${key}[l${deep}]`, `k${deep}`, level + 2);
1144
+ } else if (fieldValue.fieldType === 'map' || fieldValue.type === 'map') {
1145
+ this.emit(`${key} = {}\n`, level);
1146
+ this.emit(`for k${deep}, v${deep} in k.items():\n`, level);
1147
+ this.visitToMapField(fieldValue.valueType, `${key}[k${deep}]`, `v${deep}`, level + 2);
1148
+ } else {
1149
+ this.emit(`${key} = ${value}\n`, level);
1150
+ }
1151
+
1152
+ }
1153
+
1154
+ visitToMap(ast, level) {
1155
+ this.emit('def to_map(self):\n', level);
1156
+ this.emit(` _map = super().to_map()
1157
+ if _map is not None:
1158
+ return _map
1159
+
1160
+ result = dict()\n`);
1161
+ for (let i = 0; i < ast.nodes.length; i++) {
1162
+ const node = ast.nodes[i];
1163
+ let realName = this.getRealName(node);
1164
+ let comments = DSL.comment.getFrontComments(this.comments, node.tokenRange[0]);
1165
+ this.visitComments(comments, level);
1166
+ let param = _snakeCase(_escape(_name(node.fieldName)));
1167
+ this.emit(`if self.${param} is not None:\n`, level + 2);
1168
+ if(!this.checkFieldHasModel(node.fieldValue)) {
1169
+ this.emit(`result['${realName}'] = self.${param}`, level + 4);
1170
+ } else {
1171
+ this.visitToMapField(node.fieldValue, `result['${realName}']`, `self.${param}`, level + 4);
1172
+ }
1173
+ this.emit('\n');
1174
+ }
1175
+ this.emit('return result\n', level + 2);
1176
+ this.emit('\n');
1177
+ }
1178
+
1179
+ visitFromField(fieldValue, fieldName, key, value, level) {
1180
+ const deep = Math.floor(level / 4);
1181
+ if (fieldValue.type === 'modelBody') {
1182
+ const subModelName = _subModelName(fieldName);
1183
+ this.emit(`temp_model = ${subModelName}\n`, level);
1184
+ this.emit(`${key} = temp_model.from_map(${value})\n`, level);
1185
+ } else if (fieldValue.type === 'array' || fieldValue.fieldType === 'array') {
1186
+ this.emit(`l${deep} = 0\n`, level);
1187
+ this.emit(`${key} = []\n`, level);
1188
+ this.emit(`for k${deep} in ${value}:\n`, level);
1189
+ this.emit(`l${deep} += 1\n`, level + 2);
1190
+ this.visitFromField(fieldValue.fieldItemType || fieldValue.subType, fieldName, `${key}[l${deep}]`, `k${deep}`, level + 2);
1191
+ } else if (fieldValue.fieldType === 'map' || fieldValue.type === 'map') {
1192
+ this.emit(`${key} = {}\n`, level);
1193
+ this.emit(`for k${deep}, v${deep} in ${value}.items():\n`, level);
1194
+ this.visitFromField(fieldValue.valueType, fieldName, `${key}[k${deep}]`, `v${deep}`, level + 2);
1195
+ } else if (fieldValue.type === 'moduleModel' ||
1196
+ (fieldValue.fieldType && fieldValue.fieldType.type === 'moduleModel')) {
1197
+ const [moduleId, ...rest] = fieldValue.path || fieldValue.fieldType.path;
1198
+ const modelName = _subModelName(rest.map((item) => {
1199
+ return item.lexeme;
1200
+ }).join('.'));
1201
+ this.emit(`${key} = ${this.getModelName(modelName, _name(moduleId), 'module')}.from_map(${value})\n`, level);
1202
+ } else if (fieldValue.type === 'subModel') {
1203
+ const [moduleId, ...rest] = fieldValue.path;
1204
+ const subModelName = _subModelName([moduleId.lexeme, ...rest.map((item) => {
1205
+ return item.lexeme;
1206
+ })].join('.'));
1207
+ this.emit(`${key} = ${subModelName}.from_map(${value})\n`, level);
1208
+ } else if (fieldValue.idType === 'model') {
1209
+ const modelName = _type(_name(fieldValue));
1210
+ this.emit(`${key} = ${modelName}.from_map(${value})\n`, level);
1211
+ } else if (fieldValue.fieldType && fieldValue.fieldType.idType === 'model') {
1212
+ const modelName = _type(_name(fieldValue.fieldType));
1213
+ this.emit(`${key} = ${modelName}.from_map(${value})\n`, level);
1214
+ } else if (fieldValue.fieldType && fieldValue.fieldType.idType === 'builtin_model') {
1215
+ const typeName = _type(_name(fieldValue.fieldType));
1216
+ this.pushImports(typeName);
1217
+ this.emit(`${key} = ${typeName}.from_map(${value})\n`, level);
1218
+ } else {
1219
+ this.emit(`${key} = ${value}\n`, level);
1220
+ }
1221
+ }
1222
+
1223
+ visitFromMap(ast, modelName, level) {
1224
+ //
1225
+ this.emit('def from_map(self, m: dict = None):\n', level);
1226
+ this.emit('m = m or dict()\n', level + 2);
1227
+ for (let i = 0; i < ast.nodes.length; i++) {
1228
+ const node = ast.nodes[i];
1229
+ let realName = this.getRealName(node);
1230
+ let comments = DSL.comment.getFrontComments(this.comments, node.tokenRange[0]);
1231
+ this.visitComments(comments, level);
1232
+ let param = _snakeCase(_escape(_name(node.fieldName)));
1233
+ this.emit(`if m.get('${realName}') is not None:\n`, level + 2);
1234
+ if(!this.checkFieldHasModel(node.fieldValue)) {
1235
+ this.emit(`self.${param} = m.get('${realName}')`, level + 4);
1236
+ } else {
1237
+ this.visitFromField(node.fieldValue, [modelName, param].join('.'), `self.${param}`, `m.get('${realName}')`, level + 4);
1238
+ }
1239
+ this.emit('\n');
1240
+ }
1241
+ this.emit('return self\n', level + 2);
1242
+ this.emit('\n');
1243
+ }
1244
+
1245
+ getAttributes(ast, name){
1246
+ const attr = ast.attrs.find((item) => {
1247
+ return item.attrName.lexeme === name;
1248
+ });
1249
+ if(!attr) {
1250
+ return;
1251
+ }
1252
+ return attr.attrValue.string || attr.attrValue.lexeme || attr.attrValue.value;
1253
+ }
1254
+
1255
+ visitFieldValidate(value, level, name) {
1256
+ if (value.type === 'array' || value.fieldType === 'array') {
1257
+ this.emit(`if(Array.isArray(${name})) {\n`, level);
1258
+ this.emit(`$dara.Model.validateArray(${name})\n`, level + 1);
1259
+ this.emit('}\n', level);
1260
+ } else if (value.fieldType === 'map' || value.type === 'map') {
1261
+ this.emit(`if(${name}) {\n`, level);
1262
+ this.emit(`$dara.Model.validateMap(${name})\n`, level + 1);
1263
+ this.emit('}\n', level);
1264
+ } else if (value.type === 'moduleModel' || value.type === 'modelBody'
1265
+ || value.type === 'subModel' || value.fieldType.type === 'moduleModel'
1266
+ || value.fieldType.idType === 'model' || value.fieldType.idType === 'module') {
1267
+ this.emit(`if(${name} && typeof (${name} as any).validate === 'function') {\n`, level);
1268
+ this.emit(`(${name} as any).validate()\n`, level + 1);
1269
+ this.emit('}\n', level);
1270
+ }
1271
+ }
1272
+
1273
+ extendBaseErr(extendOn){
1274
+ if (!extendOn) {
1275
+ return true;
1276
+ }
1277
+ if(_name(extendOn) === '$Error') {
1278
+ return true;
1279
+ }
1280
+
1281
+ return false;
1282
+ }
1283
+
1284
+ visitExtendOn(extendOn, type = 'model') {
1285
+ if (!extendOn) {
1286
+ type === 'model' ? this.pushImports(`${CORE}Model`) : this.pushImports(`${CORE}Exception`);
1287
+ return type === 'model' ? this.emit(`(${CORE}Model)`) : this.emit(`(${CORE}Exception)`);
1288
+ }
1289
+
1290
+ switch(_name(extendOn)) {
1291
+ case '$Error':
1292
+ this.pushImports(`${CORE}Exception`);
1293
+ this.emit(`(${CORE}Exception)`);
1294
+ return;
1295
+ case '$ResponseError':
1296
+ this.pushImports('ResponseException');
1297
+ this.emit('(ResponseException)');
1298
+ return;
1299
+ case '$Model':
1300
+ this.pushImports(`${CORE}Model`);
1301
+ this.emit(`(${CORE}Model)`);
1302
+ return;
1303
+ }
1304
+
1305
+ let needBaseException = false;
1306
+
1307
+ if (extendOn.type === 'moduleModel') {
1308
+ const [moduleId, ...rest] = extendOn.path;
1309
+ const moduleName = _name(moduleId);
1310
+ const modelName = _subModelName(rest.map((item) => {
1311
+ return item.lexeme;
1312
+ }).join('.'));
1313
+
1314
+ const externModel = this.usedExternModel.get(moduleName);
1315
+ if (externModel && externModel.has(modelName) && type === 'exception') {
1316
+ needBaseException = true;
1317
+ }
1318
+
1319
+ this.emit(`(${this.getModelName(modelName, moduleName, type)}`);
1320
+ } else if (extendOn.type === 'subModel') {
1321
+ const [moduleId, ...rest] = extendOn.path;
1322
+ if (type === 'exception') {
1323
+ needBaseException = true;
1324
+ const modelPkgName = path.basename(this.modelPath, '.py');
1325
+ this.imports.push({
1326
+ className: modelPkgName,
1327
+ });
1328
+ this.emit(`${modelPkgName}.`);
1329
+ }
1330
+ this.emit(`(${_subModelName([moduleId.lexeme, ...rest.map((item) => {
1331
+ return item.lexeme;
1332
+ })].join('.'))}`);
1333
+ } else {
1334
+ let modelName = _upperFirst(_name(extendOn));
1335
+ this.emit('(');
1336
+ if(extendOn.moduleName){
1337
+ this.getModelName(_upperFirst(_name(extendOn)), extendOn.moduleName, type);
1338
+ } else if (this.predefined[modelName] && this.predefined[modelName].isException && type === 'model') {
1339
+ const exPkgName = path.basename(this.exceptionPath, '.py');
1340
+ this.imports.push({
1341
+ className: exPkgName,
1342
+ });
1343
+ this.emit(`${exPkgName}.`);
1344
+ } else if (this.predefined[modelName] && !this.predefined[modelName].isException && type === 'exception') {
1345
+ needBaseException = true;
1346
+ const modelPkgName = path.basename(this.modelPath, '.py');
1347
+ this.imports.push({
1348
+ className: modelPkgName,
1349
+ });
1350
+ this.emit(`${modelPkgName}.`);
1351
+ }
1352
+ this.emit(`${modelName}`);
1353
+ if(type === 'exception' && !needBaseException) {
1354
+ this.emit('Exception');
1355
+ }
1356
+ }
1357
+ if(needBaseException) {
1358
+ this.emit(`, ${CORE}Exception`);
1359
+ }
1360
+ this.emit(')');
1361
+ }
1362
+
1363
+ dealExtendFileds(ast) {
1364
+ const fileds = [];
1365
+ for (let i = 0; i < ast.nodes.length; i++) {
1366
+ const node = ast.nodes[i];
1367
+ const fieldName = _name(node.fieldName);
1368
+ fileds.push(fieldName);
1369
+ }
1370
+ const extendFileds = [];
1371
+ for (let i = 0; i < ast.extendFileds.length; i++) {
1372
+ const node = ast.extendFileds[i];
1373
+ node.extend = true;
1374
+ const fieldName = _name(node.fieldName);
1375
+ if(fileds.includes(fieldName)) {
1376
+ continue;
1377
+ }
1378
+ extendFileds.push(node);
1379
+
1380
+ }
1381
+ return extendFileds.concat(ast.nodes);
1382
+ }
1383
+
1384
+ visitModel(modelBody, modelName, extendOn, level) {
1385
+ // const modelDir = path.join(path.dirname(filepath), this.modelDir);
1386
+ this.emit(`class ${modelName}`, level);
1387
+ this.visitExtendOn(extendOn);
1388
+ this.emit(':\n');
1389
+ this.visitModelBody(modelBody, level + 2, modelName);
1390
+ }
1391
+
1392
+ eachModel(ast, level) {
1393
+ assert.equal(ast.type, 'model');
1394
+ const modelName = _upperFirst(_name(ast.modelName));
1395
+ this.visitAnnotation(ast.annotation, level);
1396
+ let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
1397
+ this.visitComments(comments, level);
1398
+ this.visitModel(ast.modelBody, modelName, ast.extendOn, level);
1399
+ }
1400
+
1401
+ visitFieldsInit(ast, level, modelName, type = 'model', baseErr = false){
1402
+ let node;
1403
+ this.emit(' def __init__(');
1404
+ const paramNodes = this.dealExtendFileds(ast);
1405
+ if (!paramNodes.length) {
1406
+ this.emit('self):\n');
1407
+ this.emit('pass', level + 2);
1408
+ return;
1409
+ }
1410
+ this.emit('\n');
1411
+ this.emit('self, \n', level + 2);
1412
+ for (let i = 0; i < paramNodes.length; i++) {
1413
+ node = paramNodes[i];
1414
+ if(!node.extend) {
1415
+ let comments = DSL.comment.getFrontComments(this.comments, node.tokenRange[0]);
1416
+ this.visitComments(comments, level);
1417
+ }
1418
+ let param = _snakeCase(_escape(_name(node.fieldName)));
1419
+ if(param === 'name' && type === 'exception') {
1420
+ continue;
1421
+ }
1422
+ this.emit(`${param}: `, level + 2);
1423
+ this.visitFieldType(node.fieldValue, level, modelName, _name(node.fieldName));
1424
+ this.emit(' = None,\n');
1425
+ }
1426
+ this.emit('):\n', level);
1427
+
1428
+ if(ast.extendFileds && ast.extendFileds.length > 0) {
1429
+ this.emit('super().__init__(', level + 2);
1430
+ if(baseErr) {
1431
+ this.emit('{\n');
1432
+ for (let i = 0; i < ast.extendFileds.length; i++) {
1433
+ node = ast.extendFileds[i];
1434
+ let value = _snakeCase(_escape(_name(node.fieldName)));
1435
+ let key = _escape(_name(node.fieldName));
1436
+ if(key === 'name' && type === 'exception') {
1437
+ continue;
1438
+ }
1439
+ this.emit(`'${key}': ${value},\n`, level + 4);
1440
+ }
1441
+ this.emit('})\n', level + 2);
1442
+ } else {
1443
+ this.emit('\n');
1444
+ for (let i = 0; i < ast.extendFileds.length; i++) {
1445
+ node = ast.extendFileds[i];
1446
+ let param = _snakeCase(_escape(_name(node.fieldName)));
1447
+ if(param === 'name' && type === 'exception') {
1448
+ continue;
1449
+ }
1450
+ this.emit(`${param} = ${param},\n`, level + 4);
1451
+ }
1452
+ this.emit(')\n', level + 2);
1453
+ }
1454
+ }
1455
+ }
1456
+
1457
+ visitEcxceptionBody(ast, extendOn, exceptionName, level) {
1458
+ assert.equal(ast.type, 'exceptionBody');
1459
+ this.visitFieldsInit(ast, level, exceptionName, 'exception', this.extendBaseErr(extendOn));
1460
+ let node;
1461
+
1462
+ this.emit(`self.name = '${exceptionName}Exception'\n`, level + 2);
1463
+ for (let i = 0; i < ast.nodes.length; i++) {
1464
+ node = ast.nodes[i];
1465
+ let comments = DSL.comment.getFrontComments(this.comments, node.tokenRange[0]);
1466
+ this.visitComments(comments, level);
1467
+ let param = _snakeCase(_escape(_name(node.fieldName)));
1468
+ if(param === 'name') {
1469
+ continue;
1470
+ }
1471
+ this.emit(`self.${param} = ${param}\n`, level + 2);
1472
+ }
1473
+ this.emit('\n');
1474
+ if (node) {
1475
+ //find the last node's back comment
1476
+ let comments = DSL.comment.getBetweenComments(this.comments, node.tokenRange[0], ast.tokenRange[1]);
1477
+ this.visitComments(comments, level);
1478
+ }
1479
+
1480
+ if (ast.nodes.length === 0) {
1481
+ //empty block's comment
1482
+ let comments = DSL.comment.getBetweenComments(this.comments, ast.tokenRange[0], ast.tokenRange[1]);
1483
+ this.visitComments(comments, level);
1484
+ }
1485
+ }
1486
+
1487
+ visitException(exceptionBody, exceptionName, extendOn, level) {
1488
+ this.emit(`class ${exceptionName}Exception`, level);
1489
+ this.visitExtendOn(extendOn, 'exception');
1490
+ this.emit(':\n');
1491
+ this.visitEcxceptionBody(exceptionBody, extendOn, exceptionName, level + 2);
1492
+ }
1493
+
1494
+ eachException(ast, level) {
1495
+ assert.equal(ast.type, 'exception');
1496
+ const exceptionName = _upperFirst(_name(ast.exceptionName));
1497
+ this.visitAnnotation(ast.annotation, level);
1498
+ let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
1499
+ this.visitComments(comments, level);
1500
+ this.visitException(ast.exceptionBody, exceptionName, ast.extendOn, level);
1501
+ }
1502
+
1503
+ eachSubModel(ast, level) {
1504
+ assert.equal(ast.type, 'model');
1505
+ const modelName = _subModelName(_name(ast.modelName));
1506
+ this.visitModel(ast.modelBody, modelName, ast.extendOn, level);
1507
+ }
1508
+
1509
+ visitObjectFieldValue(ast, level) {
1510
+ this.visitExpr(ast, level);
1511
+ }
1512
+
1513
+ visitObjectField(ast, level, end) {
1514
+ let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
1515
+ this.visitComments(comments, level);
1516
+ if (ast.type === 'objectField') {
1517
+ // TODO 这里粗暴处理的双引号,可以考虑优化
1518
+ var key = _escape(_name(ast.fieldName) || _string(ast.fieldName)).replace(/['"]/g, '');
1519
+ this.emit(`'${key}': `, level + 2);
1520
+ this.visitObjectFieldValue(ast.expr, level + 2);
1521
+ if (!end) {
1522
+ this.emit(',\n');
1523
+ } else {
1524
+ this.emit('\n');
1525
+ }
1526
+ } else if (ast.type !== 'expandField'){
1527
+ throw new Error('unimpelemented');
1528
+ }
1529
+ }
1530
+
1531
+ visitModelField(ast, level, end) {
1532
+ let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
1533
+ this.visitComments(comments, level);
1534
+ if (ast.type === 'objectField') {
1535
+ // TODO 这里粗暴处理的双引号,可以考虑优化
1536
+ var key = _escape(_name(ast.fieldName) || _string(ast.fieldName)).replace(/['"]/g, '');
1537
+ this.emit(`${_snakeCase(key)} = `, level + 2);
1538
+ this.visitObjectFieldValue(ast.expr, level + 2);
1539
+ if (!end) {
1540
+ this.emit(',\n');
1541
+ } else {
1542
+ this.emit('\n');
1543
+ }
1544
+ } else if (ast.type !== 'expandField'){
1545
+ throw new Error('unimpelemented');
1546
+ }
1547
+ }
1548
+
1549
+ visitObject(ast, level) {
1550
+ assert.equal(ast.type, 'object');
1551
+ if (ast.fields.length === 0) {
1552
+ this.emit('{');
1553
+ let comments = DSL.comment.getBetweenComments(this.comments, ast.tokenRange[0], ast.tokenRange[1]);
1554
+ if (comments.length > 0) {
1555
+ this.emit('\n');
1556
+ this.visitComments(comments, level + 2);
1557
+ this.emit('', level);
1558
+ }
1559
+ this.emit('}');
1560
+ } else {
1561
+ var expandFields = [];
1562
+ for (var i = 0; i < ast.fields.length; i++) {
1563
+ if (ast.fields[i].type !== 'expandField') {
1564
+ continue;
1565
+ }
1566
+ expandFields.push(ast.fields[i]);
1567
+ }
1568
+ if (expandFields.length !== 0){
1569
+ this.pushImports(`${CORE}Core`);
1570
+ this.emit(`${CORE}Core.merge({`);
1571
+ if(ast.fields.length !== expandFields.length) {
1572
+ this.emit('\n');
1573
+ }
1574
+ } else {
1575
+ this.emit('{\n');
1576
+ }
1577
+ for (i = 0; i < ast.fields.length; i++) {
1578
+ this.visitObjectField(ast.fields[i], level, i === ast.fields.length - 1);
1579
+ }
1580
+
1581
+ if (expandFields.length !== 0) {
1582
+ if(ast.fields.length !== expandFields.length) {
1583
+ this.emit('', level);
1584
+ }
1585
+ this.emit('}, ');
1586
+ this.visitExpr(expandFields[0].expr);
1587
+ expandFields.slice(1).forEach((item) => {
1588
+ this.emit(', ');
1589
+ this.visitExpr(item.expr);
1590
+ });
1591
+ this.emit(')');
1592
+ } else {
1593
+ this.emit('}', level);
1594
+ }
1595
+
1596
+ let comments = DSL.comment.getBetweenComments(this.comments, ast.fields[i - 1].tokenRange[0], ast.tokenRange[1]);
1597
+ this.visitComments(comments, level + 1);
1598
+ }
1599
+ }
1600
+
1601
+ visitMethodCall(ast, level) {
1602
+ assert.equal(ast.left.type, 'method_call');
1603
+ const name = _name(ast.left.id);
1604
+ const functionName = _snakeCase(name);
1605
+ if (name.startsWith('$') && this.builtin[name]) {
1606
+ const method = name.replace('$', '');
1607
+ this.builtin[name][method](ast, level, ast.isAsync && this.isAsyncFunction);
1608
+ return;
1609
+ } else if(this.isStaticFunction === false && this.isAsyncFunction && ast.isAsync){
1610
+ this.emit(`await self.${functionName}_async`);
1611
+ } else if(this.isStaticFunction === false) {
1612
+ this.emit(`self.${functionName}`);
1613
+ } else if(ast.isAsync && this.isAsyncFunction) {
1614
+ this.emit(`await ${this.className}.${functionName}_async`);
1615
+ } else {
1616
+ const functionName = _snakeCase(name);
1617
+ this.emit(`${this.className}.${functionName}`);
1618
+ }
1619
+ this.visitArgs(ast.args, level);
1620
+ }
1621
+
1622
+
1623
+ visitInstanceCall(ast, level) {
1624
+ assert.equal(ast.left.type, 'instance_call');
1625
+ const method = _name(ast.left.propertyPath[0]);
1626
+ const async = ast.isAsync && this.isAsyncFunction;
1627
+ if (async) {
1628
+ this.emit('await ');
1629
+ }
1630
+ if (ast.builtinModule && this.builtin[ast.builtinModule] && this.builtin[ast.builtinModule][method]) {
1631
+ this.builtin[ast.builtinModule][method](ast, level, async);
1632
+ } else {
1633
+ if (ast.left.id.tag === DSL.Tag.Tag.VID) {
1634
+ this.emit(`self.${_snakeCase(_vid(ast.left.id))}`);
1635
+ } else {
1636
+ const aliasId = _snakeCase(_name(ast.left.id));
1637
+ this.emit(aliasId);
1638
+ }
1639
+ this.emit(`.${(_snakeCase(method))}`);
1640
+ if(async) {
1641
+ this.emit('_async');
1642
+ }
1643
+ this.visitArgs(ast.args, level);
1644
+ }
1645
+ }
1646
+
1647
+ visitStaticCall(ast, level) {
1648
+ assert.equal(ast.left.type, 'static_call');
1649
+ if (ast.left.id.type === 'builtin_module') {
1650
+ this.visitBuiltinStaticCall(ast, level);
1651
+ return;
1652
+ }
1653
+
1654
+
1655
+ const aliasId = _name(ast.left.id);
1656
+ let clientName = this.getModelName('', aliasId, 'module');
1657
+
1658
+ const functionName = _snakeCase(_name(ast.left.propertyPath[0]));
1659
+
1660
+ if (ast.isAsync && this.isAsyncFunction) {
1661
+ this.emit(`await ${clientName}.${functionName}_async`);
1662
+ } else {
1663
+ this.emit(`${clientName}.${functionName}`);
1664
+ }
1665
+ this.visitArgs(ast.args, level);
1666
+ }
1667
+
1668
+ visitBuiltinStaticCall(ast, level) {
1669
+ const moduleName = _name(ast.left.id);
1670
+
1671
+ const builtiner = this.builtin[moduleName];
1672
+ if (!builtiner) {
1673
+ throw new Error('un-implemented');
1674
+ }
1675
+ const func = _name(ast.left.propertyPath[0]);
1676
+ builtiner[func](ast, level, ast.isAsync && this.isAsyncFunction);
1677
+ }
1678
+
1679
+ visitCall(ast, level) {
1680
+ // TODO 这块目前都进了method_call 下面两个分支不知道有没有用
1681
+ assert.equal(ast.type, 'call');
1682
+ if (ast.left.type === 'method_call') {
1683
+ this.visitMethodCall(ast, level);
1684
+ } else if (ast.left.type === 'instance_call') {
1685
+ this.visitInstanceCall(ast, level);
1686
+ } else if (ast.left.type === 'static_call') {
1687
+ this.visitStaticCall(ast, level);
1688
+ } else {
1689
+ throw new Error('un-implemented');
1690
+ }
1691
+ }
1692
+
1693
+ visitConstruct(ast, level) {
1694
+ assert.equal(ast.type, 'construct');
1695
+ const aliasId = _name(ast.aliasId);
1696
+
1697
+ if(this.builtin[aliasId]) {
1698
+ const type = _type(aliasId);
1699
+ this.pushImports(type);
1700
+ this.emit(type);
1701
+ } else {
1702
+ this.emit(this.getModelName('', aliasId, 'module'));
1703
+ }
1704
+
1705
+ this.visitArgs(ast.args, level);
1706
+ }
1707
+
1708
+
1709
+ visitSuper(ast, level) {
1710
+ assert.equal(ast.type, 'super');
1711
+ this.emit('super().__init__');
1712
+ this.visitArgs(ast.args, level);
1713
+ }
1714
+
1715
+ visitArgs(args, level) {
1716
+ this.emit('(');
1717
+ for (let i = 0; i < args.length; i++) {
1718
+ const expr = args[i];
1719
+ if (expr.needCast) {
1720
+ this.emit(`${CORE}Core.to_map(`);
1721
+ this.visitExpr(expr, level);
1722
+ this.emit(')');
1723
+ } else {
1724
+ this.visitExpr(expr, level);
1725
+ }
1726
+ if (i !== args.length - 1) {
1727
+ this.emit(', ');
1728
+ }
1729
+ }
1730
+ this.emit(')');
1731
+ }
1732
+
1733
+ visitPropertyAccess(ast, env = {}) {
1734
+ assert.ok(ast.type === 'property_access' || ast.type === 'property');
1735
+ var id = _snakeCase(_name(ast.id));
1736
+ if (ast.id.tag === Tag.VID) {
1737
+ id = `self.${_snakeCase(_vid(ast.id))}`;
1738
+ }
1739
+ var expr = avoidReserveName(id);
1740
+ const prefix = env.left ? '[' : '.get(';
1741
+ const suffix = env.left ? ']' : ')';
1742
+ var current = ast.id.inferred;
1743
+
1744
+ for (var i = 0; i < ast.propertyPath.length; i++) {
1745
+ var name = _name(ast.propertyPath[i]);
1746
+ if (current.type === 'model') {
1747
+ expr += `.${_snakeCase(name)}`;
1748
+ } else {
1749
+ expr += `${prefix}"${name}"${suffix}`;
1750
+ }
1751
+ current = ast.propertyPathTypes[i];
1752
+ }
1753
+ this.emit(expr);
1754
+ }
1755
+
1756
+ visitExpr(ast, level, env) {
1757
+ if (ast.type === 'boolean') {
1758
+ this.emit(_upperFirst(`${ast.value}`));
1759
+ } else if (ast.type === 'null') {
1760
+ this.emit('None');
1761
+ } else if (ast.type === 'property_access') {
1762
+ this.visitPropertyAccess(ast, env);
1763
+ } else if (ast.type === 'string') {
1764
+ this.emit(`'${(_string(ast.value))}'`);
1765
+ } else if (ast.type === 'number') {
1766
+ this.emit(ast.value.value);
1767
+ } else if (ast.type === 'object') {
1768
+ this.visitObject(ast, level);
1769
+ } else if (ast.type === 'variable') {
1770
+ if(ast.inferred && ast.inferred.type === 'basic' && ast.inferred.name === 'class') {
1771
+ this.emit(this.getModelName('', _name(ast.id), 'module'));
1772
+ } else {
1773
+ this.emit(avoidReserveName(_snakeCase(_name(ast.id))));
1774
+ }
1775
+ } else if (ast.type === 'virtualVariable') {
1776
+ this.emit(`self.${_snakeCase(_vid(ast.vid))}`);
1777
+ } else if (ast.type === 'decrement') {
1778
+ this.visitExpr(ast.expr, level, { left: true });
1779
+ this.emit('-= 1');
1780
+ } else if (ast.type === 'increment') {
1781
+ this.visitExpr(ast.expr, level, { left: true });
1782
+ this.emit('+= 1');
1783
+ } else if (ast.type === 'template_string') {
1784
+ const tmp = this.output;
1785
+ this.output = '';
1786
+ for (var i = 0; i < ast.elements.length; i++) {
1787
+ var item = ast.elements[i];
1788
+ if (item.type === 'element') {
1789
+ this.emit((item.value.string).replace(/{/g, '{{').replace(/}/g, '}}'));
1790
+ } else if (item.type === 'expr') {
1791
+ this.emit('{');
1792
+ this.visitExpr(item.expr, level);
1793
+ this.emit('}');
1794
+ } else {
1795
+ throw new Error('unimpelemented');
1796
+ }
1797
+ }
1798
+ const quote = _adaptedQuotes(this.output);
1799
+ this.output = tmp + `f${quote}${this.output}${quote}`;
1800
+ } else if (ast.type === 'call') {
1801
+ // 调用函数
1802
+ this.visitCall(ast, level);
1803
+ } else if (ast.type === 'construct') {
1804
+ this.visitConstruct(ast, level);
1805
+ } else if (ast.type === 'array') {
1806
+ this.visitArray(ast, level);
1807
+ } else if (ast.type === 'group') {
1808
+ this.emit('(');
1809
+ this.visitExpr(ast.expr, level, env);
1810
+ this.emit(')');
1811
+ } else if (_isBinaryOp(ast.type)) {
1812
+ this.visitExpr(ast.left, level, env);
1813
+ if (ast.type === 'or') {
1814
+ this.emit(' or ');
1815
+ } else if (ast.type === 'add') {
1816
+ this.emit(' + ');
1817
+ } else if (ast.type === 'subtract') {
1818
+ this.emit(' - ');
1819
+ } else if (ast.type === 'div') {
1820
+ this.emit(' / ');
1821
+ } else if (ast.type === 'multi') {
1822
+ this.emit(' * ');
1823
+ } else if (ast.type === 'and') {
1824
+ this.emit(' and ');
1825
+ // eslint-disable-next-line no-dupe-else-if
1826
+ } else if (ast.type === 'or') {
1827
+ this.emit(' or ');
1828
+ } else if (ast.type === 'lte') {
1829
+ this.emit(' <= ');
1830
+ } else if (ast.type === 'lt') {
1831
+ this.emit(' < ');
1832
+ } else if (ast.type === 'gte') {
1833
+ this.emit(' >= ');
1834
+ } else if (ast.type === 'gt') {
1835
+ this.emit(' > ');
1836
+ } else if (ast.type === 'neq') {
1837
+ this.emit(' != ');
1838
+ } else if (ast.type === 'eq') {
1839
+ this.emit(' == ');
1840
+ }
1841
+ this.visitExpr(ast.right, level, env);
1842
+ } else if (ast.type === 'not') {
1843
+ this.emit('not ',level);
1844
+ this.visitExpr(ast.expr, level, env);
1845
+ } else if (ast.type === 'construct_model') {
1846
+ // 生成实例的初始化赋值
1847
+ this.visitConstructModel(ast, level);
1848
+ } else if (ast.type === 'map_access') {
1849
+ this.visitMapAccess(ast, level, env);
1850
+ } else if (ast.type === 'array_access') {
1851
+ this.visitArrayAccess(ast);
1852
+ } else if (ast.type === 'super') {
1853
+ this.visitSuper(ast, level);
1854
+ } else {
1855
+ throw new Error('unimpelemented');
1856
+ }
1857
+ }
1858
+
1859
+ visitConstructModel(ast, level) {
1860
+ assert.equal(ast.type, 'construct_model');
1861
+ if (ast.aliasId.isModule) {
1862
+ // 这里做了粗糙改动 直接生成aliasId对应的models
1863
+ let type = 'model';
1864
+ let moduleName = _name(ast.aliasId);
1865
+ let modelName = _subModelName(ast.propertyPath.map((item) => {
1866
+ return item.lexeme;
1867
+ }).join('.'));
1868
+ const externEx = this.usedExternException.get(moduleName);
1869
+ if (externEx && externEx.has(modelName)) {
1870
+ type = 'exception';
1871
+ }
1872
+ this.emit(this.getModelName(modelName, moduleName, type));
1873
+ }
1874
+
1875
+ if (ast.aliasId.isModel) {
1876
+ let type = 'model';
1877
+ let mainModelName = _name(ast.aliasId);
1878
+ mainModelName = _subModelName([mainModelName, ...ast.propertyPath.map((item) => {
1879
+ return item.lexeme;
1880
+ })].join('.'));
1881
+
1882
+ if(mainModelName.startsWith('$') && _type(mainModelName)) {
1883
+ mainModelName = _type(mainModelName);
1884
+ this.pushImports(mainModelName);
1885
+ this.emit(mainModelName);
1886
+ } else {
1887
+ if (this.predefined[mainModelName] && this.predefined[mainModelName].isException) {
1888
+ type = 'exception';
1889
+ }
1890
+ this.emit(this.getModelName(mainModelName, '', type));
1891
+ }
1892
+ }
1893
+
1894
+ this.emit('(');
1895
+ if (ast.object && ast.object.fields.length !== 0) {
1896
+ // 判断是否有初始化赋值
1897
+ // this.visitObject(ast.object, level);
1898
+ this.emit('\n');
1899
+ for (var i = 0; i < ast.object.fields.length; i++) {
1900
+ this.visitModelField(ast.object.fields[i], level, i === ast.object.fields.length - 1);
1901
+ }
1902
+ this.emit(')', level);
1903
+ } else{
1904
+ this.emit(')');
1905
+ }
1906
+
1907
+ }
1908
+
1909
+ visitMapAccess(ast, level, env = {}) {
1910
+ assert.equal(ast.type, 'map_access');
1911
+ let expr;
1912
+ if (ast.id.tag === DSL.Tag.Tag.VID) {
1913
+ expr = `self.${_snakeCase(_vid(ast.id))}`;
1914
+ } else {
1915
+ expr = `${_snakeCase(_name(ast.id))}`;
1916
+ }
1917
+ const prefix = env.left ? '[' : '.get(';
1918
+ const suffix = env.left ? ']' : ')';
1919
+ if (ast.propertyPath && ast.propertyPath.length) {
1920
+ var current = ast.id.inferred;
1921
+ for (var i = 0; i < ast.propertyPath.length; i++) {
1922
+ var name = _name(ast.propertyPath[i]);
1923
+ if (current.type === 'model') {
1924
+ expr += `.${_snakeCase(name)}`;
1925
+ } else {
1926
+ expr += `${prefix}"${name}"${suffix}`;
1927
+ }
1928
+ current = ast.propertyPathTypes[i];
1929
+ }
1930
+ }
1931
+ this.emit(`${expr}${prefix}`);
1932
+ this.visitExpr(ast.accessKey, level);
1933
+ this.emit(suffix);
1934
+ }
1935
+
1936
+ visitArrayAccess(ast, level) {
1937
+ assert.equal(ast.type, 'array_access');
1938
+ let expr;
1939
+ if (ast.id.tag === DSL.Tag.Tag.VID) {
1940
+ // 这个判断很奇怪诶
1941
+ expr = `self.${_snakeCase(_vid(ast.id))}`;
1942
+ } else {
1943
+ expr = `${_snakeCase(_name(ast.id))}`;
1944
+ }
1945
+ if (ast.propertyPath && ast.propertyPath.length) {
1946
+ var current = ast.id.inferred;
1947
+ for (var i = 0; i < ast.propertyPath.length; i++) {
1948
+ var name = _name(ast.propertyPath[i]);
1949
+ if (current.type === 'model') {
1950
+ expr += `.${_snakeCase(name)}`;
1951
+ } else {
1952
+ expr += `["${name}"]`;
1953
+ }
1954
+ current = ast.propertyPathTypes[i];
1955
+ }
1956
+ }
1957
+ this.emit(`${expr}[`, level);
1958
+ this.visitExpr(ast.accessKey, level);
1959
+ this.emit(']');
1960
+ }
1961
+
1962
+ visitArray(ast, level) {
1963
+ assert.equal(ast.type, 'array');
1964
+ let arrayComments = DSL.comment.getBetweenComments(this.comments, ast.tokenRange[0], ast.tokenRange[1]);
1965
+ if (ast.items.length === 0) {
1966
+ this.emit('[ ');
1967
+ if (arrayComments.length > 0) {
1968
+ this.emit('\n');
1969
+ this.visitComments(arrayComments, level);
1970
+ this.emit('', level);
1971
+ }
1972
+ this.emit(']');
1973
+ return;
1974
+ }
1975
+
1976
+ this.emit('[\n');
1977
+ let item;
1978
+ for (let i = 0; i < ast.items.length; i++) {
1979
+ item = ast.items[i];
1980
+ let comments = DSL.comment.getFrontComments(this.comments, item.tokenRange[0]);
1981
+ this.visitComments(comments, level);
1982
+ this.emit('', level +2);
1983
+ this.visitExpr(item, level + 2);
1984
+ if (i < ast.items.length - 1) {
1985
+ this.emit(',');
1986
+ }
1987
+ this.emit('\n');
1988
+ }
1989
+ if (item) {
1990
+ //find the last item's back comment
1991
+ let comments = DSL.comment.getBetweenComments(this.comments, item.tokenRange[0], ast.tokenRange[1]);
1992
+ this.visitComments(comments, level);
1993
+ }
1994
+ this.emit(']', level);
1995
+ }
1996
+
1997
+ visitYield(ast, level) {
1998
+ assert.equal(ast.type, 'yield');
1999
+ this.emit('yield ', level);
2000
+ if (!ast.expr || ast.expr.type === 'null') {
2001
+ this.emit('\n');
2002
+ return;
2003
+ }
2004
+ this.emit(' ');
2005
+
2006
+ if (ast.needCast) {
2007
+ this.emit(`${CORE}Core.from_map(\n`);
2008
+ this.emit('', level + 2);
2009
+ this.visitType(ast.expectedType);
2010
+ this.emit('(),\n');
2011
+ this.emit('', level + 2);
2012
+ }
2013
+
2014
+ this.visitExpr(ast.expr, level);
2015
+
2016
+ if (ast.needCast) {
2017
+ this.emit(')');
2018
+ }
2019
+
2020
+ this.emit('\n');
2021
+ }
2022
+
2023
+ visitReturn(ast, level) {
2024
+ assert.equal(ast.type, 'return');
2025
+ this.emit('return', level);
2026
+ if (!ast.expr || ast.expr.type === 'null') {
2027
+ this.emit('\n');
2028
+ return;
2029
+ }
2030
+
2031
+ this.emit(' ');
2032
+
2033
+ if (ast.needCast) {
2034
+ this.emit(`${CORE}Core.from_map(\n`);
2035
+ this.emit('', level + 2);
2036
+ this.visitType(ast.expectedType);
2037
+ this.emit('(),\n');
2038
+ this.emit('', level + 2);
2039
+ }
2040
+
2041
+ this.visitExpr(ast.expr, level);
2042
+
2043
+ if (ast.needCast) {
2044
+ this.emit('\n');
2045
+ this.emit(')', level);
2046
+ }
2047
+
2048
+ this.emit('\n');
2049
+ }
2050
+
2051
+ visitRetry(ast, level) {
2052
+ assert.equal(ast.type, 'retry');
2053
+ this.pushImports(`${CORE}Exception`);
2054
+ this.emit(`raise ${CORE}Exception(${REQUEST}, ${RESPONSE})\n`, level);
2055
+ }
2056
+
2057
+ visitTry(ast, level) {
2058
+ assert.equal(ast.type, 'try');
2059
+ this.emit('try :\n', level);
2060
+ this.visitStmts(ast.tryBlock, level + 2);
2061
+ if (ast.catchBlocks && ast.catchBlocks.length > 0) {
2062
+ ast.catchBlocks.forEach(catchBlock => {
2063
+ if (!catchBlock.id) {
2064
+ return;
2065
+ }
2066
+ if (!catchBlock.id.type) {
2067
+ this.emit(`except Exception as ${_name(ast.catchId)} :\n`, level);
2068
+ } else {
2069
+ this.emit('except ', level);
2070
+ this.visitType(catchBlock.id.type);
2071
+ this.emit(` as ${_name(ast.catchId)} :\n`);
2072
+ }
2073
+ this.visitStmts(catchBlock.catchStmts, level + 2);
2074
+ });
2075
+ } else if (ast.catchBlock && ast.catchBlock.stmts.length > 0) {
2076
+ this.emit(`except Exception as ${_name(ast.catchId)} :\n`, level);
2077
+ this.visitStmts(ast.catchBlock, level + 2);
2078
+ }
2079
+ if (ast.finallyBlock && ast.finallyBlock.stmts.length > 0) {
2080
+ this.emit('finally:\n', level);
2081
+ this.visitStmts(ast.finallyBlock, level + 2);
2082
+ }
2083
+ this.emit('\n', level);
2084
+ }
2085
+
2086
+ visitWhile(ast, level) {
2087
+ assert.equal(ast.type, 'while');
2088
+ this.emit('while ', level);
2089
+ this.visitExpr(ast.condition);
2090
+ this.emit(':\n');
2091
+ this.visitStmts(ast.stmts, level + 2);
2092
+ }
2093
+
2094
+ visitFor(ast, level) {
2095
+ assert.equal(ast.type, 'for');
2096
+ // this.emit('\n');
2097
+ if (ast.list.inferred.type === 'asyncIterator' && this.isAsyncFunction) {
2098
+ this.emit('async for ', level);
2099
+ } else {
2100
+ this.emit('for ', level);
2101
+ }
2102
+
2103
+ if (ast.list.inferred && ast.list.inferred.itemType
2104
+ && ast.list.inferred.itemType.type === 'entry'){
2105
+ this.emit('k, v in ');
2106
+ this.visitExpr(ast.list, level);
2107
+ } else {
2108
+ this.emit(`${_snakeCase(_name(ast.id))} in `);
2109
+ this.visitExpr(ast.list, level);
2110
+ }
2111
+ this.emit(':\n');
2112
+ this.visitStmts(ast.stmts, level + 2);
2113
+ }
2114
+
2115
+ visitIf(ast, level) {
2116
+ assert.equal(ast.type, 'if');
2117
+ this.emit('if ', level);
2118
+ this.visitExpr(ast.condition);
2119
+ this.emit(':\n');
2120
+ this.visitStmts(ast.stmts, level + 2);
2121
+
2122
+ if (ast.elseIfs) {
2123
+ for (let i = 0; i < ast.elseIfs.length; i++) {
2124
+ const branch = ast.elseIfs[i];
2125
+ this.emit('elif ',level);
2126
+ this.visitExpr(branch.condition);
2127
+ this.emit(':\n');
2128
+ this.visitStmts(branch.stmts, level + 2);
2129
+ }
2130
+ }
2131
+
2132
+ if (ast.elseStmts) {
2133
+ this.emit('else:\n', level);
2134
+ for (let i = 0; i < ast.elseStmts.stmts.length; i++) {
2135
+ this.visitStmt(ast.elseStmts.stmts[i], level + 2);
2136
+ }
2137
+ if (ast.elseStmts.stmts.length === 0) {
2138
+ const comments = DSL.comment.getBetweenComments(this.comments, ast.elseStmts.tokenRange[0], ast.elseStmts.tokenRange[1]);
2139
+ this.visitComments(comments, level + 1);
2140
+ this.emit('pass', level + 2);
2141
+ }
2142
+ this.emit('\n');
2143
+ }
2144
+ }
2145
+
2146
+ visitThrow(ast, level) {
2147
+ this.emit('raise ', level);
2148
+ if (ast.expr.type === 'construct_model') {
2149
+ this.visitConstructModel(ast.expr, level);
2150
+ this.emit('\n');
2151
+ } else {
2152
+ this.pushImports(`${CORE}Exception`);
2153
+ this.emit(`${CORE}Exception(`);
2154
+ this.visitObject(ast.expr, level);
2155
+ this.emit(')\n');
2156
+ }
2157
+ }
2158
+
2159
+ visitAssign(ast, level) {
2160
+ if (ast.left.type === 'property_assign' || ast.left.type === 'property') {
2161
+ this.emit('', level);
2162
+ this.visitPropertyAccess(ast.left, { left: true });
2163
+ } else if (ast.left.type === 'virtualVariable') { // vid
2164
+ this.emit(`self.${_snakeCase(_vid((ast.left.vid)))}`, level);
2165
+ } else if (ast.left.type === 'variable') {
2166
+ this.emit(`${_snakeCase(_name(ast.left.id))}`, level);
2167
+ } else if (ast.left.type === 'map_access') {
2168
+ // 声明时不能用get去赋值
2169
+ this.emit('', level);
2170
+ this.visitMapAccess(ast.left, level, { left: true });
2171
+ } else if (ast.left.type === 'array_access') {
2172
+ this.emit('', level);
2173
+ this.visitArrayAccess(ast.left, level);
2174
+ } else {
2175
+ throw new Error('unimpelemented');
2176
+ }
2177
+
2178
+ this.emit(' = ');
2179
+ // if (ast.expr.needToReadable) {
2180
+ // this.emit(`${CORE}Core.to_readable_stream(`);
2181
+ // }
2182
+ this.visitExpr(ast.expr, level);
2183
+ // if (ast.expr.needToReadable) {
2184
+ // this.emit(')');
2185
+ // }
2186
+ this.emit('\n');
2187
+ }
2188
+
2189
+ // 实例初始化 new的地方
2190
+ visitDeclare(ast, level) {
2191
+ var id = _snakeCase(_name(ast.id));
2192
+ this.emit(`${id}`, level);
2193
+ if(id === 'new_full_str'){
2194
+ this.emit('');
2195
+ }
2196
+
2197
+ if (ast.expr.type === 'null') {
2198
+ this.emit(' = None\n');
2199
+ return;
2200
+ }
2201
+
2202
+ this.emit(' = ');
2203
+ this.visitExpr(ast.expr, level);
2204
+ this.emit('\n');
2205
+ }
2206
+
2207
+ visitStmts(ast, level) {
2208
+ assert.equal(ast.type, 'stmts');
2209
+ let node;
2210
+ for (var i = 0; i < ast.stmts.length; i++) {
2211
+ node = ast.stmts[i];
2212
+ this.visitStmt(node, level);
2213
+ }
2214
+ if (node) {
2215
+ //find the last node's back comment
2216
+ let comments = DSL.comment.getBackComments(this.comments, node.tokenRange[1]);
2217
+ this.visitComments(comments, level);
2218
+ }
2219
+
2220
+ if (ast.stmts.length === 0) {
2221
+ //empty block's comment
2222
+ let comments = DSL.comment.getBetweenComments(this.comments, ast.tokenRange[0], ast.tokenRange[1]);
2223
+ this.visitComments(comments, level);
2224
+ this.emit('pass\n',level);
2225
+ }
2226
+ }
2227
+
2228
+ visitReturnBody(ast, level) {
2229
+ assert.equal(ast.type, 'returnBody');
2230
+ this.visitStmts(ast.stmts, level);
2231
+ }
2232
+
2233
+ visitDefaultReturnBody(level) {
2234
+ this.emit('\n');
2235
+ this.emit('return {}\n', level);
2236
+ }
2237
+
2238
+ visitFunctionBody(ast, level) {
2239
+ assert.equal(ast.type, 'functionBody');
2240
+ this.visitStmts(ast.stmts, level);
2241
+ }
2242
+
2243
+ isIterator(returnType) {
2244
+ if (returnType.type === 'iterator' || returnType.type === 'asyncIterator') {
2245
+ return true;
2246
+ }
2247
+ return false;
2248
+ }
2249
+
2250
+ eachFunction(ast, level) {
2251
+ this.emit('\n');
2252
+ // level += 1;
2253
+ // TODO: 注释部分,暂时移除
2254
+ // this.visitAnnotation(ast.annotation, level);
2255
+ // let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
2256
+ // this.visitComments(comments, level);
2257
+ const functionName = _snakeCase(_name(ast.functionName));
2258
+
2259
+ if (ast.isStatic) {
2260
+ this.emit('@staticmethod\n', level);
2261
+ } else {
2262
+ this.isStaticFunction = false;
2263
+ }
2264
+
2265
+ this.emit('', level);
2266
+
2267
+ this.emit('def ');
2268
+
2269
+ this.emit(`${functionName}`);
2270
+
2271
+ // 入参
2272
+ if (ast.isStatic) {
2273
+ this.visitParams(ast.params, level);
2274
+ } else {
2275
+ this.visitParams(ast.params, level, true);
2276
+ }
2277
+
2278
+ // 返回值类型
2279
+ this.visitReturnType(ast);
2280
+ this.emit(':\n');
2281
+ let secondLevel = level + 2;
2282
+ if (ast.functionBody) {
2283
+ // 这里是函数体
2284
+ this.visitFunctionBody(ast.functionBody, secondLevel);
2285
+ } else {
2286
+ let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
2287
+ this.visitComments(comments, secondLevel);
2288
+ this.emit('raise Exception(\'Un-implemented\')\n', secondLevel);
2289
+ }
2290
+ // generate async function
2291
+ if (ast.isAsync) {
2292
+ this.isAsyncFunction = true;
2293
+ this.emit('\n');
2294
+ if (ast.isStatic) {
2295
+ this.emit('@staticmethod\n', level);
2296
+ } else {
2297
+ this.isStaticFunction = false;
2298
+ }
2299
+ this.emit('', level);
2300
+ this.emit('async def ');
2301
+ this.emit(`${functionName}_async`);
2302
+ // 入参
2303
+ if (ast.isStatic) {
2304
+ this.visitParams(ast.params, level);
2305
+ } else {
2306
+ this.visitParams(ast.params, level, true);
2307
+ }
2308
+ // 返回值类型
2309
+ this.visitReturnType(ast);
2310
+ this.emit(':\n');
2311
+ if (ast.functionBody) {
2312
+ // 这里是函数体
2313
+ this.visitFunctionBody(ast.functionBody, secondLevel);
2314
+ } else {
2315
+ let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
2316
+ this.visitComments(comments, level+2);
2317
+ this.emit('raise Exception(\'Un-implemented\')\n', level + 2);
2318
+ }
2319
+ }
2320
+ this.isAsyncFunction = false;
2321
+ this.isStaticFunction = true;
2322
+ }
2323
+
2324
+ eachAPI(ast, level) {
2325
+ this.emit('\n');
2326
+ // if (ast.annotation) {
2327
+ // this.emit(`${_anno(ast.annotation.value)}\n`, level);
2328
+ // }
2329
+
2330
+ this.visitAnnotation(ast.annotation, level);
2331
+ let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
2332
+ this.visitComments(comments, level);
2333
+ // set api name to _snakeCase
2334
+ const apiName = _snakeCase(_name(ast.apiName));
2335
+ this.isStaticFunction = false;
2336
+ this.emit(`def ${apiName}`, level);
2337
+ this.visitParams(ast.params, level, true);
2338
+ this.visitReturnType(ast);
2339
+ this.emit(':\n');
2340
+ let secondLevel = level + 2;
2341
+ this.pushImports(`${CORE}Core`);
2342
+ if (ast.runtimeBody) {
2343
+ this.pushImports('UnretryableException');
2344
+ this.pushImports('RetryPolicyContext');
2345
+ this.visitRuntimeBefore(ast.runtimeBody, level);
2346
+ secondLevel += 4;
2347
+ }
2348
+ if (ast.apiBody) {
2349
+ this.visitAPIBody(ast.apiBody, secondLevel);
2350
+ }
2351
+ this.emit(`_last_request = ${REQUEST}\n`, secondLevel);
2352
+ this.emit(`${RESPONSE} = ${CORE}Core.do_action(${REQUEST}`, secondLevel);
2353
+ if (ast.runtimeBody) {
2354
+ this.emit(', _runtime');
2355
+ }
2356
+ this.emit(')\n');
2357
+ if (ast.runtimeBody) {
2358
+ this.emit(`_last_response = ${RESPONSE}\n`, secondLevel);
2359
+ }
2360
+
2361
+
2362
+ if (ast.returns) {
2363
+ this.visitReturnBody(ast.returns, secondLevel);
2364
+ } else {
2365
+ this.visitDefaultReturnBody(secondLevel);
2366
+ }
2367
+
2368
+ if (ast.runtimeBody) {
2369
+ this.visitRuntimeAfter(ast.runtimeBody, level + 1);
2370
+ }
2371
+ // generate async function
2372
+ this.emit('\n');
2373
+ this.isAsyncFunction = true;
2374
+ this.emit(`async def ${apiName}_async`, level);
2375
+ this.visitParams(ast.params, level, true);
2376
+ this.visitReturnType(ast);
2377
+ this.emit(':\n');
2378
+ // api level
2379
+ if (ast.runtimeBody) {
2380
+ this.visitRuntimeBefore(ast.runtimeBody, level);
2381
+ }
2382
+ // temp level
2383
+ this.visitAPIBody(ast.apiBody, secondLevel);
2384
+ this.emit(`_last_request = ${REQUEST}\n`, secondLevel);
2385
+ this.emit(`${RESPONSE} = await ${CORE}Core.async_do_action(${REQUEST}`, secondLevel);
2386
+ if (ast.runtimeBody) {
2387
+ this.emit(', _runtime');
2388
+ }
2389
+ this.emit(')\n');
2390
+ if (ast.runtimeBody) {
2391
+ this.emit(`_last_response = ${RESPONSE}\n`, secondLevel);
2392
+ }
2393
+
2394
+ if (ast.returns) {
2395
+ this.visitReturnBody(ast.returns, secondLevel);
2396
+ } else {
2397
+ this.visitDefaultReturnBody(secondLevel);
2398
+ }
2399
+
2400
+ if (ast.runtimeBody) {
2401
+ this.visitRuntimeAfter(ast.runtimeBody, level + 1);
2402
+ }
2403
+ this.isStaticFunction = true;
2404
+ this.isAsyncFunction = false;
2405
+ }
2406
+
2407
+ visitRuntimeAfter(ast, level) {
2408
+ this.emit(` except Exception as e:
2409
+ _context = RetryPolicyContext(
2410
+ retries_attempted= _retries_attempted,
2411
+ http_request = _last_request,
2412
+ http_response = _last_response,
2413
+ exception = e
2414
+ )
2415
+ continue
2416
+ raise UnretryableException(_context)\n`);
2417
+ }
2418
+
2419
+ emitImports() {
2420
+ let tempOutput = ''; // 定义一个临时变量来存放输出内容
2421
+
2422
+ if (this.config.editable !== true) {
2423
+ tempOutput += '# -*- coding: utf-8 -*-\n';
2424
+ tempOutput += '# This file is auto-generated, don\'t edit it. Thanks.\n';
2425
+ }
2426
+
2427
+ tempOutput += 'from __future__ import annotations\n';
2428
+
2429
+ const imports = [];
2430
+ this.imports.forEach(ele => {
2431
+ let header = '';
2432
+ if(ele.packageName) {
2433
+ header += `from ${ele.packageName} `;
2434
+ }
2435
+
2436
+ if(ele.className) {
2437
+ header += `import ${ele.className} `;
2438
+ }
2439
+
2440
+ if(ele.aliasName) {
2441
+ header += `as ${ele.aliasName} `;
2442
+ }
2443
+ imports.push(header);
2444
+ });
2445
+
2446
+ tempOutput += [...new Set(imports)].join('\n') + '\n';
2447
+
2448
+ if (this.usedTypes.length > 0) {
2449
+ tempOutput += 'from typing import '
2450
+ + [...new Set(this.usedTypes)].join(', ');
2451
+ tempOutput += '\n';
2452
+ }
2453
+
2454
+
2455
+ // 将临时输出插入到 this.output 的开头
2456
+ this.output = tempOutput + '\n\n' + this.output;
2457
+ }
2458
+
2459
+ modelBefore(ast, level) {
2460
+ let beginToken = 0;
2461
+ if(ast.imports.length > 0) {
2462
+ const lastIndex = ast.imports.length - 1;
2463
+ beginToken = ast.imports[lastIndex].tokenRange[0];
2464
+ }
2465
+ let endToken = 0;
2466
+ if(ast.moduleBody.nodes.length > 0) {
2467
+ endToken = ast.moduleBody.nodes[0].tokenRange[0];
2468
+ }
2469
+ const beginNotes = DSL.note.getNotes(this.notes, beginToken, endToken);
2470
+ const part = beginNotes.find(note => note.note.lexeme === '@pythonModel');
2471
+ if(part && part.arg.value) {
2472
+ this.emit(_string(part.arg.value));
2473
+ }
2474
+ }
2475
+
2476
+ moduleBefore(ast, level) {
2477
+ let beginToken = 0;
2478
+ if(ast.imports.length > 0) {
2479
+ const lastIndex = ast.imports.length - 1;
2480
+ beginToken = ast.imports[lastIndex].tokenRange[0];
2481
+ }
2482
+ let endToken = 0;
2483
+ if(ast.moduleBody.nodes.length > 0) {
2484
+ endToken = ast.moduleBody.nodes[0].tokenRange[0];
2485
+ }
2486
+ const beginNotes = DSL.note.getNotes(this.notes, beginToken, endToken);
2487
+ const part = beginNotes.find(note => note.note.lexeme === '@python');
2488
+ if(part && part.arg.value) {
2489
+ this.emit(_string(part.arg.value));
2490
+ }
2491
+ }
2492
+
2493
+ apiBefore(level) {
2494
+
2495
+ this.emit(`class ${this.className}`, level);
2496
+ if (this.parentModule) {
2497
+ const aliasId = _name(this.parentModule);
2498
+ let clientName = this.getModelName('', aliasId, 'module');
2499
+ this.emit(`(${clientName})`);
2500
+ }
2501
+ this.emit(':');
2502
+ }
2503
+
2504
+ checkFieldHasModel(fieldValue) {
2505
+ if (fieldValue.type === 'modelBody') {
2506
+ return true;
2507
+ } else if (fieldValue.type === 'array' || fieldValue.fieldType === 'array') {
2508
+ return this.checkFieldHasModel(fieldValue.fieldItemType || fieldValue.subType);
2509
+ } else if (fieldValue.fieldType === 'map' || fieldValue.type === 'map') {
2510
+ return this.checkFieldHasModel(fieldValue.valueType);
2511
+ } else if (fieldValue.type === 'moduleModel' ||
2512
+ (fieldValue.fieldType && fieldValue.fieldType.type === 'moduleModel')) {
2513
+ return true;
2514
+ } else if (fieldValue.type === 'subModel') {
2515
+ return true;
2516
+ } else if (fieldValue.idType === 'model') {
2517
+ return true;
2518
+ } else if (fieldValue.fieldType && fieldValue.fieldType.idType === 'model') {
2519
+ return true;
2520
+ } else if (fieldValue.fieldType && fieldValue.fieldType.idType === 'builtin_model') {
2521
+ return true;
2522
+ }
2523
+ return false;
2524
+ }
2525
+
2526
+ checkFieldItemTypeAllString(obj) {
2527
+ // 基本检查,确保传入的是对象且存在 fieldItemType 属性
2528
+ if (obj && obj.fieldItemType) {
2529
+ // 如果 fieldItemType 是字符串且等于 'string'
2530
+ if (obj.fieldItemType.lexeme === 'string') {
2531
+ return true;
2532
+ } else if (obj.fieldItemType.fieldType === 'array') {
2533
+ // 如果 fieldItemType 仍然是数组
2534
+ return this.checkFieldItemTypeAllString(obj.fieldItemType);
2535
+ } else if (obj.fieldItemType.valueType && obj.fieldItemType.valueType.lexeme === 'any'){
2536
+ return true;
2537
+ }
2538
+ }
2539
+ if (obj && obj.fieldType ==='map'){
2540
+ return this.checkFieldItemTypeAllString(obj.valueType);
2541
+ }
2542
+ if (obj && obj.subType){
2543
+ if (obj.subType.type === 'map'){
2544
+ return this.checkFieldItemTypeAllString(obj.subType);
2545
+ }
2546
+ }
2547
+ if (obj && obj.valueType) {
2548
+ if (obj.valueType.lexeme === 'string') {
2549
+ return true;
2550
+ }
2551
+ }
2552
+ return false;
2553
+ }
2554
+
2555
+ getClassNamespace(pyPath) {
2556
+ if(path.resolve(pyPath).startsWith(path.resolve(this.outputDir))) {
2557
+ const baseDir = path.join(this.outputDir, path.sep, this.config.package);
2558
+ pyPath = pyPath.replace(baseDir, '');
2559
+ }
2560
+
2561
+ const arr = pyPath.replace('.py', '').split(path.sep).slice(0, -1);
2562
+
2563
+
2564
+ let className = this.config.package;
2565
+ arr.map(key => {
2566
+ if(!key) {
2567
+ return;
2568
+ }
2569
+ className += '.' + key;
2570
+ });
2571
+
2572
+ return className;
2573
+ }
2574
+
2575
+ getAliasName(name, aliasId) {
2576
+ let aliasName = '';
2577
+ if (!this.clientName.has(name) && name !== this.className) {
2578
+ this.clientName.set(name, aliasId);
2579
+ return aliasName;
2580
+ }
2581
+ if (aliasId) {
2582
+ aliasName = aliasId + name;
2583
+ }
2584
+ if (aliasName && !this.clientName.has(aliasName)) {
2585
+ this.clientName.set(aliasName, aliasId);
2586
+ return aliasName.replace(/-/g, '');
2587
+ }
2588
+ }
2589
+
2590
+ getRealName(node) {
2591
+ const nameAttr = node.attrs.find((item) => {
2592
+ return item.attrName.lexeme === 'name';
2593
+ });
2594
+ return nameAttr ?_string(nameAttr.attrValue) : _name(node.fieldName);
2595
+ }
2596
+
2597
+ getModelName(name, moduleName, type = 'model'){
2598
+ if(type === 'model' && !moduleName) {
2599
+ const aliasName = 'main_models';
2600
+ this.imports.push({
2601
+ aliasName,
2602
+ packageName: this.config.package,
2603
+ className: 'models',
2604
+ });
2605
+ return `${aliasName}.${name}`;
2606
+ }
2607
+
2608
+ if(type === 'model' && moduleName) {
2609
+ const { namemespace, models } = this.packageInfo[moduleName];
2610
+ const aliasName = `${_snakeCase(moduleName.replace(/-/g, ''))}_models`;
2611
+ this.imports.push({
2612
+ aliasName,
2613
+ packageName: namemespace,
2614
+ className: models || 'models',
2615
+ });
2616
+ return `${aliasName}.${name}`;
2617
+ }
2618
+
2619
+ if(type === 'exception' && !moduleName) {
2620
+ const aliasName = 'main_exceptions';
2621
+ this.imports.push({
2622
+ aliasName,
2623
+ packageName: this.config.package,
2624
+ className: 'exceptions',
2625
+ });
2626
+ return `${aliasName}.${name}Exception`;
2627
+ }
2628
+
2629
+ if(type === 'exception' && moduleName) {
2630
+ const { namemespace, exceptions } = this.packageInfo[moduleName];
2631
+ const aliasName = `${_snakeCase(moduleName.replace(/-/g, ''))}_exceptions`;
2632
+ this.imports.push({
2633
+ aliasName,
2634
+ packageName: namemespace,
2635
+ className: exceptions || 'exceptions',
2636
+ });
2637
+ return `${aliasName}.${name}Exception`;
2638
+ }
2639
+
2640
+ if(type === 'module') {
2641
+ const {
2642
+ aliasName,
2643
+ clientName,
2644
+ fileName,
2645
+ namemespace,
2646
+ } = this.packageInfo[moduleName];
2647
+
2648
+ this.imports.push({
2649
+ aliasName: clientName === aliasName ? '' : aliasName,
2650
+ packageName: `${namemespace}.${fileName}`,
2651
+ className: clientName,
2652
+ });
2653
+ return aliasName;
2654
+ }
2655
+
2656
+ name = _type(name);
2657
+ this.pushImports(name);
2658
+ return name;
2659
+ }
2660
+
2661
+ getInnerClient(aliasId) {
2662
+ const moduleAst = this.ast.innerDep.get(aliasId);
2663
+ const beginNotes = DSL.note.getNotes(moduleAst.notes, 0, moduleAst.moduleBody.nodes[0].tokenRange[0]);
2664
+ const clientNote = beginNotes.find(note => note.note.lexeme === '@clientName');
2665
+ if(clientNote) {
2666
+ return _string(clientNote.arg.value);
2667
+ }
2668
+ return 'Client';
2669
+ }
2670
+
2671
+ pushImports(type) {
2672
+ const pkg = _getImport(type);
2673
+ if(pkg) {
2674
+ this.imports.push(pkg);
2675
+ return;
2676
+ }
2677
+
2678
+ if(type === 'sys') {
2679
+ this.imports.push({
2680
+ className: 'sys',
2681
+ });
2682
+ }
2683
+
2684
+ if(type === 'Any' ) {
2685
+ this.usedTypes.push('Any');
2686
+ }
2687
+
2688
+ if(type === 'array') {
2689
+ this.usedTypes.push('List');
2690
+ }
2691
+
2692
+ if(type === 'map') {
2693
+ this.usedTypes.push('Dict');
2694
+ }
2695
+
2696
+ if(type === 'BinaryIO') {
2697
+ this.usedTypes.push('BinaryIO');
2698
+ }
2699
+
2700
+ }
2701
+
2702
+ }
2703
+
2704
+ module.exports = Visitor;