@lcap/nasl 3.8.3-beta.4 → 3.8.3-beta.6

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 (101) hide show
  1. package/out/common/BaseNode.d.ts +9 -4
  2. package/out/common/BaseNode.js +73 -18
  3. package/out/common/BaseNode.js.map +1 -1
  4. package/out/common/utils.d.ts +5 -1
  5. package/out/common/utils.js +188 -6
  6. package/out/common/utils.js.map +1 -1
  7. package/out/concepts/App__.js +17 -13
  8. package/out/concepts/App__.js.map +1 -1
  9. package/out/concepts/AuthLogicForCallInterface__.js +2 -50
  10. package/out/concepts/AuthLogicForCallInterface__.js.map +1 -1
  11. package/out/concepts/BusinessComponent__.js +2 -42
  12. package/out/concepts/BusinessComponent__.js.map +1 -1
  13. package/out/concepts/BusinessLogic__.js +2 -50
  14. package/out/concepts/BusinessLogic__.js.map +1 -1
  15. package/out/concepts/CallFunction__.d.ts +1 -1
  16. package/out/concepts/CallFunction__.js +1 -1
  17. package/out/concepts/CallLogic__.js +2 -2
  18. package/out/concepts/CallLogic__.js.map +1 -1
  19. package/out/concepts/Identifier__.d.ts +2 -0
  20. package/out/concepts/Identifier__.js +51 -5
  21. package/out/concepts/Identifier__.js.map +1 -1
  22. package/out/concepts/Logic__.js +6 -101
  23. package/out/concepts/Logic__.js.map +1 -1
  24. package/out/concepts/MemberExpression__.d.ts +1 -1
  25. package/out/concepts/MemberExpression__.js +15 -3
  26. package/out/concepts/MemberExpression__.js.map +1 -1
  27. package/out/concepts/OqlQueryComponent__.d.ts +0 -1
  28. package/out/concepts/OqlQueryComponent__.js +0 -70
  29. package/out/concepts/OqlQueryComponent__.js.map +1 -1
  30. package/out/concepts/OverriddenLogic__.js +2 -50
  31. package/out/concepts/OverriddenLogic__.js.map +1 -1
  32. package/out/concepts/ProcessElementV2__.js +4 -0
  33. package/out/concepts/ProcessElementV2__.js.map +1 -1
  34. package/out/concepts/ProcessElement__.js +4 -0
  35. package/out/concepts/ProcessElement__.js.map +1 -1
  36. package/out/concepts/ProcessV2__.js +4 -0
  37. package/out/concepts/ProcessV2__.js.map +1 -1
  38. package/out/concepts/Process__.js +4 -0
  39. package/out/concepts/Process__.js.map +1 -1
  40. package/out/concepts/SubLogic__.js +5 -50
  41. package/out/concepts/SubLogic__.js.map +1 -1
  42. package/out/concepts/TypeAnnotation__.js +1 -1
  43. package/out/concepts/TypeAnnotation__.js.map +1 -1
  44. package/out/concepts/View__.js +10 -49
  45. package/out/concepts/View__.js.map +1 -1
  46. package/out/generator/genBundleFiles.js +5 -5
  47. package/out/generator/permission.js +21 -5
  48. package/out/generator/permission.js.map +1 -1
  49. package/out/generator/release-body/body.js.map +1 -1
  50. package/out/natural/transformTS2UI.js +5 -5
  51. package/out/natural/transformTS2UI.js.map +1 -1
  52. package/out/natural/transforms/transform2LogicItem.js +5 -5
  53. package/out/natural/transforms/transform2LogicItem.js.map +1 -1
  54. package/out/server/naslServer.js +20 -2
  55. package/out/server/naslServer.js.map +1 -1
  56. package/out/server/semanticData.d.ts +32 -0
  57. package/out/server/semanticData.js +371 -0
  58. package/out/server/semanticData.js.map +1 -0
  59. package/out/service/logic/api.d.ts +9 -0
  60. package/out/service/logic/api.js +6 -0
  61. package/out/service/logic/api.js.map +1 -1
  62. package/out/templator/block2nasl/viewMergeBlock.js +2 -1
  63. package/out/templator/block2nasl/viewMergeBlock.js.map +1 -1
  64. package/package.json +1 -1
  65. package/sandbox/stdlib/nasl.collection.ts +3 -3
  66. package/src/common/BaseNode.ts +106 -36
  67. package/src/common/utils.ts +227 -5
  68. package/src/concepts/App__.ts +17 -13
  69. package/src/concepts/AuthLogicForCallInterface__.ts +3 -56
  70. package/src/concepts/BusinessComponent__.ts +6 -51
  71. package/src/concepts/BusinessLogic__.ts +4 -56
  72. package/src/concepts/CallFunction__.ts +1 -1
  73. package/src/concepts/CallLogic__.ts +8 -4
  74. package/src/concepts/Identifier__.ts +57 -6
  75. package/src/concepts/Logic__.ts +9 -111
  76. package/src/concepts/MemberExpression__.ts +21 -7
  77. package/src/concepts/OqlQueryComponent__.ts +1 -74
  78. package/src/concepts/OverriddenLogic__.ts +4 -56
  79. package/src/concepts/ProcessElementV2__.ts +4 -0
  80. package/src/concepts/ProcessElement__.ts +4 -0
  81. package/src/concepts/ProcessV2__.ts +5 -0
  82. package/src/concepts/Process__.ts +4 -0
  83. package/src/concepts/SubLogic__.ts +6 -56
  84. package/src/concepts/TypeAnnotation__.ts +1 -1
  85. package/src/concepts/View__.ts +14 -54
  86. package/src/generator/genBundleFiles.ts +5 -5
  87. package/src/generator/permission.ts +23 -5
  88. package/src/generator/release-body/body.ts +0 -1
  89. package/src/natural/transformTS2UI.ts +5 -5
  90. package/src/natural/transforms/transform2LogicItem.ts +5 -5
  91. package/src/server/naslServer.ts +26 -2
  92. package/src/server/semanticData.ts +447 -0
  93. package/src/service/logic/api.js +6 -0
  94. package/src/templator/block2nasl/viewMergeBlock.ts +2 -1
  95. package/src/translator/utils.ts +1 -1
  96. package/test/concepts/logic/__snapshots__/toEmbeddedTS.spec.ts.snap +182 -0
  97. package/test/concepts/logic/constant.ts +5 -0
  98. package/test/concepts/logic/fixtures/variable-host-call-logic-member-expression.json +267 -0
  99. package/test/concepts/logic/fixtures/variable-host-call-logic-nested-member-expression copy.json +457 -0
  100. package/test/concepts/logic/fixtures/variable-host-call-logic-with-handle-error-member-expression.json +267 -0
  101. package/test/concepts/logic/toEmbeddedTS.spec.ts +15 -0
@@ -20,6 +20,8 @@ export function setActionable(value: boolean) {
20
20
  actionable = value;
21
21
  }
22
22
 
23
+ import { varScopeCtx } from '../server/semanticData';
24
+
23
25
  const patchCompose = (node: BaseNode, type = 'add') => {
24
26
  if (node?.composedBy) {
25
27
  const app = (node as any)?.app;
@@ -942,7 +944,7 @@ export class BaseNode extends EventEmitter {
942
944
  }
943
945
 
944
946
  get app() {
945
- return this.getAncestor('App') as App;
947
+ return varScopeCtx.isFirstScreen ? varScopeCtx.app : this.getAncestor('App') as App;
946
948
  }
947
949
 
948
950
  /**
@@ -1435,13 +1437,9 @@ export class BaseNode extends EventEmitter {
1435
1437
  * @description 与`traverseChildren`不同,此方法会过滤掉非节点值
1436
1438
  */
1437
1439
  *traverseChildrenGenerator(cb: (node: types.SyntaxNode) => (void | Generator<any, any, any>)) {
1438
- const isNode = (node: unknown): node is types.SyntaxNode => {
1439
- return Boolean(node) && typeof node === 'object' && ('concept' in node) && typeof (node as any).concept === 'string';
1440
- };
1441
-
1442
1440
  function* traverse(node: BaseNode): Generator<any, any, any> {
1443
- if (isNode(node)) {
1444
- const result = cb(node);
1441
+ if (asserts.isBaseNode(node)) {
1442
+ const result = cb(node as types.SyntaxNode);
1445
1443
 
1446
1444
  if (utils.isGenerator(result)) {
1447
1445
  yield* result;
@@ -1486,50 +1484,122 @@ export class BaseNode extends EventEmitter {
1486
1484
  * @description 严格迭代所有子节点!排除属性!
1487
1485
  */
1488
1486
  traverseStrictChildren(cb: (el: types.SyntaxNode) => void, whitelist?: string[]): void {
1489
- this.traverseChildren((el) => {
1490
- if (asserts.isBaseNode(el)) {
1491
- cb(el as types.SyntaxNode);
1487
+ function traverse(node: any) {
1488
+ if (!node) {
1489
+ return;
1490
+ }
1491
+
1492
+ if (asserts.isBaseNode(node)) {
1493
+ cb(node as types.SyntaxNode);
1492
1494
  }
1493
- }, whitelist);
1495
+
1496
+ const propertyMap = getConceptPropertyMap(node?.concept);
1497
+
1498
+ if (!propertyMap) {
1499
+ return;
1500
+ }
1501
+
1502
+ const keys = (whitelist && whitelist.length > 0)
1503
+ ? Array.from(propertyMap.keys()).concat(whitelist)
1504
+ : propertyMap.keys();
1505
+
1506
+ for (const property of keys) {
1507
+ const prop = node[property as keyof BaseNode];
1508
+
1509
+ if (!prop) {
1510
+ continue;
1511
+ }
1512
+ else if (Array.isArray(prop)) {
1513
+ for (const child of prop) {
1514
+ traverse(child);
1515
+ }
1516
+ }
1517
+ else {
1518
+ traverse(prop);
1519
+ }
1520
+ }
1521
+ }
1522
+
1523
+ traverse(this);
1494
1524
  }
1495
1525
 
1496
- /**
1526
+ /**
1497
1527
  * 迭代所有子节点
1498
1528
  *
1499
- * @description 严格迭代所有子节点!排除属性!条件满足时可提前终止!
1529
+ * @description 严格迭代所有子节点!排除属性!条件满足时整个遍历全部终止!
1500
1530
  */
1501
- traverseStrictChildrenStopWhen(cb: (el: types.SyntaxNode) => void, setStopFlag: (el: types.SyntaxNode) => boolean, whitelist?: string[]): void {
1502
- let shouldStop = false;
1531
+ traverseStrictChildrenStopWhen(cb: (el: types.SyntaxNode) => void, setStopFlag: (el: types.SyntaxNode) => boolean, whitelist?: string[]): void {
1532
+ let shouldStop = false;
1503
1533
 
1504
- // if ((node instanceof View || node instanceof ViewElement) && node.auth) flag = true;
1505
- function traverse(node: any) {
1506
- if (asserts.isBaseNode(node)) {
1507
- cb(node as types.SyntaxNode);
1508
- }
1534
+ function __traverse(node: any) {
1535
+ if (asserts.isBaseNode(node)) {
1536
+ cb(node as types.SyntaxNode);
1537
+ }
1509
1538
 
1510
- shouldStop = shouldStop || setStopFlag(node);
1511
- if (shouldStop) {
1512
- return;
1513
- }
1539
+ shouldStop = shouldStop || setStopFlag(node);
1514
1540
 
1515
- const propertyMap = getConceptPropertyMap(node?.concept);
1516
- if (!propertyMap) return;
1541
+ if (shouldStop) {
1542
+ return;
1543
+ }
1517
1544
 
1518
- const propertyKeys = [...propertyMap.keys()];
1519
- if (Array.isArray(whitelist) && whitelist.length) {
1520
- propertyKeys.push(...whitelist);
1521
- }
1522
- for (const property of propertyKeys) {
1523
- const child = node[property as keyof BaseNode];
1524
- if (!child) continue;
1525
- else if (Array.isArray(child)) child?.forEach?.((node: types.SyntaxNode) => traverse(node));
1526
- else traverse(child);
1545
+ const propertyMap = getConceptPropertyMap(node?.concept);
1546
+ if (!propertyMap) return;
1547
+
1548
+ const propertyKeys = [...propertyMap.keys()];
1549
+ if (Array.isArray(whitelist) && whitelist.length) {
1550
+ propertyKeys.push(...whitelist);
1551
+ }
1552
+ for (const property of propertyKeys) {
1553
+ const child = node[property as keyof BaseNode];
1554
+ if (!child) continue;
1555
+ else if (Array.isArray(child)) child?.forEach?.((node: types.SyntaxNode) => __traverse(node));
1556
+ else __traverse(child);
1557
+ }
1558
+ }
1559
+
1560
+ __traverse(this);
1561
+ }
1562
+
1563
+ /**
1564
+ * 迭代所有子节点
1565
+ * @description 严格迭代所有子节点,排除属性;多函数特化版本,不做额外检查
1566
+ */
1567
+ *traverseStrictChildrenDoMultiTasks(
1568
+ tasks: Array<(_: BaseNode) => Generator<any, any, any>>,
1569
+ cleanups: Array<(_: BaseNode) => Generator<any, any, any>>): Generator<any, any, any> {
1570
+
1571
+ function __traverse(nd: BaseNode) {
1572
+ if (!asserts.isBaseNode(nd)) {
1573
+ return;
1574
+ }
1575
+ tasks.forEach(task => utils.runGeneratorSync(task(nd)));
1576
+
1577
+ const props = getConceptPropertyMap(nd?.concept)?.keys();
1578
+ if (!props) {
1579
+ cleanups.forEach(task => utils.runGeneratorSync(task(nd)));
1580
+ return;
1581
+ }
1582
+
1583
+ for (const p of props) {
1584
+ const child = nd[p as keyof BaseNode];
1585
+ if (!child) {
1586
+ continue;
1587
+ } else if (Array.isArray(child)) {
1588
+ child?.forEach?.((node: types.SyntaxNode) => {
1589
+ __traverse(node);
1590
+ });
1591
+ } else {
1592
+ __traverse(child);
1527
1593
  }
1528
1594
  }
1529
1595
 
1530
- traverse(this);
1596
+ cleanups.forEach(task => utils.runGeneratorSync(task(nd)));
1531
1597
  }
1532
1598
 
1599
+ __traverse(this);
1600
+ }
1601
+
1602
+
1533
1603
  /**
1534
1604
  * 获取当前节点在nasl标注节点上的节点
1535
1605
  */
@@ -1,17 +1,239 @@
1
+ import type { AxiosInstance } from 'axios';
1
2
  import type { types } from '../concepts';
3
+ import EntityProperty from '../concepts/EntityProperty__';
4
+ import Entity from '../concepts/Entity__';
5
+ import OqlQueryComponent from '../concepts/OqlQueryComponent__';
6
+ import api from '../service/logic/api';
7
+ import { naslOQLCacheStore } from '../utils/language-cache/nasl';
2
8
 
3
- export function waitOqlQueryComponentChildrenFinish(node: types.SyntaxNode) {
4
- const needGetSourceMapOqlList: Promise<any>[] = [];
9
+ type OQLEmbeddedTSRequestPayload = {
10
+ appId: 'myAppId';
11
+ oqlIdentifier: 'myoqlIdentifier';
12
+ dataSourceName: string;
13
+ oql: string;
14
+ ideVersion: string;
15
+ dataSourceNasl: any[];
16
+ typeScriptStartLine: 1;
17
+ typeScriptStartLineColumn: 1;
18
+ };
19
+
20
+ type PayloadWithCacheKey = {
21
+ payload: OQLEmbeddedTSRequestPayload | null;
22
+ cacheKey: string;
23
+ };
24
+
25
+ function preparePayloadAndCacheKey(oql: OqlQueryComponent): PayloadWithCacheKey {
26
+ if (oql.code) {
27
+ let dataSourceNasl = oql.app.findNodeByCompleteName(oql.dataSource)?.toJSON();
28
+ if (dataSourceNasl) {
29
+ dataSourceNasl = {
30
+ concept: 'DataSource',
31
+ entities: (dataSourceNasl.entities = dataSourceNasl.entities?.map((entity: Entity) => {
32
+ return {
33
+ name: entity.name,
34
+ concept: entity.concept,
35
+ tableName: entity.tableName,
36
+ properties: entity.properties?.map((prop: EntityProperty) => {
37
+ return {
38
+ name: prop.name,
39
+ concept: prop.concept,
40
+ columnName: prop.columnName,
41
+ };
42
+ }),
43
+ };
44
+ })),
45
+ };
46
+ }
47
+ const payload: OQLEmbeddedTSRequestPayload = {
48
+ appId: 'myAppId',
49
+ oqlIdentifier: 'myoqlIdentifier',
50
+ dataSourceName: oql.dataSource,
51
+ oql: oql.code,
52
+ ideVersion: oql.app.ideVersion,
53
+ dataSourceNasl,
54
+ typeScriptStartLine: 1,
55
+ typeScriptStartLineColumn: 1,
56
+ };
57
+ return {
58
+ cacheKey: JSON.stringify(payload),
59
+ payload: payload,
60
+ };
61
+ }
62
+ return {
63
+ cacheKey: '',
64
+ payload: null,
65
+ };
66
+ }
67
+
68
+ type RequestedEmbeddedTS = {
69
+ typescript: string;
70
+ lexicalErrorCode: number;
71
+ };
72
+
73
+ // 从服务端获取 SQL -> TS 的翻译和 sourceMap
74
+ export async function requestEmbeddedTS(this: OqlQueryComponent): Promise<void> {
75
+ const { http, logger } = this.rootNode.naslServer;
76
+
77
+ if (this.code) {
78
+ let dataSourceNasl = this.app.findNodeByCompleteName(this.dataSource)?.toJSON();
79
+ if (dataSourceNasl) {
80
+ dataSourceNasl = {
81
+ concept: 'DataSource',
82
+ entities: (dataSourceNasl.entities = dataSourceNasl.entities?.map((entity: Entity) => {
83
+ return {
84
+ name: entity.name,
85
+ concept: entity.concept,
86
+ tableName: entity.tableName,
87
+ properties: entity.properties?.map((prop: EntityProperty) => {
88
+ return {
89
+ name: prop.name,
90
+ concept: prop.concept,
91
+ columnName: prop.columnName,
92
+ };
93
+ }),
94
+ };
95
+ })),
96
+ };
97
+ }
98
+
99
+ const queryWithCache = async () => {
100
+ const params = {
101
+ appId: 'myAppId',
102
+ oqlIdentifier: 'myoqlIdentifier',
103
+ dataSourceName: this.dataSource,
104
+ oql: this.code,
105
+ ideVersion: this.app.ideVersion,
106
+ dataSourceNasl,
107
+ typeScriptStartLine: 1,
108
+ typeScriptStartLineColumn: 1,
109
+ };
110
+ const key = JSON.stringify(params);
111
+ let res = null;
112
+ let canUseCache = false;
113
+ try {
114
+ res = await naslOQLCacheStore.getItem(key);
115
+ canUseCache = true;
116
+ } catch (error) {}
117
+ if (res !== null) {
118
+ return res;
119
+ }
120
+ return http.post(api.queryDebugTypescript.url.path, params).then(async ({ data }) => {
121
+ if (canUseCache) {
122
+ try {
123
+ await naslOQLCacheStore.setItem(key, data);
124
+ } catch (error) {}
125
+ }
126
+ return data;
127
+ });
128
+ };
129
+
130
+ return queryWithCache()
131
+ .then((data: any) => {
132
+ this.codeSourceMap = data.result ?? { typescript: '', lexicalErrorCode: 1001 };
133
+ })
134
+ .catch((err) => {
135
+ logger.error('Oql 请求失败', err.toString());
136
+ this.codeSourceMap = { typescript: '', lexicalErrorCode: 1001 };
137
+ });
138
+ }
139
+ this.codeSourceMap = { typescript: '', lexicalErrorCode: 1001 };
140
+ }
141
+
142
+ async function makeCachedBatchRequest(
143
+ http: AxiosInstance,
144
+ payloadWithCacheKeyList: PayloadWithCacheKey[]
145
+ ): Promise<(RequestedEmbeddedTS | null)[]> {
146
+ const itemsWithIndex = payloadWithCacheKeyList.map((item, index) => {
147
+ return { item, index };
148
+ });
149
+
150
+ const cacheTest = await Promise.all(
151
+ itemsWithIndex.map(async ({ item, index }) => {
152
+ const cached: RequestedEmbeddedTS | null = await naslOQLCacheStore.getItem(item.cacheKey);
153
+ return { item, index, cached };
154
+ })
155
+ );
156
+
157
+ const notCachedList = cacheTest.filter((x) => !x.cached);
158
+ const cachedList = cacheTest.filter((x) => x.cached);
159
+
160
+ const resultContainer = Array.from<RequestedEmbeddedTS | null>({
161
+ length: payloadWithCacheKeyList.length,
162
+ }).fill(null);
163
+
164
+ for (const { cached, index } of cachedList) {
165
+ resultContainer[index] = cached;
166
+ }
167
+ const paramList = notCachedList.map((x) => x.item.payload);
168
+ const tempResultList: (RequestedEmbeddedTS | null)[] = paramList.length
169
+ ? await http
170
+ .post(api.queryDebugTypescriptBatch.url.path, paramList)
171
+ .then((x) => x.data.result)
172
+ .then(async (resultList: (RequestedEmbeddedTS | null)[]) => {
173
+ await Promise.all(
174
+ resultList.map((res, index) => {
175
+ const payload = notCachedList[index];
176
+ resultContainer[payload.index] = res;
177
+ return naslOQLCacheStore.setItem(payload.item.cacheKey, res);
178
+ })
179
+ );
180
+ return resultList;
181
+ })
182
+ : [];
183
+ if (tempResultList.length !== paramList.length) {
184
+ throw new Error('返回的数据长度不一致');
185
+ }
186
+ return resultContainer;
187
+ }
188
+
189
+ // 从服务端获取 SQL -> TS 的翻译和 sourceMap
190
+ export async function requestEmbeddedTSBatch(
191
+ http: AxiosInstance,
192
+ oqlList: OqlQueryComponent[]
193
+ ): Promise<void> {
194
+ const paramList = oqlList.map((oql) => {
195
+ const { cacheKey, payload } = preparePayloadAndCacheKey(oql);
196
+ return { oql, cacheKey, payload };
197
+ });
198
+
199
+ return makeCachedBatchRequest(http, paramList)
200
+ .then((data) => {
201
+ if (data.length !== oqlList.length) {
202
+ throw new Error('返回的数据长度不一致');
203
+ }
204
+ data.forEach((item, index) => {
205
+ const targetOql = oqlList[index];
206
+ targetOql.codeSourceMap = item ?? { typescript: '', lexicalErrorCode: 1001 };
207
+ });
208
+ })
209
+ .catch((err) => {
210
+ // TODO wudengke logger
211
+ console.error('Oql 请求失败', err.toString());
212
+ console.error(err);
213
+ });
214
+ }
215
+
216
+ export async function waitOqlQueryComponentChildrenFinish(node: types.SyntaxNode) {
217
+ const oqlList: OqlQueryComponent[] = [];
5
218
 
6
219
  node.traverseStrictChildren((el) => {
7
220
  if (el.concept === 'OqlQueryComponent') {
8
221
  if (!el.codeSourceMap) {
9
- needGetSourceMapOqlList.push(el.requestEmbeddedTS());
222
+ oqlList.push(el);
10
223
  }
11
224
  }
12
225
  });
13
226
 
14
- if (needGetSourceMapOqlList.length > 0) {
15
- return Promise.all(needGetSourceMapOqlList);
227
+ if (oqlList.length > 0) {
228
+ const http =
229
+ node.rootNode?.naslServer.http ??
230
+ // @ts-expect-error
231
+ // 若是App节点
232
+ node?.naslServer.http;
233
+ if (http) {
234
+ return requestEmbeddedTSBatch(http, oqlList);
235
+ } else {
236
+ throw new Error('http client 不存在');
237
+ }
16
238
  }
17
239
  }
@@ -3839,23 +3839,24 @@ export class App extends BaseNode {
3839
3839
  deleteCompose(path: string[]) {
3840
3840
  if (!Array.isArray(path)) return;
3841
3841
  let compose = this.composeCache;
3842
-
3843
- const delNodes = (_compose: composeCacheType) => {
3842
+ const delNodes = (_compose: composeCacheType, key: string) => {
3844
3843
  if (_compose?.nodes) {
3845
3844
  for (const key in _compose) {
3846
- if (key !== 'nodes') {
3847
- delNodes(_compose[key]);
3845
+ // 只有form和table层级触发删除
3846
+ if (key !== 'nodes' && key !== 'saveModalForm') {
3847
+ delNodes(_compose[key], key);
3848
3848
  }
3849
3849
  }
3850
3850
  const arr = [..._compose.nodes] || [];
3851
- const triggerNode: BaseNode[] = []; // 触点放在最后删
3852
- arr.forEach((node) => {
3853
- if (node.name === path?.[0]) {
3854
- triggerNode.push(node);
3855
- } else {
3856
- node && node.delete();
3857
- }
3858
- });
3851
+ // table内的saveModalForm.nodes也在table层级一起删除,避免先删父后删子的情况
3852
+ if (_compose.hasOwnProperty('saveModalForm')) {
3853
+ arr.push(..._compose.saveModalForm.nodes);
3854
+ }
3855
+ // 按照路径长度,粗粒度处理好父子关系后,再删除节点
3856
+ const triggerNode = arr
3857
+ .map((item, index) => ({ nodePath: item?.nodePath, index }))
3858
+ .sort((a, b) => b.nodePath.length - a.nodePath.length)
3859
+ .map((item) => arr[item.index]);
3859
3860
 
3860
3861
  triggerNode.forEach((node) => {
3861
3862
  node && node.delete();
@@ -3867,10 +3868,13 @@ export class App extends BaseNode {
3867
3868
 
3868
3869
  this.emit('collect:start', {
3869
3870
  actionMsg: '删除同一分组节点',
3871
+ extra: {
3872
+ isCustomDesigner: true,
3873
+ },
3870
3874
  });
3871
3875
  path.forEach((key, index) => {
3872
3876
  if (index === path.length - 1) {
3873
- delNodes(compose?.[key]);
3877
+ delNodes(compose?.[key], key);
3874
3878
  } else {
3875
3879
  compose = compose[key];
3876
3880
  }
@@ -42,6 +42,7 @@ import * as asserts from './utils/asserts';
42
42
 
43
43
  import Param from './Param__';
44
44
  import AuthLogic from './AuthLogic__';
45
+ import { reCollectTyInferCtx } from '../server/semanticData';
45
46
 
46
47
  /**
47
48
  * 调用接口的鉴权逻辑
@@ -352,61 +353,7 @@ export class AuthLogicForCallInterface extends AuthLogic {
352
353
  // 需要类型推导的局部变量/返回值需要调整申明顺序
353
354
  const advanceMap: Map<Return | Variable, Assignment | BatchAssignment> = new Map();
354
355
  const callFunctionAdvanceMap: Map<Return | Variable, CallFunction> = new Map();
355
- yield* self.traverseChildrenGenerator(function* traverseChildrenGenerator(el) {
356
- if (
357
- el &&
358
- // 批量赋值
359
- (asserts.isBatchAssignment(el) ||
360
- // 赋值
361
- (asserts.isAssignment(el) && el.left?.name) ||
362
- // 内置函数对集合类型的推导
363
- (asserts.isCallFunction(el) && el.derivablecollection?.name))
364
- ) {
365
- if (el?.getAncestor('SubLogic')) {
366
- return;
367
- }
368
- if (asserts.isAssignment(el)) {
369
- const advanceVar = self.variables?.find(
370
- (variable) => !variable.typeAnnotation && el.left?.name === variable.name,
371
- );
372
- if (advanceVar && !advanceMap.get(advanceVar)) {
373
- advanceMap.set(advanceVar, el);
374
- }
375
- const advanceRn = self.returns?.find((ret) => !ret.typeAnnotation && el.left?.name === ret.name);
376
- if (advanceRn && !advanceMap.get(advanceRn)) {
377
- advanceMap.set(advanceRn, el);
378
- }
379
- } else if (asserts.isCallFunction(el)) {
380
- // 需要被推导的集合
381
- const expression = el.derivablecollection;
382
- // 宽泛意义上的变量(变量+出参)
383
- const advanceVar = [...(self.variables || []), ...(self.returns || [])].find((variable) => {
384
- return !variable.typeAnnotation && expression?.name === variable.name;
385
- });
386
- if (advanceVar && !callFunctionAdvanceMap.get(advanceVar)) {
387
- callFunctionAdvanceMap.set(advanceVar, el);
388
- }
389
- } else if (asserts.isBatchAssignment(el)) {
390
- yield* wrapForEach(el.assignmentLines, function* warpForEachGenerator({ leftIndex }) {
391
- const leftCode =
392
- leftIndex.length === 1
393
- ? yield* el.left.expression.toEmbeddedTS(shiftState(state, code, { inline: true }))
394
- : yield* el.left.members[leftIndex[1]]?.toEmbeddedTS(shiftState(state, code, { inline: true })) ??
395
- returnOrigin('');
396
- const advanceVar = self.variables?.find(
397
- (variable) => !variable.typeAnnotation && leftCode === variable.name,
398
- );
399
- if (advanceVar && !advanceMap.get(advanceVar)) {
400
- advanceMap.set(advanceVar, el);
401
- }
402
- const advanceRn = self.returns?.find((ret) => !ret.typeAnnotation && leftCode === ret.name);
403
- if (advanceRn && !advanceMap.get(advanceRn)) {
404
- advanceMap.set(advanceRn, el);
405
- }
406
- });
407
- }
408
- }
409
- });
356
+ yield* reCollectTyInferCtx(advanceMap, callFunctionAdvanceMap, self);
410
357
  code += '{\n';
411
358
  // 用于虚拟节点的查找引用
412
359
  if (Array.isArray(self.virtualParams)) {
@@ -551,7 +498,7 @@ export class AuthLogicForCallInterface extends AuthLogic {
551
498
  && itemNode.typeAnnotation?.typeKind === 'anonymousStructure'
552
499
  )
553
500
  || (
554
- (asserts.isNewList(itemNode) || asserts.isNewMap(itemNode))
501
+ (asserts.isNewList(itemNode) || asserts.isNewMap(itemNode))
555
502
  && !(itemNode?.typeAnnotation)
556
503
  )
557
504
  ) {
@@ -46,6 +46,7 @@ import Variable from './Variable__';
46
46
  import BindEvent from './BindEvent__';
47
47
  import BusinessLogic from './BusinessLogic__';
48
48
  import ViewElement from './ViewElement__';
49
+ import { reCollectTyInferCtx } from '../server/semanticData';
49
50
 
50
51
  /**
51
52
  * 业务组件
@@ -1999,53 +2000,7 @@ export class BusinessComponent extends BaseNode {
1999
2000
 
2000
2001
  const advanceMap: Map<Variable, Assignment | BatchAssignment> = new Map();
2001
2002
  const callFunctionAdvanceMap: Map<Variable, CallFunction> = new Map();
2002
- yield* self.traverseChildrenGenerator(function* traverseChildrenGenerator(el) {
2003
- if (
2004
- el &&
2005
- // 批量赋值
2006
- (asserts.isBatchAssignment(el) ||
2007
- // 赋值
2008
- (asserts.isAssignment(el) && el.left?.name) ||
2009
- // 内置函数对集合类型的推导
2010
- (asserts.isCallFunction(el) && el.derivablecollection?.name))
2011
- ) {
2012
- if (el?.getAncestor('SubLogic')) {
2013
- return;
2014
- }
2015
- if (asserts.isAssignment(el)) {
2016
- const advanceVar = self.variables?.find(
2017
- (variable) => !variable.typeAnnotation && el.left?.name === variable.name,
2018
- );
2019
- if (advanceVar && !advanceMap.get(advanceVar)) {
2020
- advanceMap.set(advanceVar, el);
2021
- }
2022
- } else if (asserts.isCallFunction(el)) {
2023
- // 需要被推导的集合
2024
- const expression = el.derivablecollection;
2025
- const advanceVar = self.variables?.find((variable) => {
2026
- return !variable.typeAnnotation && expression?.name === variable.name;
2027
- });
2028
- if (advanceVar && !callFunctionAdvanceMap.get(advanceVar)) {
2029
- callFunctionAdvanceMap.set(advanceVar, el);
2030
- }
2031
- } else if (asserts.isBatchAssignment(el)) {
2032
- yield* wrapForEach(el.assignmentLines, function* warpForEachGenerator({ leftIndex }) {
2033
- const leftCode =
2034
- leftIndex.length === 1
2035
- ? yield* el.left?.expression?.toEmbeddedTS(shiftState(state, code, { inline: true })) ??
2036
- returnOrigin('')
2037
- : yield* el.left?.members[leftIndex[1]]?.toEmbeddedTS(shiftState(state, code, { inline: true })) ??
2038
- returnOrigin('');
2039
- const advanceVar = self.variables?.find(
2040
- (variable) => !variable.typeAnnotation && leftCode === variable.name,
2041
- );
2042
- if (advanceVar && !advanceMap.get(advanceVar)) {
2043
- advanceMap.set(advanceVar, el);
2044
- }
2045
- });
2046
- }
2047
- }
2048
- });
2003
+ yield* reCollectTyInferCtx(advanceMap, callFunctionAdvanceMap, self);
2049
2004
 
2050
2005
  // 用来储存默认值翻译结构是__IDENTIFIER__或者__IDENTIFIER__()的节点
2051
2006
  const IDENTIFIERMAP = new Set<Variable>();
@@ -2155,7 +2110,7 @@ export class BusinessComponent extends BaseNode {
2155
2110
  && itemNode.typeAnnotation?.typeKind === 'anonymousStructure'
2156
2111
  )
2157
2112
  || (
2158
- (asserts.isNewList(itemNode) || asserts.isNewMap(itemNode))
2113
+ (asserts.isNewList(itemNode) || asserts.isNewMap(itemNode))
2159
2114
  && !(itemNode?.typeAnnotation)
2160
2115
  )
2161
2116
  ) {
@@ -2523,11 +2478,11 @@ export class BusinessComponent extends BaseNode {
2523
2478
  @withSourceMap()
2524
2479
  toTextualNASL(state = createCompilerState()): string {
2525
2480
  let code = '';
2526
-
2481
+
2527
2482
  code += createDecoratorCode(state, this, ['title', 'description']);
2528
2483
 
2529
2484
  code += `viewComponent ${this.name}`;
2530
-
2485
+
2531
2486
  code += `(\n`;
2532
2487
  this.params.forEach((param, index) => {
2533
2488
  code += param.toTextualNASL(shiftState(state, code, { tabSize: state.tabSize + 1 }));
@@ -2551,7 +2506,7 @@ export class BusinessComponent extends BaseNode {
2551
2506
  code += '\n';
2552
2507
  });
2553
2508
  if (this.logics.length) code += '\n';
2554
-
2509
+
2555
2510
  code += this.elements[0].toTextualNASL(shiftState(state, code, { tabSize: state.tabSize + 1 }));
2556
2511
 
2557
2512
  code += `\n${indent(state.tabSize)}}`;