@lcap/nasl 3.8.3-beta.4 → 3.8.3-beta.5
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.
- package/out/common/BaseNode.d.ts +9 -4
- package/out/common/BaseNode.js +73 -18
- package/out/common/BaseNode.js.map +1 -1
- package/out/concepts/App__.js +17 -13
- package/out/concepts/App__.js.map +1 -1
- package/out/concepts/AuthLogicForCallInterface__.js +2 -50
- package/out/concepts/AuthLogicForCallInterface__.js.map +1 -1
- package/out/concepts/BusinessComponent__.js +2 -42
- package/out/concepts/BusinessComponent__.js.map +1 -1
- package/out/concepts/BusinessLogic__.js +2 -50
- package/out/concepts/BusinessLogic__.js.map +1 -1
- package/out/concepts/CallFunction__.d.ts +1 -1
- package/out/concepts/CallFunction__.js +1 -1
- package/out/concepts/CallLogic__.js +2 -2
- package/out/concepts/CallLogic__.js.map +1 -1
- package/out/concepts/Identifier__.d.ts +2 -0
- package/out/concepts/Identifier__.js +51 -5
- package/out/concepts/Identifier__.js.map +1 -1
- package/out/concepts/Logic__.js +6 -101
- package/out/concepts/Logic__.js.map +1 -1
- package/out/concepts/MemberExpression__.d.ts +1 -1
- package/out/concepts/MemberExpression__.js +15 -3
- package/out/concepts/MemberExpression__.js.map +1 -1
- package/out/concepts/OverriddenLogic__.js +2 -50
- package/out/concepts/OverriddenLogic__.js.map +1 -1
- package/out/concepts/ProcessElementV2__.js +4 -0
- package/out/concepts/ProcessElementV2__.js.map +1 -1
- package/out/concepts/ProcessElement__.js +4 -0
- package/out/concepts/ProcessElement__.js.map +1 -1
- package/out/concepts/ProcessV2__.js +4 -0
- package/out/concepts/ProcessV2__.js.map +1 -1
- package/out/concepts/Process__.js +4 -0
- package/out/concepts/Process__.js.map +1 -1
- package/out/concepts/SubLogic__.js +5 -50
- package/out/concepts/SubLogic__.js.map +1 -1
- package/out/concepts/TypeAnnotation__.js +1 -1
- package/out/concepts/TypeAnnotation__.js.map +1 -1
- package/out/concepts/View__.js +10 -49
- package/out/concepts/View__.js.map +1 -1
- package/out/generator/genBundleFiles.js +5 -5
- package/out/generator/permission.js +21 -5
- package/out/generator/permission.js.map +1 -1
- package/out/generator/release-body/body.js.map +1 -1
- package/out/natural/transformTS2UI.js +5 -5
- package/out/natural/transformTS2UI.js.map +1 -1
- package/out/natural/transforms/transform2LogicItem.js +4 -4
- package/out/natural/transforms/transform2LogicItem.js.map +1 -1
- package/out/server/naslServer.js +17 -2
- package/out/server/naslServer.js.map +1 -1
- package/out/server/semanticData.d.ts +32 -0
- package/out/server/semanticData.js +371 -0
- package/out/server/semanticData.js.map +1 -0
- package/out/templator/block2nasl/viewMergeBlock.js +2 -1
- package/out/templator/block2nasl/viewMergeBlock.js.map +1 -1
- package/package.json +1 -1
- package/src/common/BaseNode.ts +106 -36
- package/src/concepts/App__.ts +17 -13
- package/src/concepts/AuthLogicForCallInterface__.ts +3 -56
- package/src/concepts/BusinessComponent__.ts +6 -51
- package/src/concepts/BusinessLogic__.ts +4 -56
- package/src/concepts/CallFunction__.ts +1 -1
- package/src/concepts/CallLogic__.ts +8 -4
- package/src/concepts/Identifier__.ts +57 -6
- package/src/concepts/Logic__.ts +9 -111
- package/src/concepts/MemberExpression__.ts +21 -7
- package/src/concepts/OverriddenLogic__.ts +4 -56
- package/src/concepts/ProcessElementV2__.ts +4 -0
- package/src/concepts/ProcessElement__.ts +4 -0
- package/src/concepts/ProcessV2__.ts +5 -0
- package/src/concepts/Process__.ts +4 -0
- package/src/concepts/SubLogic__.ts +6 -56
- package/src/concepts/TypeAnnotation__.ts +1 -1
- package/src/concepts/View__.ts +14 -54
- package/src/generator/genBundleFiles.ts +5 -5
- package/src/generator/permission.ts +23 -5
- package/src/generator/release-body/body.ts +0 -1
- package/src/natural/transformTS2UI.ts +5 -5
- package/src/natural/transforms/transform2LogicItem.ts +4 -4
- package/src/server/naslServer.ts +22 -2
- package/src/server/semanticData.ts +447 -0
- package/src/templator/block2nasl/viewMergeBlock.ts +2 -1
- package/src/translator/utils.ts +1 -1
- package/test/concepts/logic/__snapshots__/toEmbeddedTS.spec.ts.snap +182 -0
- package/test/concepts/logic/constant.ts +5 -0
- package/test/concepts/logic/fixtures/variable-host-call-logic-member-expression.json +267 -0
- package/test/concepts/logic/fixtures/variable-host-call-logic-nested-member-expression copy.json +457 -0
- package/test/concepts/logic/fixtures/variable-host-call-logic-with-handle-error-member-expression.json +267 -0
- package/test/concepts/logic/toEmbeddedTS.spec.ts +15 -0
package/src/server/naslServer.ts
CHANGED
|
@@ -124,6 +124,8 @@ import { withQueueExecute } from '../decorators';
|
|
|
124
124
|
import { getNodeByNodeCallee } from '../automate/engine/utils';
|
|
125
125
|
import { isApp, isConnection, isConnector, isMsgTriggerEvent, isProcess, isProcessV2, isStrictLogic } from '../concepts/utils/asserts';
|
|
126
126
|
|
|
127
|
+
import { collectAllSemanticCtx, clearSemanticData, printSemanticDataInfo } from './semanticData';
|
|
128
|
+
|
|
127
129
|
const EmbeddedTSFileLineMap: { [name: string]: number } = {
|
|
128
130
|
Entity: 3,
|
|
129
131
|
};
|
|
@@ -649,6 +651,10 @@ class NaslServer {
|
|
|
649
651
|
|
|
650
652
|
async openApp(app: App, performance = false, needRegisterCommand = true) {
|
|
651
653
|
this.logger.time('生成 TS 文件');
|
|
654
|
+
this.logger.time('简单语义分析');
|
|
655
|
+
await utils.runGeneratorSync(collectAllSemanticCtx(app));
|
|
656
|
+
this.logger.timeEnd('简单语义分析');
|
|
657
|
+
// printSemanticDataInfo();
|
|
652
658
|
invokeCommand('naslServer:startWork');
|
|
653
659
|
|
|
654
660
|
app.naslServer = this;
|
|
@@ -677,6 +683,7 @@ class NaslServer {
|
|
|
677
683
|
callback();
|
|
678
684
|
});
|
|
679
685
|
}
|
|
686
|
+
clearSemanticData();
|
|
680
687
|
this.logger.timeEnd('生成 TS 文件');
|
|
681
688
|
|
|
682
689
|
function* getAllTsFiles() {
|
|
@@ -1121,7 +1128,9 @@ class NaslServer {
|
|
|
1121
1128
|
return;
|
|
1122
1129
|
}
|
|
1123
1130
|
|
|
1124
|
-
|
|
1131
|
+
let { node } = record;
|
|
1132
|
+
// @ts-ignore
|
|
1133
|
+
node = node.__v_raw || node; // 暂时先这样提速
|
|
1125
1134
|
|
|
1126
1135
|
// 先获取原来的节点先清除一下之前有异常的节点,下面重新赋值
|
|
1127
1136
|
const oldRecord = self.diagnosticManager.getRecord?.(record.id);
|
|
@@ -1815,6 +1824,8 @@ class NaslServer {
|
|
|
1815
1824
|
*/
|
|
1816
1825
|
private *_attachDiagnosticsWithGenerator(fileNode: BaseNode) {
|
|
1817
1826
|
// 每次诊断前先清空这个Set
|
|
1827
|
+
// @ts-ignore
|
|
1828
|
+
fileNode = fileNode.__v_raw || fileNode; // 暂时先这样提速
|
|
1818
1829
|
this.logicSetWithComponentLogic = new Set<string>();
|
|
1819
1830
|
|
|
1820
1831
|
const self = this;
|
|
@@ -3197,11 +3208,15 @@ class NaslServer {
|
|
|
3197
3208
|
fileNode: FileNode
|
|
3198
3209
|
): Generator<void, MinRange> {
|
|
3199
3210
|
let minRange: MinRange;
|
|
3211
|
+
// @ts-ignore
|
|
3212
|
+
fileNode = fileNode.__v_raw || fileNode; // 暂时先这样提速
|
|
3200
3213
|
const { sourceMap } = fileNode;
|
|
3201
3214
|
// 是否找到了行内准确的,是的话,就不走多行的
|
|
3202
3215
|
let haveLineNode = false;
|
|
3203
3216
|
|
|
3204
|
-
for (
|
|
3217
|
+
for (let [node, item] of sourceMap.entries()) {
|
|
3218
|
+
// @ts-ignore
|
|
3219
|
+
node = node.__v_raw || node; // 暂时先这样提速
|
|
3205
3220
|
/**
|
|
3206
3221
|
* 当前内容的开始行 <= 诊断开始的行 &&
|
|
3207
3222
|
* 当前内容的结束行 >= 诊断结束的行
|
|
@@ -4663,6 +4678,7 @@ class NaslServer {
|
|
|
4663
4678
|
}
|
|
4664
4679
|
if (
|
|
4665
4680
|
![
|
|
4681
|
+
|
|
4666
4682
|
'Identifier',
|
|
4667
4683
|
'BinaryExpression',
|
|
4668
4684
|
'CallLogic',
|
|
@@ -4775,8 +4791,10 @@ class NaslServer {
|
|
|
4775
4791
|
}
|
|
4776
4792
|
}
|
|
4777
4793
|
});
|
|
4794
|
+
|
|
4778
4795
|
yield* utils.wrapIteratorToGenerator(types.entries(), ([node, value]) => {
|
|
4779
4796
|
try {
|
|
4797
|
+
|
|
4780
4798
|
// 因为node可能是经过处理的TypeAnnotation
|
|
4781
4799
|
node.__isCorrectTypeAnnotation = true;
|
|
4782
4800
|
if (value) {
|
|
@@ -5492,6 +5510,7 @@ class NaslServer {
|
|
|
5492
5510
|
*/
|
|
5493
5511
|
async handleRename(fileNode: BaseNode, targetNode: BaseNode, result: utils.EmbeddedTSFileResult, oldFilePath?: string) {
|
|
5494
5512
|
// rename 场景
|
|
5513
|
+
|
|
5495
5514
|
const outputFiles = [{ file: result.filePath, fileContent: result.code }];
|
|
5496
5515
|
// 如果是要修改顶级文件名
|
|
5497
5516
|
// file节点和当前改得是同一节点
|
|
@@ -5798,6 +5817,7 @@ class NaslServer {
|
|
|
5798
5817
|
|
|
5799
5818
|
changeFileNext() {
|
|
5800
5819
|
if (!this.singleFileChangeIng) {
|
|
5820
|
+
// SHIFT IS O(n) AND SLOW
|
|
5801
5821
|
const item = this.changeStackList.shift();
|
|
5802
5822
|
this.receiveHandleChange(item)
|
|
5803
5823
|
.catch((err) => {
|
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
import { App, Identifier, MemberExpression, View, ViewElement, BaseNode, Return, Variable,
|
|
2
|
+
Assignment, BatchAssignment, CallFunction, AuthLogicForCallInterface, BusinessComponent, BusinessLogic,
|
|
3
|
+
Logic, OverriddenLogic, SubLogic,
|
|
4
|
+
Process,
|
|
5
|
+
ProcessV2,
|
|
6
|
+
ProcessElement,
|
|
7
|
+
ProcessElementV2,
|
|
8
|
+
} from '..';
|
|
9
|
+
|
|
10
|
+
import { SyntaxNode } from '../concepts/utils/types';
|
|
11
|
+
|
|
12
|
+
import { createCompilerState, shiftState } from '../translator';
|
|
13
|
+
import { runGeneratorAsync, runGeneratorSync, wrapForEachToGenerator, returnOrigin } from '../utils';
|
|
14
|
+
|
|
15
|
+
type VarScopeCtx = {
|
|
16
|
+
// 优化首屏 getAncestor 热点代码
|
|
17
|
+
app: App;
|
|
18
|
+
isFirstScreen: boolean;
|
|
19
|
+
frontendGlobalVars: Set<string>;
|
|
20
|
+
varInViewOrComponent: Set<string>;
|
|
21
|
+
logicInViewOrComponent: Set<string>;
|
|
22
|
+
idToView: Map<Identifier, View>;
|
|
23
|
+
ctxViewElement: Array<ViewElement>;
|
|
24
|
+
ctxView: Array<View>;
|
|
25
|
+
isInViewOrComponent: boolean;
|
|
26
|
+
memExprToViewElem: Map<MemberExpression, ViewElement>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
type TyInferCtx = {
|
|
30
|
+
// 优化首屏 类型推导,变量提升
|
|
31
|
+
inferViaAsgnMap: Map<Return | Variable , Assignment | BatchAssignment | CallFunction>,
|
|
32
|
+
inferViaFnCallMap: Map<Return | Variable , CallFunction>,
|
|
33
|
+
scope: Array<AuthLogicForCallInterface | BusinessComponent | BusinessLogic | Logic | OverriddenLogic | SubLogic | View>,
|
|
34
|
+
// key 用 name 是不精确的,应该用地址。 暂时用 name,后面比较的时候简单点,暂时应该没 bug
|
|
35
|
+
// 全局变量暂不支持推导
|
|
36
|
+
capturedVars: Map<string, Variable | Return>,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
type SubLogicCtx = {
|
|
40
|
+
// naslNodesCount: number;
|
|
41
|
+
ctx: Logic | Process | ProcessV2 | ProcessElement | ProcessElementV2 | null;
|
|
42
|
+
// 我也不知道为啥 view 这么特殊
|
|
43
|
+
viewSubLogics: Set<SubLogic>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 前端全局变量很少,一般就十个以内,所以 map 大小可以忽略不计
|
|
47
|
+
export const varScopeCtx : VarScopeCtx = {
|
|
48
|
+
app: null,
|
|
49
|
+
isFirstScreen: false,
|
|
50
|
+
frontendGlobalVars: new Set<string>(),
|
|
51
|
+
// Collect all params, (local) variables, and logic names under business component
|
|
52
|
+
// Note that within a business component, one can only refer to the above variables, and cannot refer to
|
|
53
|
+
// frontend global variables and any other variables under Views; therefore, checking the Name already suffices.
|
|
54
|
+
// 收集业务组件下的所有参数、(局部)变量和逻辑名称,请注意,在业务组件中,只能引用上述变量,
|
|
55
|
+
// 而不能引用前端全局变量和其他任何 “视图 ”下的变量;因此,检查 “Name” 已经足够了。
|
|
56
|
+
varInViewOrComponent: new Set<string>(),
|
|
57
|
+
|
|
58
|
+
logicInViewOrComponent: new Set<string>(),
|
|
59
|
+
|
|
60
|
+
// Collect all params, (local) variables, and logic names under views
|
|
61
|
+
// Actually, frontendGlobalVars U idInView U idInComponent should be the complete set of accessible variables
|
|
62
|
+
// 事实上,frontendGlobalVars 并上 idInView 并上 idInComponent 应该是前端所有能访问到的变量(名的集合)
|
|
63
|
+
|
|
64
|
+
// 赫基 27w 应用,前端 View 下有 2000 个变量名字;56176 个变量引用,内存占用约 1M。
|
|
65
|
+
idToView: new Map<Identifier, View>(),
|
|
66
|
+
|
|
67
|
+
// 路径上的 ViewElement 节点
|
|
68
|
+
ctxViewElement: [],
|
|
69
|
+
|
|
70
|
+
// 路径上的 View 节点
|
|
71
|
+
ctxView: [],
|
|
72
|
+
|
|
73
|
+
isInViewOrComponent: false,
|
|
74
|
+
|
|
75
|
+
memExprToViewElem: new Map<MemberExpression, ViewElement>(),
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const tyInferCtx : TyInferCtx = {
|
|
79
|
+
inferViaAsgnMap: new Map(),
|
|
80
|
+
inferViaFnCallMap: new Map(),
|
|
81
|
+
scope: [],
|
|
82
|
+
capturedVars: new Map(),
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export const subLogicCtx : SubLogicCtx = {
|
|
86
|
+
// naslNodesCount: 0,
|
|
87
|
+
ctx: null, // 当前逻辑
|
|
88
|
+
viewSubLogics : new Set<SubLogic>(), // 隶属于 view 的 SubLogic,需要排除掉隶属于 Logic 的 SubLogic。
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const last = <T>(arr: Array<T>) => arr[arr.length - 1];
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
export function *collectAllSemanticCtx(app: App) {
|
|
95
|
+
varScopeCtx.app = app;
|
|
96
|
+
varScopeCtx.isFirstScreen = true;
|
|
97
|
+
const tasks = [
|
|
98
|
+
// collectFrontendVariablesTask, 这样不值得,能快一点还是快一点吧,
|
|
99
|
+
collectVarInViewOrComponentCtxTask,
|
|
100
|
+
collectLogicInViewOrComponentTask,
|
|
101
|
+
// collectMemExprToViewElemCtxTask, // 因为 $ce 的原因,暂时用不了
|
|
102
|
+
collectIdToViewCtxTask,
|
|
103
|
+
collectSubLogicCtxTask,
|
|
104
|
+
collectTyInferCtxTask
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
const cleanups = [
|
|
108
|
+
collectVarInViewOrComponentCtxCleanup,
|
|
109
|
+
// collectLogicInViewOrComponentCleanup,
|
|
110
|
+
// collectMemExprToViewElemCtxCleanup, // 因为 $ce 的原因,暂时用不了
|
|
111
|
+
collectIdToViewCtxCleanup,
|
|
112
|
+
collectSubLogicCtxCleanup,
|
|
113
|
+
collectTyInferCtxCleanup
|
|
114
|
+
];
|
|
115
|
+
|
|
116
|
+
runGeneratorSync(collectFrontendVariablesTask(app));
|
|
117
|
+
runGeneratorSync(app.traverseStrictChildrenDoMultiTasks(tasks, cleanups));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
function *collectFrontendVariablesTask(app: App) {
|
|
122
|
+
app.frontendTypes.forEach(ft => {
|
|
123
|
+
ft.frontends.forEach(f => {
|
|
124
|
+
f.variables.forEach(v => {
|
|
125
|
+
varScopeCtx.frontendGlobalVars.add(v.name);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
})
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function *collectVarInViewOrComponentCtxTask(nd: SyntaxNode) {
|
|
132
|
+
switch (nd.concept) {
|
|
133
|
+
case 'Variable': /* FALL THROUGH */
|
|
134
|
+
case 'Param': /* FALL THROUGH */
|
|
135
|
+
case 'Return': {
|
|
136
|
+
if (varScopeCtx.isInViewOrComponent) {
|
|
137
|
+
varScopeCtx.varInViewOrComponent.add(nd.name);
|
|
138
|
+
}
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
case 'View': /* FALL THROUGH */
|
|
142
|
+
case 'BusinessComponent': varScopeCtx.isInViewOrComponent = true; break;
|
|
143
|
+
default: break;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function *collectVarInViewOrComponentCtxCleanup(nd: SyntaxNode) {
|
|
148
|
+
if (nd.concept === 'View' || nd.concept === 'BusinessComponent') {
|
|
149
|
+
varScopeCtx.isInViewOrComponent = false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
// component-like:业务组件下的变量引用
|
|
155
|
+
function *collectLogicInViewOrComponentTask(nd: SyntaxNode) {
|
|
156
|
+
if (nd.concept === 'Logic' || nd.concept === 'BusinessComponent') {
|
|
157
|
+
if (varScopeCtx.isInViewOrComponent) {
|
|
158
|
+
varScopeCtx.logicInViewOrComponent.add(nd.name);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// collectLogicInViewOrComponentCleanup 的事情被 collectVarInViewOrComponentCtxPost 做了
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
function *collectMemExprToViewElemCtxTask(nd: SyntaxNode) {
|
|
166
|
+
// view 下的 identifier 的 getAncestor 必定有 view
|
|
167
|
+
switch (nd.concept) {
|
|
168
|
+
case 'ViewElement': {
|
|
169
|
+
varScopeCtx.ctxViewElement.push(nd as ViewElement);
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
case 'MemberExpression': {
|
|
173
|
+
if (varScopeCtx.ctxViewElement) {
|
|
174
|
+
varScopeCtx.memExprToViewElem.set(nd as MemberExpression, last(varScopeCtx.ctxViewElement));
|
|
175
|
+
}
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
default: break;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function *collectMemExprToViewElemCtxCleanup(nd: SyntaxNode) {
|
|
183
|
+
if (nd.concept === 'ViewElement') {
|
|
184
|
+
varScopeCtx.ctxViewElement.pop();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
function *collectIdToViewCtxTask(nd: SyntaxNode) {
|
|
190
|
+
// view 下的 identifier 的 getAncestor 必定有 view
|
|
191
|
+
switch (nd.concept) {
|
|
192
|
+
case 'View': varScopeCtx.ctxView.push(nd); break;
|
|
193
|
+
case 'Identifier': {
|
|
194
|
+
if (varScopeCtx.ctxView.length > 0) {
|
|
195
|
+
varScopeCtx.idToView.set(nd as Identifier, last(varScopeCtx.ctxView));
|
|
196
|
+
}
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
default: break;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function *collectIdToViewCtxCleanup(nd: SyntaxNode) {
|
|
204
|
+
switch (nd.concept) {
|
|
205
|
+
case 'View': varScopeCtx.ctxView.pop(); break;
|
|
206
|
+
default: break;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
function *collectSubLogicCtxTask(nd : SyntaxNode) {
|
|
212
|
+
switch (nd.concept) {
|
|
213
|
+
case 'Logic': /* FALL THROUGH */
|
|
214
|
+
/* 流程支持子逻辑 */
|
|
215
|
+
/* 流程变量不支持类型推导 */
|
|
216
|
+
case 'Process': /* FALL THROUGH */
|
|
217
|
+
case 'ProcessV2': /* FALL THROUGH */
|
|
218
|
+
case 'ProcessElement': /* FALL THROUGH */
|
|
219
|
+
case 'ProcessElementV2': /* FALL THROUGH */
|
|
220
|
+
case 'BusinessLogic': subLogicCtx.ctx = nd; break;
|
|
221
|
+
case 'SubLogic': {
|
|
222
|
+
// 收集子逻辑
|
|
223
|
+
if (subLogicCtx.ctx) {
|
|
224
|
+
subLogicCtx.ctx.subLogics.push(nd as SubLogic);
|
|
225
|
+
// console.log('逻辑或流程的子逻辑:', subLogicCtx.ctx)
|
|
226
|
+
} else {
|
|
227
|
+
subLogicCtx.viewSubLogics.add(nd as SubLogic);
|
|
228
|
+
}
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
default: break;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function *collectSubLogicCtxCleanup(nd : SyntaxNode) {
|
|
236
|
+
switch (nd.concept) {
|
|
237
|
+
/* 流程支持子逻辑 */
|
|
238
|
+
/* 流程变量不支持类型推导 */
|
|
239
|
+
case 'Logic': /* FALL THROUGH */
|
|
240
|
+
case 'Process': /* FALL THROUGH */
|
|
241
|
+
case 'ProcessV2': /* FALL THROUGH */
|
|
242
|
+
case 'ProcessElement': /* FALL THROUGH */
|
|
243
|
+
case 'ProcessElementV2': subLogicCtx.ctx = null; break;
|
|
244
|
+
// 可能是有人忘了给业务组件加 subLogics?
|
|
245
|
+
case 'View': {
|
|
246
|
+
subLogicCtx.viewSubLogics.forEach(sl => { nd.subLogics.push(sl); });
|
|
247
|
+
// console.log('View 的子逻辑:', nd.subLogics)
|
|
248
|
+
subLogicCtx.viewSubLogics.clear();
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
default: break;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
const addVars = (nd : Array<Variable> | Array<Return>, s : Map<string, Variable | Return>) => {
|
|
257
|
+
nd.forEach(v => {
|
|
258
|
+
if (!v.typeAnnotation) {
|
|
259
|
+
s.set(v.name, v);
|
|
260
|
+
}
|
|
261
|
+
})
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const removeVars = (nd : Array<Variable> | Array<Return>, s : Map<string, Variable | Return>) => {
|
|
265
|
+
nd.forEach(v => s.delete(v.name))
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
// OQL 批量优化优化完成前请勿移除
|
|
270
|
+
// const oqlSet = new Set<string>();
|
|
271
|
+
|
|
272
|
+
function *collectTyInferCtxTask(nd : SyntaxNode) {
|
|
273
|
+
// ++subLogicCtx.naslNodesCount;
|
|
274
|
+
// if (nd.concept === 'OqlQueryComponent') {
|
|
275
|
+
// oqlSet.add(nd.code);
|
|
276
|
+
// }
|
|
277
|
+
switch (nd.concept) {
|
|
278
|
+
case 'Logic': /* FALL THROUGH */
|
|
279
|
+
case 'AuthLogicForCallInterface': /* FALL THROUGH */
|
|
280
|
+
case 'BusinessLogic': /* FALL THROUGH */
|
|
281
|
+
case 'OverriddenLogic': /* FALL THROUGH */
|
|
282
|
+
case 'SubLogic': {
|
|
283
|
+
// 全局变量不支持类型推导;逻辑的变量也不支持跨子逻辑推导
|
|
284
|
+
// addVars(nd.variables, tyInferCtx.capturedVars);
|
|
285
|
+
// addVars(nd.returns, tyInferCtx.capturedVars);
|
|
286
|
+
tyInferCtx.scope.push(nd);
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
case 'View': /* FALL THROUGH */
|
|
290
|
+
case 'BusinessComponent': {
|
|
291
|
+
addVars(nd.variables, tyInferCtx.capturedVars);
|
|
292
|
+
tyInferCtx.scope.push(nd);
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
default: {
|
|
296
|
+
runGeneratorAsync(
|
|
297
|
+
collectAsgn(tyInferCtx.inferViaAsgnMap, tyInferCtx.inferViaFnCallMap, nd));
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function *collectTyInferCtxCleanup(nd : SyntaxNode) {
|
|
304
|
+
switch (nd.concept) {
|
|
305
|
+
case 'Logic': /* FALL THROUGH */
|
|
306
|
+
case 'AuthLogicForCallInterface': /* FALL THROUGH */
|
|
307
|
+
case 'BusinessLogic': /* FALL THROUGH */
|
|
308
|
+
case 'OverriddenLogic': /* FALL THROUGH */
|
|
309
|
+
case 'SubLogic': {
|
|
310
|
+
// removeVars(nd.variables, tyInferCtx.capturedVars);
|
|
311
|
+
// removeVars(nd.returns, tyInferCtx.capturedVars);
|
|
312
|
+
tyInferCtx.scope.pop();
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
case 'View': /* FALL THROUGH */
|
|
317
|
+
case 'BusinessComponent': {
|
|
318
|
+
removeVars(nd.variables, tyInferCtx.capturedVars);
|
|
319
|
+
tyInferCtx.scope.pop();
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
default: break;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
type LogicContainer = AuthLogicForCallInterface | BusinessComponent | BusinessLogic | Logic | OverriddenLogic | SubLogic | View;
|
|
328
|
+
|
|
329
|
+
export function *reCollectTyInferCtx(
|
|
330
|
+
inferViaAsgn: Map<Return | Variable, Assignment | BatchAssignment | CallFunction>,
|
|
331
|
+
inferViaFnCall: Map<Return | Variable, CallFunction>,
|
|
332
|
+
self: LogicContainer) {
|
|
333
|
+
|
|
334
|
+
// No (types of) variables to be inferred
|
|
335
|
+
// @ts-ignore
|
|
336
|
+
const preTest = self.variables?.some((v : Variable) => !v.typeAnnotation) || self.returns?.some((v : Variable) => !v.typeAnnotation)
|
|
337
|
+
if (!preTest) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// 非首次则清空脏 map,重新收集所需上下文
|
|
342
|
+
if (!varScopeCtx.isFirstScreen) {
|
|
343
|
+
tyInferCtx.inferViaAsgnMap.clear();
|
|
344
|
+
tyInferCtx.inferViaFnCallMap.clear();
|
|
345
|
+
yield* self.traverseChildrenGenerator(collectTyInferCtxTask);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
self.variables.forEach((locVar : Variable) => {
|
|
349
|
+
if (tyInferCtx.inferViaAsgnMap.has(locVar)){
|
|
350
|
+
inferViaAsgn.set(locVar, tyInferCtx.inferViaAsgnMap.get(locVar))
|
|
351
|
+
} else if (tyInferCtx.inferViaFnCallMap.has(locVar)){
|
|
352
|
+
inferViaFnCall.set(locVar, tyInferCtx.inferViaFnCallMap.get(locVar))
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
// @ts-ignore
|
|
356
|
+
self.returns?.forEach((locRet : Return) => {
|
|
357
|
+
if (tyInferCtx.inferViaAsgnMap.has(locRet)){
|
|
358
|
+
inferViaAsgn.set(locRet, tyInferCtx.inferViaAsgnMap.get(locRet))
|
|
359
|
+
} else if (tyInferCtx.inferViaFnCallMap.has(locRet)){
|
|
360
|
+
inferViaFnCall.set(locRet, tyInferCtx.inferViaFnCallMap.get(locRet))
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function *collectAsgn(
|
|
366
|
+
inferViaAsgnMap: Map<Return | Variable, Assignment | BatchAssignment | CallFunction>,
|
|
367
|
+
inferViaBuiltinFnMap: Map<Return | Variable, CallFunction>,
|
|
368
|
+
nd: SyntaxNode) {
|
|
369
|
+
const self = last(tyInferCtx.scope); // 可能是 undefined
|
|
370
|
+
if (!nd || !self) {
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (nd.concept === 'Assignment' && nd.left?.name) {
|
|
375
|
+
if (!self) {
|
|
376
|
+
console.log('nd', nd)
|
|
377
|
+
}
|
|
378
|
+
const hoistVar = self.variables?.find(v => nd.left?.name === v.name && !v.typeAnnotation)
|
|
379
|
+
// View 和 BusinessComponent 没有 returns
|
|
380
|
+
// @ts-ignore
|
|
381
|
+
?? self.returns?.find(ret => nd.left?.name === ret.name && !ret.typeAnnotation)
|
|
382
|
+
?? tyInferCtx.capturedVars.get(nd.left.name);
|
|
383
|
+
if (hoistVar && !inferViaAsgnMap.has(hoistVar)) {
|
|
384
|
+
inferViaAsgnMap.set(hoistVar, nd);
|
|
385
|
+
}
|
|
386
|
+
} else if (nd.concept === 'BatchAssignment') {
|
|
387
|
+
yield* wrapForEachToGenerator(nd.assignmentLines, function* warpForEachGenerator({ leftIndex }) {
|
|
388
|
+
const leftCode =
|
|
389
|
+
leftIndex.length === 1
|
|
390
|
+
? yield* nd.left.expression.toEmbeddedTS(shiftState(createCompilerState(), '', { inline: true }))
|
|
391
|
+
: yield* nd.left.members[leftIndex[1]]?.toEmbeddedTS(shiftState(createCompilerState(), '', { inline: true })) ??
|
|
392
|
+
returnOrigin('');
|
|
393
|
+
const hoistVar = self.variables?.find((v : Variable) => leftCode === v.name && !v.typeAnnotation)
|
|
394
|
+
// View 和 BusinessComponent 没有 returns
|
|
395
|
+
// @ts-ignore
|
|
396
|
+
?? self.returns?.find(ret => leftCode === ret.name && !ret.typeAnnotation)
|
|
397
|
+
?? tyInferCtx.capturedVars.get(leftCode);
|
|
398
|
+
if (hoistVar && !inferViaAsgnMap.has(hoistVar)) {
|
|
399
|
+
inferViaAsgnMap.set(hoistVar, nd);
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
} else if (nd.concept === 'CallFunction' && nd.derivableCollection?.name) {
|
|
403
|
+
// 需要被推导的集合
|
|
404
|
+
const expr = nd.derivableCollection;
|
|
405
|
+
// 宽泛意义上的变量(变量+出参),View 和 BusinessComponent 没有 returns
|
|
406
|
+
const hoistVar = self.variables.find((v) => expr?.name === v.name && !v.typeAnnotation)
|
|
407
|
+
// @ts-ignore
|
|
408
|
+
?? self.returns?.find(ret => expr?.name === ret.name && !ret.typeAnnotation)
|
|
409
|
+
?? tyInferCtx.capturedVars.get(expr.name);
|
|
410
|
+
if (hoistVar && !inferViaBuiltinFnMap.has(hoistVar)) {
|
|
411
|
+
inferViaBuiltinFnMap.set(hoistVar, nd);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
export const clearSemanticData = () => {
|
|
417
|
+
varScopeCtx.isFirstScreen = false;
|
|
418
|
+
varScopeCtx.frontendGlobalVars.clear();
|
|
419
|
+
varScopeCtx.varInViewOrComponent.clear();
|
|
420
|
+
varScopeCtx.logicInViewOrComponent.clear();
|
|
421
|
+
varScopeCtx.idToView.clear();
|
|
422
|
+
varScopeCtx.ctxViewElement = [];
|
|
423
|
+
varScopeCtx.memExprToViewElem.clear();
|
|
424
|
+
tyInferCtx.inferViaAsgnMap.clear();
|
|
425
|
+
tyInferCtx.inferViaFnCallMap.clear();
|
|
426
|
+
tyInferCtx.scope = [];
|
|
427
|
+
tyInferCtx.capturedVars.clear();
|
|
428
|
+
subLogicCtx.viewSubLogics.clear();
|
|
429
|
+
subLogicCtx.ctx = null;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
export function printSemanticDataInfo() {
|
|
433
|
+
console.log('frontendGlobalVars', varScopeCtx.frontendGlobalVars)
|
|
434
|
+
console.log('varInViewOrComponent', varScopeCtx.varInViewOrComponent)
|
|
435
|
+
console.log('logicInViewOrComponent', varScopeCtx.logicInViewOrComponent)
|
|
436
|
+
console.log('idToView', varScopeCtx.idToView)
|
|
437
|
+
console.log('memExprToViewElem', varScopeCtx.memExprToViewElem)
|
|
438
|
+
console.log('inferViaAsgnMap', tyInferCtx.inferViaAsgnMap)
|
|
439
|
+
console.log('inferViaFnCallMap', tyInferCtx.inferViaFnCallMap)
|
|
440
|
+
// console.log(oqlSet)
|
|
441
|
+
// console.log('capturedVars', tyInferCtx.capturedVars)
|
|
442
|
+
// console.log('viewSubLogics', subLogicCtx.viewSubLogics)
|
|
443
|
+
// console.log('naslNodesCount', subLogicCtx.naslNodesCount)
|
|
444
|
+
// console.log('ctx', subLogicCtx.ctx)
|
|
445
|
+
// console.log('scope', tyInferCtx.scope)
|
|
446
|
+
// console.log('isFirstScreen', varScopeCtx.isFirstScreen)
|
|
447
|
+
}
|
|
@@ -37,7 +37,8 @@ export function viewMergeBlock({
|
|
|
37
37
|
const naslCode = tryTransformBlock2Nasl(code);
|
|
38
38
|
const blockView = naslCode.view;
|
|
39
39
|
// vue2需要对tag进行转换 kebab-case
|
|
40
|
-
|
|
40
|
+
const frontendType = (view as any)?.getAncestor('FrontendType');
|
|
41
|
+
if((frontendType as any)?.frameworkKind === 'vue2') {
|
|
41
42
|
traverse(({ node }) => {
|
|
42
43
|
if (node.concept === 'ViewElement') {
|
|
43
44
|
node.tag = Camel2kebab(node.tag);
|
package/src/translator/utils.ts
CHANGED