@darabonba/python-generator 1.2.19 → 2.0.1

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