@jay-framework/compiler 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +77 -0
- package/dist/index.js +1918 -0
- package/package.json +55 -0
- package/readme.md +41 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1918 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
|
+
var __publicField = (obj, key, value) => {
|
|
5
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
6
|
+
return value;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
9
|
+
const ts = require("typescript");
|
|
10
|
+
const compilerShared = require("@jay-framework/compiler-shared");
|
|
11
|
+
const changeCase = require("change-case");
|
|
12
|
+
const path = require("node:path");
|
|
13
|
+
const compilerJayHtml = require("@jay-framework/compiler-jay-html");
|
|
14
|
+
function _interopNamespaceDefault(e) {
|
|
15
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
16
|
+
if (e) {
|
|
17
|
+
for (const k in e) {
|
|
18
|
+
if (k !== "default") {
|
|
19
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
20
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
get: () => e[k]
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
n.default = e;
|
|
28
|
+
return Object.freeze(n);
|
|
29
|
+
}
|
|
30
|
+
const ts__namespace = /* @__PURE__ */ _interopNamespaceDefault(ts);
|
|
31
|
+
const printer = ts.createPrinter({
|
|
32
|
+
newLine: ts.NewLineKind.LineFeed
|
|
33
|
+
});
|
|
34
|
+
function astToCode(node) {
|
|
35
|
+
return printer.printNode(ts.EmitHint.Unspecified, node, void 0);
|
|
36
|
+
}
|
|
37
|
+
function codeToAst(code, context) {
|
|
38
|
+
let dummySourceFile = ts.createSourceFile("dummy.ts", code, ts.ScriptTarget.Latest, true);
|
|
39
|
+
function visitor(node) {
|
|
40
|
+
let updatedNode = ts.setTextRange(node, { pos: -1, end: -1 });
|
|
41
|
+
return ts.visitEachChild(updatedNode, visitor, context);
|
|
42
|
+
}
|
|
43
|
+
return ts.visitEachChild(dummySourceFile, visitor, context).statements;
|
|
44
|
+
}
|
|
45
|
+
function isFunctionLikeDeclarationBase(node) {
|
|
46
|
+
return ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node) || ts.isConstructorDeclaration(node) || ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node);
|
|
47
|
+
}
|
|
48
|
+
function mkTransformer(fileTransformer, config) {
|
|
49
|
+
return (context) => {
|
|
50
|
+
const { factory } = context;
|
|
51
|
+
return (sourceFile) => {
|
|
52
|
+
return fileTransformer({ factory, context, sourceFile, ...config || {} });
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function extractImportDeclarations(sourceFile) {
|
|
57
|
+
const importDeclarations = [];
|
|
58
|
+
function visit(node) {
|
|
59
|
+
if (ts__namespace.isImportDeclaration(node)) {
|
|
60
|
+
importDeclarations.push(node);
|
|
61
|
+
}
|
|
62
|
+
ts__namespace.forEachChild(node, visit);
|
|
63
|
+
}
|
|
64
|
+
ts__namespace.forEachChild(sourceFile, visit);
|
|
65
|
+
return importDeclarations;
|
|
66
|
+
}
|
|
67
|
+
function extractImportedModules(sourceFile) {
|
|
68
|
+
return extractImportDeclarations(sourceFile).filter((node) => ts__namespace.isStringLiteral(node.moduleSpecifier)).map((node) => node.moduleSpecifier.text);
|
|
69
|
+
}
|
|
70
|
+
function isRelativeImport(module2) {
|
|
71
|
+
return module2.startsWith(".");
|
|
72
|
+
}
|
|
73
|
+
function getImportSpecifiers(importDeclaration) {
|
|
74
|
+
const namedBindings = importDeclaration.importClause?.namedBindings;
|
|
75
|
+
return namedBindings && ts__namespace.isNamedImports(namedBindings) ? namedBindings.elements : void 0;
|
|
76
|
+
}
|
|
77
|
+
function getImportName(importSpecifier) {
|
|
78
|
+
return importSpecifier.propertyName?.text ?? importSpecifier.name.text;
|
|
79
|
+
}
|
|
80
|
+
function findMakeJayComponentImport(makeJayComponentName, node) {
|
|
81
|
+
if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier) && node.moduleSpecifier.text === compilerShared.JAY_COMPONENT) {
|
|
82
|
+
let importSpecifier = getImportSpecifiers(node)?.find(
|
|
83
|
+
(element) => getImportName(element) === makeJayComponentName
|
|
84
|
+
);
|
|
85
|
+
if (importSpecifier) {
|
|
86
|
+
return importSpecifier.name.text;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return void 0;
|
|
90
|
+
}
|
|
91
|
+
function findComponentConstructorsBlock(componentFunctionExpressions, sourceFile) {
|
|
92
|
+
const foundConstructors = [];
|
|
93
|
+
const namedConstructors = new Set(
|
|
94
|
+
componentFunctionExpressions.filter((expression) => ts.isIdentifier(expression)).map((expression) => ts.isIdentifier(expression) && expression.text)
|
|
95
|
+
);
|
|
96
|
+
const inlineConstructors = componentFunctionExpressions.filter(
|
|
97
|
+
isFunctionLikeDeclarationBase
|
|
98
|
+
);
|
|
99
|
+
function visit(node) {
|
|
100
|
+
if (ts.isFunctionDeclaration(node)) {
|
|
101
|
+
if (namedConstructors.has(node?.name.text))
|
|
102
|
+
foundConstructors.push(node);
|
|
103
|
+
} else if (ts.isVariableStatement(node)) {
|
|
104
|
+
node.declarationList.declarations.forEach((declaration) => {
|
|
105
|
+
if (ts.isIdentifier(declaration.name) && namedConstructors.has(declaration.name.text) && declaration.initializer && ts.isArrowFunction(declaration.initializer))
|
|
106
|
+
foundConstructors.push(declaration.initializer);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
ts.forEachChild(node, visit);
|
|
110
|
+
}
|
|
111
|
+
ts.forEachChild(sourceFile, visit);
|
|
112
|
+
return [...foundConstructors, ...inlineConstructors];
|
|
113
|
+
}
|
|
114
|
+
function mkParameterVariableRoot(param, paramIndex) {
|
|
115
|
+
return { kind: 0, param, paramIndex };
|
|
116
|
+
}
|
|
117
|
+
function mkFunctionVariableRoot(func) {
|
|
118
|
+
return { kind: 1, func };
|
|
119
|
+
}
|
|
120
|
+
function mkLiteralVariableRoot(literal) {
|
|
121
|
+
return { kind: 2, literal };
|
|
122
|
+
}
|
|
123
|
+
function mkImportModuleVariableRoot(module2, importType) {
|
|
124
|
+
return { kind: 3, module: module2, importType };
|
|
125
|
+
}
|
|
126
|
+
function mkFunctionCallVariableRoot(node) {
|
|
127
|
+
return { kind: 4, node };
|
|
128
|
+
}
|
|
129
|
+
function mkGlobalVariableRoot(name) {
|
|
130
|
+
return { kind: 5, name };
|
|
131
|
+
}
|
|
132
|
+
function mkOtherVariableRoot(node) {
|
|
133
|
+
return { kind: 6, node };
|
|
134
|
+
}
|
|
135
|
+
function isParamVariableRoot(vr) {
|
|
136
|
+
return vr.kind === 0;
|
|
137
|
+
}
|
|
138
|
+
function isFunctionVariableRoot(vr) {
|
|
139
|
+
return vr.kind === 1;
|
|
140
|
+
}
|
|
141
|
+
function isImportModuleVariableRoot(vr) {
|
|
142
|
+
return vr.kind === 3;
|
|
143
|
+
}
|
|
144
|
+
function isLiteralVariableRoot(vr) {
|
|
145
|
+
return vr.kind === 2;
|
|
146
|
+
}
|
|
147
|
+
function isFunctionCallVariableRoot(vr) {
|
|
148
|
+
return vr.kind === 4;
|
|
149
|
+
}
|
|
150
|
+
function isGlobalVariableRoot(vr) {
|
|
151
|
+
return vr.kind === 5;
|
|
152
|
+
}
|
|
153
|
+
var LetOrConst = /* @__PURE__ */ ((LetOrConst2) => {
|
|
154
|
+
LetOrConst2[LetOrConst2["LET"] = 0] = "LET";
|
|
155
|
+
LetOrConst2[LetOrConst2["CONST"] = 1] = "CONST";
|
|
156
|
+
return LetOrConst2;
|
|
157
|
+
})(LetOrConst || {});
|
|
158
|
+
function mkVariable(members) {
|
|
159
|
+
return Object.fromEntries(Object.entries(members).filter(([, value]) => value !== void 0));
|
|
160
|
+
}
|
|
161
|
+
const UNKNOWN_VARIABLE = {};
|
|
162
|
+
const getAccessedByProperty = (binding, accessedFrom, propertyName) => {
|
|
163
|
+
return accessedFrom ? propertyName ? ts.isIdentifier(propertyName) ? propertyName.text : void 0 : binding.text : void 0;
|
|
164
|
+
};
|
|
165
|
+
function findDeclaringStatement(node) {
|
|
166
|
+
if (!node)
|
|
167
|
+
return void 0;
|
|
168
|
+
else if (ts.isStatement(node))
|
|
169
|
+
return node;
|
|
170
|
+
else
|
|
171
|
+
return findDeclaringStatement(node.parent);
|
|
172
|
+
}
|
|
173
|
+
function tsBindingNameToVariable(binding, accessedFrom, assignedFrom, propertyName, root) {
|
|
174
|
+
if (ts.isIdentifier(binding)) {
|
|
175
|
+
return [
|
|
176
|
+
mkVariable({
|
|
177
|
+
name: binding.text,
|
|
178
|
+
accessedFrom,
|
|
179
|
+
accessedByProperty: getAccessedByProperty(binding, accessedFrom, propertyName),
|
|
180
|
+
assignedFrom,
|
|
181
|
+
root,
|
|
182
|
+
definingStatement: findDeclaringStatement(binding)
|
|
183
|
+
})
|
|
184
|
+
];
|
|
185
|
+
} else if (ts.isObjectBindingPattern(binding)) {
|
|
186
|
+
let variable = mkVariable({
|
|
187
|
+
accessedFrom,
|
|
188
|
+
accessedByProperty: propertyName ? ts.isIdentifier(propertyName) ? propertyName.text : void 0 : void 0,
|
|
189
|
+
assignedFrom,
|
|
190
|
+
root,
|
|
191
|
+
definingStatement: findDeclaringStatement(binding)
|
|
192
|
+
});
|
|
193
|
+
return binding.elements.flatMap((element) => {
|
|
194
|
+
return tsBindingNameToVariable(element.name, variable, void 0, element.propertyName);
|
|
195
|
+
});
|
|
196
|
+
} else if (ts.isArrayBindingPattern(binding)) {
|
|
197
|
+
let variable = mkVariable({
|
|
198
|
+
accessedFrom,
|
|
199
|
+
accessedByProperty: propertyName ? ts.isIdentifier(propertyName) ? propertyName.text : void 0 : void 0,
|
|
200
|
+
assignedFrom,
|
|
201
|
+
root,
|
|
202
|
+
definingStatement: findDeclaringStatement(binding)
|
|
203
|
+
});
|
|
204
|
+
return binding.elements.flatMap((element, index) => {
|
|
205
|
+
return ts.isBindingElement(element) && tsBindingNameToVariable(element.name, variable, void 0, {
|
|
206
|
+
kind: 80,
|
|
207
|
+
text: "" + index
|
|
208
|
+
});
|
|
209
|
+
}).filter((variable2) => !!variable2);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
class NameBindingResolver {
|
|
213
|
+
constructor(parentNameResolver) {
|
|
214
|
+
__publicField(this, "variables", /* @__PURE__ */ new Map());
|
|
215
|
+
this.parentNameResolver = parentNameResolver;
|
|
216
|
+
}
|
|
217
|
+
addVariable(name, variable) {
|
|
218
|
+
this.variables.set(name, variable);
|
|
219
|
+
}
|
|
220
|
+
addFunctionParams(functionDeclaration) {
|
|
221
|
+
functionDeclaration.parameters.map((param, paramIndex) => {
|
|
222
|
+
let paramVariables = tsBindingNameToVariable(
|
|
223
|
+
param.name,
|
|
224
|
+
void 0,
|
|
225
|
+
void 0,
|
|
226
|
+
void 0,
|
|
227
|
+
mkParameterVariableRoot(param, paramIndex)
|
|
228
|
+
);
|
|
229
|
+
paramVariables.forEach((variable) => {
|
|
230
|
+
if (variable.name)
|
|
231
|
+
this.variables.set(variable.name, variable);
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
addFunctionDeclaration(statement) {
|
|
236
|
+
if (statement.name) {
|
|
237
|
+
let functionVariable = mkVariable({
|
|
238
|
+
name: statement.name.text,
|
|
239
|
+
root: mkFunctionVariableRoot(statement),
|
|
240
|
+
definingStatement: statement
|
|
241
|
+
});
|
|
242
|
+
this.variables.set(statement.name.text, functionVariable);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
addVariableDeclarationList(declarationList) {
|
|
246
|
+
const letOrConst = declarationList.flags === ts.NodeFlags.Const ? 1 : 0;
|
|
247
|
+
declarationList.declarations.forEach((declaration) => {
|
|
248
|
+
let rightSide = declaration.initializer ? this.resolvePropertyAccessChain(declaration.initializer) : void 0;
|
|
249
|
+
let declaredVariable = tsBindingNameToVariable(
|
|
250
|
+
declaration.name,
|
|
251
|
+
void 0,
|
|
252
|
+
rightSide,
|
|
253
|
+
void 0
|
|
254
|
+
);
|
|
255
|
+
declaredVariable.forEach(
|
|
256
|
+
(variable) => this.variables.set(variable.name, { ...variable, letOrConst })
|
|
257
|
+
);
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
addVariableStatement(variableStatement) {
|
|
261
|
+
this.addVariableDeclarationList(variableStatement.declarationList);
|
|
262
|
+
}
|
|
263
|
+
getVariable(name) {
|
|
264
|
+
return this.variables.get(name) || UNKNOWN_VARIABLE;
|
|
265
|
+
}
|
|
266
|
+
resolvePropertyAccessChain(expression) {
|
|
267
|
+
if (ts.isPropertyAccessExpression(expression)) {
|
|
268
|
+
const name = expression.name.text;
|
|
269
|
+
const identifiersFromObject = this.resolvePropertyAccessChain(expression.expression);
|
|
270
|
+
return { accessedFrom: identifiersFromObject, accessedByProperty: name };
|
|
271
|
+
} else if (ts.isElementAccessExpression(expression) && ts.isStringLiteral(expression.argumentExpression)) {
|
|
272
|
+
const name = expression.argumentExpression.text;
|
|
273
|
+
const identifiersFromObject = this.resolvePropertyAccessChain(expression.expression);
|
|
274
|
+
return { accessedFrom: identifiersFromObject, accessedByProperty: name };
|
|
275
|
+
} else if (ts.isIdentifier(expression)) {
|
|
276
|
+
return this.resolveIdentifier(expression);
|
|
277
|
+
} else if (ts.isParenthesizedExpression(expression)) {
|
|
278
|
+
return this.resolvePropertyAccessChain(expression.expression);
|
|
279
|
+
} else if (ts.isAsExpression(expression)) {
|
|
280
|
+
return this.resolvePropertyAccessChain(expression.expression);
|
|
281
|
+
} else if (ts.isObjectLiteralExpression(expression)) {
|
|
282
|
+
return {
|
|
283
|
+
properties: expression.properties.map((property) => {
|
|
284
|
+
if (ts.isPropertyAssignment(property) && (ts.isStringLiteral(property.name) || ts.isIdentifier(property.name))) {
|
|
285
|
+
if (ts.isIdentifier(property.initializer))
|
|
286
|
+
return {
|
|
287
|
+
name: property.name.text,
|
|
288
|
+
assignedFrom: this.resolveIdentifier(property.initializer)
|
|
289
|
+
};
|
|
290
|
+
else if (ts.isObjectLiteralExpression(property.initializer)) {
|
|
291
|
+
let nestedProperty = this.resolvePropertyAccessChain(
|
|
292
|
+
property.initializer
|
|
293
|
+
);
|
|
294
|
+
nestedProperty.name = property.name.text;
|
|
295
|
+
return nestedProperty;
|
|
296
|
+
} else if (ts.isArrowFunction(property.initializer) || ts.isFunctionExpression(property.initializer)) {
|
|
297
|
+
return {
|
|
298
|
+
name: property.name.text,
|
|
299
|
+
root: mkFunctionVariableRoot(property.initializer)
|
|
300
|
+
};
|
|
301
|
+
} else
|
|
302
|
+
return {
|
|
303
|
+
name: property.name.text,
|
|
304
|
+
root: mkLiteralVariableRoot(property.initializer)
|
|
305
|
+
};
|
|
306
|
+
} else if (ts.isShorthandPropertyAssignment(property))
|
|
307
|
+
return {
|
|
308
|
+
name: property.name.text,
|
|
309
|
+
assignedFrom: this.resolveIdentifier(property.name)
|
|
310
|
+
};
|
|
311
|
+
})
|
|
312
|
+
};
|
|
313
|
+
} else if (ts.isArrowFunction(expression) || ts.isFunctionExpression(expression)) {
|
|
314
|
+
return { root: mkFunctionVariableRoot(expression) };
|
|
315
|
+
} else if (ts.isCallExpression(expression)) {
|
|
316
|
+
return { root: mkFunctionCallVariableRoot(expression) };
|
|
317
|
+
} else if (ts.isStringLiteral(expression) || ts.isNumericLiteral(expression) || ts.isToken(expression) && expression.kind === ts.SyntaxKind.TrueKeyword || ts.isToken(expression) && expression.kind === ts.SyntaxKind.FalseKeyword) {
|
|
318
|
+
return { root: mkLiteralVariableRoot(expression) };
|
|
319
|
+
} else {
|
|
320
|
+
return { root: mkOtherVariableRoot(expression) };
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
resolvePropertyAccess(expression) {
|
|
324
|
+
return this.resolvePropertyAccessChain(expression);
|
|
325
|
+
}
|
|
326
|
+
resolveIdentifier(expression) {
|
|
327
|
+
let variableName = expression.text;
|
|
328
|
+
let nameResolver = this;
|
|
329
|
+
let resolved;
|
|
330
|
+
while ((resolved = nameResolver.getVariable(variableName)) === UNKNOWN_VARIABLE && nameResolver.parentNameResolver)
|
|
331
|
+
nameResolver = nameResolver.parentNameResolver;
|
|
332
|
+
if (resolved === UNKNOWN_VARIABLE)
|
|
333
|
+
return { root: mkGlobalVariableRoot(variableName) };
|
|
334
|
+
return resolved;
|
|
335
|
+
}
|
|
336
|
+
addImportDeclaration(node) {
|
|
337
|
+
if (node.importClause?.name) {
|
|
338
|
+
let root = mkImportModuleVariableRoot(
|
|
339
|
+
node.moduleSpecifier,
|
|
340
|
+
0
|
|
341
|
+
/* defaultImport */
|
|
342
|
+
);
|
|
343
|
+
let variable = mkVariable({
|
|
344
|
+
name: node.importClause.name.text,
|
|
345
|
+
definingStatement: node,
|
|
346
|
+
root
|
|
347
|
+
});
|
|
348
|
+
this.variables.set(node.importClause.name.text, variable);
|
|
349
|
+
}
|
|
350
|
+
if (node.importClause?.namedBindings) {
|
|
351
|
+
let root = mkImportModuleVariableRoot(
|
|
352
|
+
node.moduleSpecifier,
|
|
353
|
+
1
|
|
354
|
+
/* namedImport */
|
|
355
|
+
);
|
|
356
|
+
let namedBindings = node.importClause.namedBindings;
|
|
357
|
+
if (ts.isNamespaceImport(namedBindings)) {
|
|
358
|
+
let variable = mkVariable({
|
|
359
|
+
name: namedBindings.name.text,
|
|
360
|
+
definingStatement: node,
|
|
361
|
+
root
|
|
362
|
+
});
|
|
363
|
+
this.variables.set(namedBindings.name.text, variable);
|
|
364
|
+
} else if (ts.isNamedImports(namedBindings)) {
|
|
365
|
+
namedBindings.elements.forEach((importSpecifier) => {
|
|
366
|
+
if (!importSpecifier.isTypeOnly) {
|
|
367
|
+
let variable = mkVariable({
|
|
368
|
+
name: importSpecifier.name.text,
|
|
369
|
+
accessedByProperty: (importSpecifier.propertyName || importSpecifier.name).text,
|
|
370
|
+
accessedFrom: {
|
|
371
|
+
definingStatement: node,
|
|
372
|
+
root
|
|
373
|
+
},
|
|
374
|
+
definingStatement: node
|
|
375
|
+
});
|
|
376
|
+
this.variables.set(importSpecifier.name.text, variable);
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
function flattenVariable(variable, path2 = []) {
|
|
384
|
+
if (variable.assignedFrom)
|
|
385
|
+
return flattenVariable(variable.assignedFrom, path2);
|
|
386
|
+
else if (variable.accessedFrom) {
|
|
387
|
+
return flattenVariable(variable.accessedFrom, [variable.accessedByProperty, ...path2]);
|
|
388
|
+
} else if (variable.properties && !!variable.properties.find((_) => _.name === path2[0])) {
|
|
389
|
+
return flattenVariable(
|
|
390
|
+
variable.properties.find((_) => _.name === path2[0]),
|
|
391
|
+
path2.slice(1)
|
|
392
|
+
);
|
|
393
|
+
} else
|
|
394
|
+
return { path: path2, root: variable.root };
|
|
395
|
+
}
|
|
396
|
+
function isIdentifierOrPropertyAccessExpression(node) {
|
|
397
|
+
return ts.isIdentifier(node) || ts.isPropertyAccessExpression(node);
|
|
398
|
+
}
|
|
399
|
+
function byAnd() {
|
|
400
|
+
return (agg, value) => agg && value;
|
|
401
|
+
}
|
|
402
|
+
function findEventHandlersBlock(functionDeclaration, bindingResolver) {
|
|
403
|
+
const foundEventHandlers = [];
|
|
404
|
+
const foundEventHandlerFunctionsToHandlerIndex = /* @__PURE__ */ new Map();
|
|
405
|
+
let nextEventHandlerIndex = 0;
|
|
406
|
+
if (ts.isBlock(functionDeclaration.body)) {
|
|
407
|
+
functionDeclaration.body.statements.forEach((statement) => {
|
|
408
|
+
if (ts.isExpressionStatement(statement) && ts.isCallExpression(statement.expression)) {
|
|
409
|
+
if (isIdentifierOrPropertyAccessExpression(statement.expression.expression)) {
|
|
410
|
+
let functionVariable = bindingResolver.explain(statement.expression.expression);
|
|
411
|
+
let accessChain = flattenVariable(functionVariable);
|
|
412
|
+
if (accessChain.path.length === 2 && isParamVariableRoot(accessChain.root) && accessChain.root.param === functionDeclaration.parameters[1]) {
|
|
413
|
+
let handler = statement.expression.arguments[0];
|
|
414
|
+
if (isFunctionLikeDeclarationBase(handler))
|
|
415
|
+
foundEventHandlers.push({
|
|
416
|
+
eventHandler: handler,
|
|
417
|
+
eventHandlerCallStatement: statement,
|
|
418
|
+
handlerIndex: nextEventHandlerIndex++
|
|
419
|
+
});
|
|
420
|
+
else if (ts.isIdentifier(handler) || ts.isPropertyAccessExpression(handler)) {
|
|
421
|
+
let flattenedHandler = flattenVariable(
|
|
422
|
+
bindingResolver.explain(handler)
|
|
423
|
+
);
|
|
424
|
+
if (flattenedHandler.path.length === 0 && isFunctionVariableRoot(flattenedHandler.root))
|
|
425
|
+
foundEventHandlers.push({
|
|
426
|
+
eventHandler: flattenedHandler.root.func,
|
|
427
|
+
eventHandlerCallStatement: statement,
|
|
428
|
+
handlerIndex: foundEventHandlerFunctionsToHandlerIndex.get(
|
|
429
|
+
flattenedHandler.root
|
|
430
|
+
) ?? foundEventHandlerFunctionsToHandlerIndex.set(flattenedHandler.root, nextEventHandlerIndex++).get(flattenedHandler.root)
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
return foundEventHandlers;
|
|
439
|
+
}
|
|
440
|
+
const BUILT_IN_TYPES = ["RegExp", "Date"];
|
|
441
|
+
function builtInType(text) {
|
|
442
|
+
return BUILT_IN_TYPES.findIndex((_) => _ === text) > -1;
|
|
443
|
+
}
|
|
444
|
+
class BuiltInResolvedType {
|
|
445
|
+
constructor(name) {
|
|
446
|
+
this.name = name;
|
|
447
|
+
}
|
|
448
|
+
canBeAssignedFrom(rightSide) {
|
|
449
|
+
return rightSide instanceof BuiltInResolvedType && this.name === rightSide.name;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
class ImportFromModuleResolvedType {
|
|
453
|
+
constructor(module2, path2) {
|
|
454
|
+
this.module = module2;
|
|
455
|
+
this.path = path2;
|
|
456
|
+
}
|
|
457
|
+
canBeAssignedFrom(rightSide) {
|
|
458
|
+
if (rightSide instanceof ImportFromModuleResolvedType) {
|
|
459
|
+
let pathEqual = this.path.length === rightSide.path.length;
|
|
460
|
+
if (pathEqual) {
|
|
461
|
+
pathEqual = this.path.map((value, index) => value === rightSide.path[index]).reduce(byAnd(), true);
|
|
462
|
+
}
|
|
463
|
+
return pathEqual && this.module === rightSide.module;
|
|
464
|
+
}
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
class ArrayResolvedType {
|
|
469
|
+
constructor(itemType) {
|
|
470
|
+
this.itemType = itemType;
|
|
471
|
+
}
|
|
472
|
+
canBeAssignedFrom(rightSide) {
|
|
473
|
+
return rightSide instanceof ArrayResolvedType && this.itemType === rightSide.itemType;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
class FunctionResolvedType {
|
|
477
|
+
constructor(params, returns) {
|
|
478
|
+
this.params = params;
|
|
479
|
+
this.returns = returns;
|
|
480
|
+
}
|
|
481
|
+
canBeAssignedFrom(rightSide) {
|
|
482
|
+
return rightSide instanceof FunctionResolvedType && this.returns.canBeAssignedFrom(rightSide.returns);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
class UnionResolvedType {
|
|
486
|
+
constructor(types) {
|
|
487
|
+
this.types = types;
|
|
488
|
+
}
|
|
489
|
+
canBeAssignedFrom(rightSide) {
|
|
490
|
+
if (rightSide instanceof UnionResolvedType) {
|
|
491
|
+
for (const item1 of this.types)
|
|
492
|
+
for (const item2 of rightSide.types)
|
|
493
|
+
if (item1.canBeAssignedFrom(item2))
|
|
494
|
+
return true;
|
|
495
|
+
} else
|
|
496
|
+
for (const item1 of this.types)
|
|
497
|
+
if (item1.canBeAssignedFrom(rightSide))
|
|
498
|
+
return true;
|
|
499
|
+
return false;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
class GlobalResolvedType {
|
|
503
|
+
constructor(name) {
|
|
504
|
+
this.name = name;
|
|
505
|
+
}
|
|
506
|
+
canBeAssignedFrom(rightSide) {
|
|
507
|
+
return rightSide instanceof GlobalResolvedType && this.name === rightSide.name;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
class SpreadResolvedType {
|
|
511
|
+
constructor(arrayType) {
|
|
512
|
+
this.arrayType = arrayType;
|
|
513
|
+
}
|
|
514
|
+
canBeAssignedFrom(rightSide) {
|
|
515
|
+
return rightSide instanceof SpreadResolvedType && this.arrayType.canBeAssignedFrom(rightSide.arrayType);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
class SourceFileBindingResolver {
|
|
519
|
+
constructor(sourceFile) {
|
|
520
|
+
__publicField(this, "nameBindingResolvers", /* @__PURE__ */ new Map());
|
|
521
|
+
this.nameBindingResolvers.set(sourceFile, new NameBindingResolver());
|
|
522
|
+
const nbResolversQueue = [
|
|
523
|
+
this.nameBindingResolvers.get(sourceFile)
|
|
524
|
+
];
|
|
525
|
+
const doWithChildBindingResolver = (node, callback) => {
|
|
526
|
+
nbResolversQueue.unshift(new NameBindingResolver(nbResolversQueue[0]));
|
|
527
|
+
this.nameBindingResolvers.set(node, nbResolversQueue[0]);
|
|
528
|
+
callback();
|
|
529
|
+
node.getChildren().forEach((child) => ts.visitNode(child, visitor));
|
|
530
|
+
nbResolversQueue.shift();
|
|
531
|
+
return node;
|
|
532
|
+
};
|
|
533
|
+
const visitor = (node) => {
|
|
534
|
+
if (ts.isFunctionDeclaration(node))
|
|
535
|
+
nbResolversQueue[0].addFunctionDeclaration(node);
|
|
536
|
+
if (ts.isVariableStatement(node))
|
|
537
|
+
nbResolversQueue[0].addVariableStatement(node);
|
|
538
|
+
else if (ts.isImportDeclaration(node))
|
|
539
|
+
nbResolversQueue[0].addImportDeclaration(node);
|
|
540
|
+
else if (ts.isBlock(node))
|
|
541
|
+
return doWithChildBindingResolver(node, () => {
|
|
542
|
+
});
|
|
543
|
+
else if (isFunctionLikeDeclarationBase(node)) {
|
|
544
|
+
return doWithChildBindingResolver(
|
|
545
|
+
node,
|
|
546
|
+
() => nbResolversQueue[0].addFunctionParams(node)
|
|
547
|
+
);
|
|
548
|
+
} else if (ts.isForStatement(node) && ts.isVariableDeclarationList(node.initializer)) {
|
|
549
|
+
return doWithChildBindingResolver(
|
|
550
|
+
node,
|
|
551
|
+
() => nbResolversQueue[0].addVariableDeclarationList(
|
|
552
|
+
node.initializer
|
|
553
|
+
)
|
|
554
|
+
);
|
|
555
|
+
} else if ((ts.isForInStatement(node) || ts.isForOfStatement(node)) && ts.isVariableDeclarationList(node.initializer) && node.initializer.declarations.length === 1 && ts.isIdentifier(node.initializer.declarations[0].name)) {
|
|
556
|
+
return doWithChildBindingResolver(node, () => {
|
|
557
|
+
let name = node.initializer.declarations[0].name.text;
|
|
558
|
+
nbResolversQueue[0].addVariable(
|
|
559
|
+
name,
|
|
560
|
+
mkVariable({
|
|
561
|
+
name,
|
|
562
|
+
root: mkOtherVariableRoot(node),
|
|
563
|
+
definingStatement: node
|
|
564
|
+
})
|
|
565
|
+
);
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
node.getChildren().forEach((child) => ts.visitNode(child, visitor));
|
|
569
|
+
return node;
|
|
570
|
+
};
|
|
571
|
+
ts.visitNode(sourceFile, visitor);
|
|
572
|
+
}
|
|
573
|
+
findBindingResolver(node) {
|
|
574
|
+
let found;
|
|
575
|
+
while (!(found = this.nameBindingResolvers.get(node)) && node.parent)
|
|
576
|
+
node = node.parent;
|
|
577
|
+
return found;
|
|
578
|
+
}
|
|
579
|
+
explain(identifier) {
|
|
580
|
+
return this.findBindingResolver(identifier).resolvePropertyAccessChain(identifier);
|
|
581
|
+
}
|
|
582
|
+
explainFlattenedVariableType(flattened) {
|
|
583
|
+
if (!!flattened.root) {
|
|
584
|
+
if (isImportModuleVariableRoot(flattened.root) && ts.isStringLiteral(flattened.root.module)) {
|
|
585
|
+
return new ImportFromModuleResolvedType(flattened.root.module.text, flattened.path);
|
|
586
|
+
}
|
|
587
|
+
} else
|
|
588
|
+
return void 0;
|
|
589
|
+
}
|
|
590
|
+
explainType(type) {
|
|
591
|
+
if (type) {
|
|
592
|
+
if (ts.isTypeReferenceNode(type)) {
|
|
593
|
+
let typeName = type.typeName;
|
|
594
|
+
if (ts.isIdentifier(typeName)) {
|
|
595
|
+
let resolved = this.findBindingResolver(typeName).resolveIdentifier(typeName);
|
|
596
|
+
let flattened = flattenVariable(resolved);
|
|
597
|
+
let typeFromFlattened = this.explainFlattenedVariableType(flattened);
|
|
598
|
+
if (typeFromFlattened)
|
|
599
|
+
return typeFromFlattened;
|
|
600
|
+
if (builtInType(typeName.text))
|
|
601
|
+
return new BuiltInResolvedType(typeName.text);
|
|
602
|
+
}
|
|
603
|
+
} else if (type.kind === ts.SyntaxKind.StringKeyword)
|
|
604
|
+
return new BuiltInResolvedType("string");
|
|
605
|
+
else if (type.kind === ts.SyntaxKind.NumberKeyword)
|
|
606
|
+
return new BuiltInResolvedType("number");
|
|
607
|
+
else if (type.kind === ts.SyntaxKind.BooleanKeyword)
|
|
608
|
+
return new BuiltInResolvedType("boolean");
|
|
609
|
+
else if (type.kind === ts.SyntaxKind.AnyKeyword)
|
|
610
|
+
return new BuiltInResolvedType("any");
|
|
611
|
+
else if (type.kind === ts.SyntaxKind.VoidKeyword)
|
|
612
|
+
return new BuiltInResolvedType("void");
|
|
613
|
+
else if (ts.isArrayTypeNode(type))
|
|
614
|
+
return new ArrayResolvedType(this.explainType(type.elementType));
|
|
615
|
+
else if (ts.isFunctionTypeNode(type)) {
|
|
616
|
+
const params = type.parameters.map((param) => this.explainType(param.type));
|
|
617
|
+
const ret = this.explainType(type.type);
|
|
618
|
+
return new FunctionResolvedType(params, ret);
|
|
619
|
+
} else if (ts.isUnionTypeNode(type))
|
|
620
|
+
return new UnionResolvedType(type.types.map((aType) => this.explainType(aType)));
|
|
621
|
+
}
|
|
622
|
+
return new BuiltInResolvedType("void");
|
|
623
|
+
}
|
|
624
|
+
globalType(globalVariableRoot) {
|
|
625
|
+
return new GlobalResolvedType(globalVariableRoot.name);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
function areResolvedTypesCompatible(type1, type2) {
|
|
629
|
+
return type1.canBeAssignedFrom(type2);
|
|
630
|
+
}
|
|
631
|
+
var CompilePatternType = /* @__PURE__ */ ((CompilePatternType2) => {
|
|
632
|
+
CompilePatternType2[CompilePatternType2["RETURN"] = 0] = "RETURN";
|
|
633
|
+
CompilePatternType2[CompilePatternType2["CALL"] = 1] = "CALL";
|
|
634
|
+
CompilePatternType2[CompilePatternType2["CHAINABLE_CALL"] = 2] = "CHAINABLE_CALL";
|
|
635
|
+
CompilePatternType2[CompilePatternType2["ASSIGNMENT_LEFT_SIDE"] = 3] = "ASSIGNMENT_LEFT_SIDE";
|
|
636
|
+
CompilePatternType2[CompilePatternType2["KNOWN_VARIABLE_READ"] = 4] = "KNOWN_VARIABLE_READ";
|
|
637
|
+
CompilePatternType2[CompilePatternType2["CONST_READ"] = 5] = "CONST_READ";
|
|
638
|
+
CompilePatternType2[CompilePatternType2["INLINE_ARROW_FUNCTION"] = 6] = "INLINE_ARROW_FUNCTION";
|
|
639
|
+
return CompilePatternType2;
|
|
640
|
+
})(CompilePatternType || {});
|
|
641
|
+
function areCompatiblePatternTypes(type1, type2) {
|
|
642
|
+
if (type1 === type2)
|
|
643
|
+
return true;
|
|
644
|
+
if (type1 === 1 && type2 === 2)
|
|
645
|
+
return true;
|
|
646
|
+
return type1 === 2 && type2 === 1;
|
|
647
|
+
}
|
|
648
|
+
const KNOWN_VARIABLE_READ_NAME = "knownVariableReadPattern";
|
|
649
|
+
const CONST_READ_NAME = "knownVariableReadPattern";
|
|
650
|
+
const INLINE_ARROW_FUNCTION = "inlineArrowFunctionPattern";
|
|
651
|
+
var JayTargetEnv = /* @__PURE__ */ ((JayTargetEnv2) => {
|
|
652
|
+
JayTargetEnv2[JayTargetEnv2["main"] = 0] = "main";
|
|
653
|
+
JayTargetEnv2[JayTargetEnv2["any"] = 1] = "any";
|
|
654
|
+
JayTargetEnv2[JayTargetEnv2["sandbox"] = 2] = "sandbox";
|
|
655
|
+
return JayTargetEnv2;
|
|
656
|
+
})(JayTargetEnv || {});
|
|
657
|
+
function intersectJayTargetEnv(a, b) {
|
|
658
|
+
if (a === b && a === 1)
|
|
659
|
+
return 1;
|
|
660
|
+
if (a === 0 && b === 0 || a === 0 && b === 1 || a === 1 && b === 0)
|
|
661
|
+
return 0;
|
|
662
|
+
else
|
|
663
|
+
return 2;
|
|
664
|
+
}
|
|
665
|
+
function extractArgumentType(argument, sourceFileBinding, node) {
|
|
666
|
+
if (isIdentifierOrPropertyAccessExpression(argument)) {
|
|
667
|
+
const explainedArgument = flattenVariable(sourceFileBinding.explain(argument));
|
|
668
|
+
if (isParamVariableRoot(explainedArgument.root)) {
|
|
669
|
+
const paramIndex = explainedArgument.root.paramIndex;
|
|
670
|
+
return sourceFileBinding.explainType(node.parameters[paramIndex].type);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
if (ts.isSpreadElement(argument)) {
|
|
674
|
+
return new SpreadResolvedType(
|
|
675
|
+
extractArgumentType(argument.expression, sourceFileBinding, node)
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
return void 0;
|
|
679
|
+
}
|
|
680
|
+
function extractArgumentTypes(callArgs, sourceFileBinding, node) {
|
|
681
|
+
return callArgs.map((argument) => {
|
|
682
|
+
return extractArgumentType(argument, sourceFileBinding, node);
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
function compileFunctionSplitPatternsBlock(patternFiles) {
|
|
686
|
+
const validations = [];
|
|
687
|
+
const compiledPatterns = [];
|
|
688
|
+
patternFiles.forEach((patternsFile) => {
|
|
689
|
+
const sourceFileBinding = new SourceFileBindingResolver(patternsFile);
|
|
690
|
+
const findPatternFunctions = (node) => {
|
|
691
|
+
if (ts.isFunctionDeclaration(node)) {
|
|
692
|
+
let declaredTargetEnv = 0;
|
|
693
|
+
node.modifiers && node.modifiers.forEach((modifier) => {
|
|
694
|
+
if (ts.isDecorator(modifier) && ts.isCallExpression(modifier.expression) && ts.isIdentifier(modifier.expression.expression) && modifier.expression.expression.text === "JayPattern" && modifier.expression.arguments.length === 1 && ts.isPropertyAccessExpression(modifier.expression.arguments[0]) && ts.isIdentifier(modifier.expression.arguments[0].expression) && modifier.expression.arguments[0].expression.text === "JayTargetEnv" && modifier.expression.arguments[0].name.text === "any")
|
|
695
|
+
declaredTargetEnv = 1;
|
|
696
|
+
});
|
|
697
|
+
let name = node.name.text;
|
|
698
|
+
node.body.statements.forEach((statement, index) => {
|
|
699
|
+
let patternTargetEnv = declaredTargetEnv;
|
|
700
|
+
let patternType;
|
|
701
|
+
let leftHandSide;
|
|
702
|
+
let callArgumentTypes = [];
|
|
703
|
+
if (ts.isReturnStatement(statement) && isIdentifierOrPropertyAccessExpression(statement.expression)) {
|
|
704
|
+
patternType = 0;
|
|
705
|
+
leftHandSide = statement.expression;
|
|
706
|
+
patternTargetEnv = 1;
|
|
707
|
+
} else if (ts.isReturnStatement(statement) && ts.isCallExpression(statement.expression) && isIdentifierOrPropertyAccessExpression(statement.expression.expression) && node.type) {
|
|
708
|
+
patternType = 2;
|
|
709
|
+
leftHandSide = statement.expression.expression;
|
|
710
|
+
callArgumentTypes = extractArgumentTypes(
|
|
711
|
+
statement.expression.arguments,
|
|
712
|
+
sourceFileBinding,
|
|
713
|
+
node
|
|
714
|
+
);
|
|
715
|
+
} else if (ts.isReturnStatement(statement) && ts.isNewExpression(statement.expression) && isIdentifierOrPropertyAccessExpression(statement.expression.expression)) {
|
|
716
|
+
patternType = 2;
|
|
717
|
+
leftHandSide = statement.expression.expression;
|
|
718
|
+
callArgumentTypes = extractArgumentTypes(
|
|
719
|
+
statement.expression.arguments,
|
|
720
|
+
sourceFileBinding,
|
|
721
|
+
node
|
|
722
|
+
);
|
|
723
|
+
} else if (ts.isExpressionStatement(statement) && ts.isCallExpression(statement.expression) && isIdentifierOrPropertyAccessExpression(statement.expression.expression)) {
|
|
724
|
+
patternType = 1;
|
|
725
|
+
leftHandSide = statement.expression.expression;
|
|
726
|
+
callArgumentTypes = extractArgumentTypes(
|
|
727
|
+
statement.expression.arguments,
|
|
728
|
+
sourceFileBinding,
|
|
729
|
+
node
|
|
730
|
+
);
|
|
731
|
+
} else if (ts.isExpressionStatement(statement) && ts.isBinaryExpression(statement.expression) && ts.isPropertyAccessExpression(statement.expression.left) && statement.expression.operatorToken.kind === ts.SyntaxKind.EqualsToken && ts.isIdentifier(statement.expression.right)) {
|
|
732
|
+
patternType = 3;
|
|
733
|
+
leftHandSide = statement.expression.left;
|
|
734
|
+
callArgumentTypes = [
|
|
735
|
+
extractArgumentType(
|
|
736
|
+
statement.expression.right,
|
|
737
|
+
sourceFileBinding,
|
|
738
|
+
node
|
|
739
|
+
)
|
|
740
|
+
];
|
|
741
|
+
}
|
|
742
|
+
let resolvedLeftHandSide = flattenVariable(
|
|
743
|
+
sourceFileBinding.findBindingResolver(statement).resolvePropertyAccessChain(leftHandSide)
|
|
744
|
+
);
|
|
745
|
+
let leftSideType = void 0;
|
|
746
|
+
if (isParamVariableRoot(resolvedLeftHandSide.root)) {
|
|
747
|
+
const paramIndex = resolvedLeftHandSide.root.paramIndex;
|
|
748
|
+
leftSideType = sourceFileBinding.explainType(
|
|
749
|
+
node.parameters[paramIndex].type
|
|
750
|
+
);
|
|
751
|
+
} else if (isGlobalVariableRoot(resolvedLeftHandSide.root))
|
|
752
|
+
leftSideType = sourceFileBinding.globalType(resolvedLeftHandSide.root);
|
|
753
|
+
else if (isImportModuleVariableRoot(resolvedLeftHandSide.root))
|
|
754
|
+
leftSideType = sourceFileBinding.explainFlattenedVariableType(resolvedLeftHandSide);
|
|
755
|
+
if (patternType !== void 0 && leftSideType !== void 0) {
|
|
756
|
+
compiledPatterns.push({
|
|
757
|
+
patternType,
|
|
758
|
+
leftSidePath: resolvedLeftHandSide.path,
|
|
759
|
+
leftSideType,
|
|
760
|
+
returnType: sourceFileBinding.explainType(node.type),
|
|
761
|
+
callArgumentTypes,
|
|
762
|
+
targetEnvForStatement: patternTargetEnv,
|
|
763
|
+
name
|
|
764
|
+
});
|
|
765
|
+
} else
|
|
766
|
+
validations.push(
|
|
767
|
+
`unsupported statement, at pattern [${node.name?.text}] statement [${index}]: `,
|
|
768
|
+
astToCode(statement)
|
|
769
|
+
);
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
return node;
|
|
773
|
+
};
|
|
774
|
+
ts.transform(patternsFile, [
|
|
775
|
+
mkTransformer(({ context, sourceFile }) => {
|
|
776
|
+
ts.visitEachChild(patternsFile, findPatternFunctions, context);
|
|
777
|
+
return sourceFile;
|
|
778
|
+
})
|
|
779
|
+
]);
|
|
780
|
+
});
|
|
781
|
+
return new compilerShared.WithValidations(compiledPatterns, validations);
|
|
782
|
+
}
|
|
783
|
+
function visitWithContext(node, initialContext, contextualVisitor) {
|
|
784
|
+
return visitWithContext2(node, initialContext, void 0, contextualVisitor);
|
|
785
|
+
}
|
|
786
|
+
function visitWithContext2(node, initialContext, transformationContext, contextualVisitor) {
|
|
787
|
+
let contexts = [initialContext];
|
|
788
|
+
const visitChild = (node2, childContext) => {
|
|
789
|
+
if (childContext)
|
|
790
|
+
contexts.push(childContext);
|
|
791
|
+
let visitedNode = ts.visitNode(node2, visitor);
|
|
792
|
+
if (childContext)
|
|
793
|
+
contexts.pop();
|
|
794
|
+
return visitedNode;
|
|
795
|
+
};
|
|
796
|
+
const visitEachChild = (node2, childContext) => {
|
|
797
|
+
if (childContext)
|
|
798
|
+
contexts.push(childContext);
|
|
799
|
+
let visitedNode = ts.visitEachChild(node2, visitor, transformationContext);
|
|
800
|
+
if (childContext)
|
|
801
|
+
contexts.pop();
|
|
802
|
+
return visitedNode;
|
|
803
|
+
};
|
|
804
|
+
const visitor = (node2) => {
|
|
805
|
+
return contextualVisitor(node2, contexts.at(-1), visitChild, visitEachChild);
|
|
806
|
+
};
|
|
807
|
+
return ts.visitNode(node, visitor);
|
|
808
|
+
}
|
|
809
|
+
function isFirstParamJayEvent(eventHandler, bindingResolver) {
|
|
810
|
+
if (eventHandler.parameters.length > 0 && eventHandler.parameters[0].type) {
|
|
811
|
+
const explainedType = bindingResolver.explainType(eventHandler.parameters[0].type);
|
|
812
|
+
if (ts.isTypeReferenceNode(eventHandler.parameters[0].type) && eventHandler.parameters[0].type.typeArguments?.length === 2 && explainedType instanceof ImportFromModuleResolvedType && explainedType.module === "@jay-framework/runtime" && explainedType.path.length === 1 && explainedType.path[0] === "JayEvent")
|
|
813
|
+
return true;
|
|
814
|
+
}
|
|
815
|
+
return false;
|
|
816
|
+
}
|
|
817
|
+
function filterEventHandlersToHaveJayEventType(foundEventHandlers, bindingResolver) {
|
|
818
|
+
return foundEventHandlers.filter((foundEventHandler) => {
|
|
819
|
+
const eventHandler = foundEventHandler.eventHandler;
|
|
820
|
+
return isFirstParamJayEvent(eventHandler, bindingResolver);
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
function generateFunctionRepository(matchedReturnPatterns, matchedVariableReads, matchedConstants, safeStatements) {
|
|
824
|
+
const constCode = [...new Set(matchedConstants)].join("\n");
|
|
825
|
+
let readPatternsReturnProperties = matchedReturnPatterns.map(
|
|
826
|
+
({ pattern, patternKey }) => `$${patternKey}: ${pattern.leftSidePath.join(".")}`
|
|
827
|
+
);
|
|
828
|
+
readPatternsReturnProperties = [...new Set(readPatternsReturnProperties)];
|
|
829
|
+
let variableReadsReturnProperties = matchedVariableReads.map(
|
|
830
|
+
({ variable, patternKey }) => `$${patternKey}: ${variable.text}`
|
|
831
|
+
);
|
|
832
|
+
let returnedObjectProperties = [
|
|
833
|
+
...readPatternsReturnProperties,
|
|
834
|
+
...variableReadsReturnProperties
|
|
835
|
+
].join(",\n");
|
|
836
|
+
if (safeStatements.length > 0) {
|
|
837
|
+
const handlerCode = `({ event }: JayEvent<any, any>) => {
|
|
838
|
+
${safeStatements.map((statement) => astToCode(statement)).join("\n ")}
|
|
839
|
+
${returnedObjectProperties.length > 0 ? ` return ({${returnedObjectProperties}})
|
|
840
|
+
` : ""}
|
|
841
|
+
}`;
|
|
842
|
+
return { handlerCode, key: constCode };
|
|
843
|
+
}
|
|
844
|
+
if (matchedReturnPatterns.length > 0) {
|
|
845
|
+
let handlerCode = `({ event }: JayEvent<any, any>) => ({${returnedObjectProperties}})`;
|
|
846
|
+
return { handlerCode, key: constCode };
|
|
847
|
+
} else
|
|
848
|
+
return { key: void 0, handlerCode: void 0 };
|
|
849
|
+
}
|
|
850
|
+
const mkTransformEventHandlerStatementVisitor = (factory, context, bindingResolver, analyzer) => {
|
|
851
|
+
let sideEffects = {
|
|
852
|
+
matchedVariableReads: [],
|
|
853
|
+
matchedConstants: [],
|
|
854
|
+
mainContextBlocks: /* @__PURE__ */ new Map(),
|
|
855
|
+
matchedReturnPatterns: [],
|
|
856
|
+
wasEventHandlerTransformed: false
|
|
857
|
+
};
|
|
858
|
+
let patternIndexes = /* @__PURE__ */ new Map();
|
|
859
|
+
const getPatternIndex = (pattern) => {
|
|
860
|
+
if (!patternIndexes.has(pattern)) {
|
|
861
|
+
patternIndexes.set(pattern, patternIndexes.size);
|
|
862
|
+
}
|
|
863
|
+
return patternIndexes.get(pattern);
|
|
864
|
+
};
|
|
865
|
+
const visitor = (node, { parentStatementTargetEnv }, visitChild, visitEachChild) => {
|
|
866
|
+
if (ts.isStatement(node)) {
|
|
867
|
+
let statementAnalysis = analyzer.getStatementStatus(node);
|
|
868
|
+
if (statementAnalysis)
|
|
869
|
+
parentStatementTargetEnv = intersectJayTargetEnv(
|
|
870
|
+
parentStatementTargetEnv,
|
|
871
|
+
statementAnalysis.targetEnv
|
|
872
|
+
);
|
|
873
|
+
}
|
|
874
|
+
if (ts.isBlock(node) && parentStatementTargetEnv !== JayTargetEnv.sandbox) {
|
|
875
|
+
let sandboxStatements = [], mainStatements = [];
|
|
876
|
+
node.statements.forEach((statement) => {
|
|
877
|
+
let statementAnalysis = analyzer.getStatementStatus(statement);
|
|
878
|
+
switch (statementAnalysis.targetEnv) {
|
|
879
|
+
case JayTargetEnv.any:
|
|
880
|
+
sandboxStatements.push(statement);
|
|
881
|
+
mainStatements.push(statement);
|
|
882
|
+
break;
|
|
883
|
+
case JayTargetEnv.main:
|
|
884
|
+
mainStatements.push(statement);
|
|
885
|
+
break;
|
|
886
|
+
case JayTargetEnv.sandbox:
|
|
887
|
+
sandboxStatements.push(statement);
|
|
888
|
+
break;
|
|
889
|
+
}
|
|
890
|
+
});
|
|
891
|
+
sideEffects.mainContextBlocks.set(node, factory.createBlock(mainStatements));
|
|
892
|
+
if (sandboxStatements.length < node.statements.length)
|
|
893
|
+
sideEffects.wasEventHandlerTransformed = true;
|
|
894
|
+
sandboxStatements = sandboxStatements.map(
|
|
895
|
+
(statement) => visitChild(statement, { parentStatementTargetEnv })
|
|
896
|
+
);
|
|
897
|
+
node = factory.updateBlock(node, sandboxStatements);
|
|
898
|
+
return node;
|
|
899
|
+
} else if (ts.isExpression(node)) {
|
|
900
|
+
let expressionAnalysis = analyzer.getExpressionStatus(node);
|
|
901
|
+
if (expressionAnalysis) {
|
|
902
|
+
let pattern = expressionAnalysis.patterns[0];
|
|
903
|
+
let patternKey = getPatternIndex(pattern);
|
|
904
|
+
if (pattern.patternType === CompilePatternType.RETURN)
|
|
905
|
+
sideEffects.matchedReturnPatterns.push({ pattern, patternKey });
|
|
906
|
+
else if (pattern.patternType === CompilePatternType.KNOWN_VARIABLE_READ && ts.isIdentifier(node))
|
|
907
|
+
sideEffects.matchedVariableReads.push({ variable: node, patternKey });
|
|
908
|
+
else if (pattern.patternType === CompilePatternType.CONST_READ && ts.isIdentifier(node)) {
|
|
909
|
+
let constant = bindingResolver.explain(node);
|
|
910
|
+
let flattenedConstant = flattenVariable(constant);
|
|
911
|
+
let literal = flattenedConstant.root.literal;
|
|
912
|
+
if (ts.isLiteralExpression(literal)) {
|
|
913
|
+
let constantValue = literal.text;
|
|
914
|
+
sideEffects.matchedConstants.push(`const ${node.text} = ${constantValue}`);
|
|
915
|
+
}
|
|
916
|
+
return node;
|
|
917
|
+
} else
|
|
918
|
+
return node;
|
|
919
|
+
let replacementPattern = `event.$${patternKey}`;
|
|
920
|
+
sideEffects.wasEventHandlerTransformed = true;
|
|
921
|
+
return codeToAst(replacementPattern, context)[0].expression;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
return visitEachChild(node, { parentStatementTargetEnv });
|
|
925
|
+
};
|
|
926
|
+
return { visitor, sideEffects };
|
|
927
|
+
};
|
|
928
|
+
const analyzeEventHandlerByPatternBlock = (context, bindingResolver, analyzer, factory, eventHandler, functionsRepository) => {
|
|
929
|
+
const scopedAnalyzer = analyzer.analyzeForScope(eventHandler);
|
|
930
|
+
const { sideEffects, visitor } = mkTransformEventHandlerStatementVisitor(
|
|
931
|
+
factory,
|
|
932
|
+
context,
|
|
933
|
+
bindingResolver,
|
|
934
|
+
scopedAnalyzer
|
|
935
|
+
);
|
|
936
|
+
let transformedEventHandler = visitWithContext2(
|
|
937
|
+
eventHandler,
|
|
938
|
+
{ parentStatementTargetEnv: JayTargetEnv.any },
|
|
939
|
+
context,
|
|
940
|
+
visitor
|
|
941
|
+
);
|
|
942
|
+
if (sideEffects.wasEventHandlerTransformed && isFirstParamJayEvent(eventHandler, bindingResolver)) {
|
|
943
|
+
const originalJayEventType = eventHandler.parameters[0].type;
|
|
944
|
+
if (originalJayEventType.typeArguments?.length === 2) {
|
|
945
|
+
const transformedJayEventType = factory.createTypeReferenceNode(
|
|
946
|
+
originalJayEventType.typeName,
|
|
947
|
+
[
|
|
948
|
+
factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
|
|
949
|
+
originalJayEventType.typeArguments[1]
|
|
950
|
+
]
|
|
951
|
+
);
|
|
952
|
+
let visitor2 = (node) => {
|
|
953
|
+
if (node === originalJayEventType) {
|
|
954
|
+
return ts.visitEachChild(transformedJayEventType, visitor2, context);
|
|
955
|
+
}
|
|
956
|
+
return ts.visitEachChild(node, visitor2, context);
|
|
957
|
+
};
|
|
958
|
+
transformedEventHandler = ts.visitEachChild(transformedEventHandler, visitor2, context);
|
|
959
|
+
}
|
|
960
|
+
let bodyForFunctionRepository = void 0;
|
|
961
|
+
if (ts.isBlock(eventHandler.body) && sideEffects.mainContextBlocks.has(eventHandler.body)) {
|
|
962
|
+
let body = sideEffects.mainContextBlocks.get(eventHandler.body);
|
|
963
|
+
const replaceBodiesVisitor = (node) => {
|
|
964
|
+
let mainNode = ts.isBlock(node) && sideEffects.mainContextBlocks.has(node) ? sideEffects.mainContextBlocks.get(node) : node;
|
|
965
|
+
return ts.visitEachChild(mainNode, replaceBodiesVisitor, context);
|
|
966
|
+
};
|
|
967
|
+
bodyForFunctionRepository = ts.visitNode(body, replaceBodiesVisitor);
|
|
968
|
+
}
|
|
969
|
+
const { handlerCode, key } = generateFunctionRepository(
|
|
970
|
+
sideEffects.matchedReturnPatterns,
|
|
971
|
+
sideEffects.matchedVariableReads,
|
|
972
|
+
sideEffects.matchedConstants,
|
|
973
|
+
bodyForFunctionRepository ? [...bodyForFunctionRepository.statements] : []
|
|
974
|
+
);
|
|
975
|
+
const handlerKey = functionsRepository.addFunction(handlerCode);
|
|
976
|
+
functionsRepository.addConst(key);
|
|
977
|
+
return {
|
|
978
|
+
transformedEventHandler,
|
|
979
|
+
wasEventHandlerTransformed: sideEffects.wasEventHandlerTransformed,
|
|
980
|
+
handlerKey
|
|
981
|
+
};
|
|
982
|
+
} else
|
|
983
|
+
return {
|
|
984
|
+
handlerKey: "",
|
|
985
|
+
transformedEventHandler,
|
|
986
|
+
wasEventHandlerTransformed: false
|
|
987
|
+
};
|
|
988
|
+
};
|
|
989
|
+
const analyzeEventHandlerCall = (context, factory, handlerKey) => (node) => {
|
|
990
|
+
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {
|
|
991
|
+
return factory.createCallExpression(
|
|
992
|
+
factory.createPropertyAccessExpression(
|
|
993
|
+
factory.createCallExpression(
|
|
994
|
+
factory.createPropertyAccessExpression(
|
|
995
|
+
node.expression.expression,
|
|
996
|
+
node.expression.name.text + "$"
|
|
997
|
+
),
|
|
998
|
+
void 0,
|
|
999
|
+
codeToAst(`handler$('${handlerKey}')`, context).map(
|
|
1000
|
+
(_) => _.expression
|
|
1001
|
+
)
|
|
1002
|
+
),
|
|
1003
|
+
factory.createIdentifier("then")
|
|
1004
|
+
),
|
|
1005
|
+
void 0,
|
|
1006
|
+
node.arguments
|
|
1007
|
+
);
|
|
1008
|
+
}
|
|
1009
|
+
return node;
|
|
1010
|
+
};
|
|
1011
|
+
const analyzeEventHandlerCallStatement$Block = (context, factory, handlerKey) => (node) => {
|
|
1012
|
+
return ts.visitEachChild(
|
|
1013
|
+
node,
|
|
1014
|
+
analyzeEventHandlerCall(context, factory, handlerKey),
|
|
1015
|
+
context
|
|
1016
|
+
);
|
|
1017
|
+
};
|
|
1018
|
+
function analyzedEventHandlersToReplaceMap(transformedEventHandlers) {
|
|
1019
|
+
const map = /* @__PURE__ */ new Map();
|
|
1020
|
+
transformedEventHandlers.forEach((_) => {
|
|
1021
|
+
map.set(_.eventHandlerCallStatement, _.transformedEventHandlerCallStatement);
|
|
1022
|
+
map.set(_.eventHandler, _.transformedEventHandler);
|
|
1023
|
+
});
|
|
1024
|
+
return map;
|
|
1025
|
+
}
|
|
1026
|
+
function analyzeEventHandlers(context, bindingResolver, analyzer, factory, foundEventHandlers, functionsRepository) {
|
|
1027
|
+
let handlerToTransformedHandlers = /* @__PURE__ */ new Map();
|
|
1028
|
+
foundEventHandlers.forEach((foundEventHandler) => {
|
|
1029
|
+
if (!handlerToTransformedHandlers.has(foundEventHandler.eventHandler))
|
|
1030
|
+
handlerToTransformedHandlers.set(
|
|
1031
|
+
foundEventHandler.eventHandler,
|
|
1032
|
+
analyzeEventHandlerByPatternBlock(
|
|
1033
|
+
context,
|
|
1034
|
+
bindingResolver,
|
|
1035
|
+
analyzer,
|
|
1036
|
+
factory,
|
|
1037
|
+
foundEventHandler.eventHandler,
|
|
1038
|
+
functionsRepository
|
|
1039
|
+
)
|
|
1040
|
+
);
|
|
1041
|
+
});
|
|
1042
|
+
return foundEventHandlers.filter(
|
|
1043
|
+
(foundEventHandler) => handlerToTransformedHandlers.get(foundEventHandler.eventHandler).wasEventHandlerTransformed
|
|
1044
|
+
).map((foundEventHandler) => {
|
|
1045
|
+
const { transformedEventHandler, wasEventHandlerTransformed, handlerKey } = handlerToTransformedHandlers.get(foundEventHandler.eventHandler);
|
|
1046
|
+
const transformedEventHandlerCallStatement = analyzeEventHandlerCallStatement$Block(
|
|
1047
|
+
context,
|
|
1048
|
+
factory,
|
|
1049
|
+
handlerKey
|
|
1050
|
+
)(foundEventHandler.eventHandlerCallStatement);
|
|
1051
|
+
return {
|
|
1052
|
+
...foundEventHandler,
|
|
1053
|
+
transformedEventHandler,
|
|
1054
|
+
wasEventHandlerTransformed,
|
|
1055
|
+
// functionRepositoryFragment,
|
|
1056
|
+
transformedEventHandlerCallStatement
|
|
1057
|
+
};
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
class SourceFileStatementAnalyzer {
|
|
1061
|
+
constructor(sourceFile, bindingResolver, compiledPatterns) {
|
|
1062
|
+
this.sourceFile = sourceFile;
|
|
1063
|
+
this.bindingResolver = bindingResolver;
|
|
1064
|
+
this.compiledPatterns = compiledPatterns;
|
|
1065
|
+
}
|
|
1066
|
+
analyzeForScope(analysisScope) {
|
|
1067
|
+
return new ScopedSourceFileStatementAnalyzer(
|
|
1068
|
+
this.sourceFile,
|
|
1069
|
+
this.bindingResolver,
|
|
1070
|
+
this.compiledPatterns,
|
|
1071
|
+
analysisScope
|
|
1072
|
+
);
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
class ScopedSourceFileStatementAnalyzer {
|
|
1076
|
+
constructor(sourceFile, bindingResolver, compiledPatterns, analysisScope) {
|
|
1077
|
+
__publicField(this, "analyzedStatements", /* @__PURE__ */ new Map());
|
|
1078
|
+
__publicField(this, "analyzedExpressions", /* @__PURE__ */ new Map());
|
|
1079
|
+
__publicField(this, "nextId", 0);
|
|
1080
|
+
this.sourceFile = sourceFile;
|
|
1081
|
+
this.bindingResolver = bindingResolver;
|
|
1082
|
+
this.compiledPatterns = compiledPatterns;
|
|
1083
|
+
this.analyze(analysisScope);
|
|
1084
|
+
}
|
|
1085
|
+
addPatternToStatement(statement, matchedPattern) {
|
|
1086
|
+
if (!this.analyzedStatements.get(statement)) {
|
|
1087
|
+
this.analyzedStatements.set(statement, {
|
|
1088
|
+
targetEnv: matchedPattern.patterns.reduce(
|
|
1089
|
+
(prev, curr) => intersectJayTargetEnv(prev, curr.targetEnvForStatement),
|
|
1090
|
+
JayTargetEnv.any
|
|
1091
|
+
),
|
|
1092
|
+
matchedPatterns: [matchedPattern]
|
|
1093
|
+
});
|
|
1094
|
+
} else {
|
|
1095
|
+
let analysisResult = this.analyzedStatements.get(statement);
|
|
1096
|
+
analysisResult.matchedPatterns.push(matchedPattern);
|
|
1097
|
+
analysisResult.targetEnv = intersectJayTargetEnv(
|
|
1098
|
+
analysisResult.targetEnv,
|
|
1099
|
+
matchedPattern.patterns.reduce(
|
|
1100
|
+
(prev, curr) => intersectJayTargetEnv(prev, curr.targetEnvForStatement),
|
|
1101
|
+
JayTargetEnv.any
|
|
1102
|
+
)
|
|
1103
|
+
);
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
markStatementSandbox(statement) {
|
|
1107
|
+
if (!this.analyzedStatements.get(statement)) {
|
|
1108
|
+
this.analyzedStatements.set(statement, {
|
|
1109
|
+
targetEnv: JayTargetEnv.sandbox,
|
|
1110
|
+
matchedPatterns: []
|
|
1111
|
+
});
|
|
1112
|
+
} else
|
|
1113
|
+
this.analyzedStatements.get(statement).targetEnv = JayTargetEnv.sandbox;
|
|
1114
|
+
}
|
|
1115
|
+
analyze(analysisScope) {
|
|
1116
|
+
let RoleInParent;
|
|
1117
|
+
((RoleInParent2) => {
|
|
1118
|
+
RoleInParent2[RoleInParent2["none"] = 0] = "none";
|
|
1119
|
+
RoleInParent2[RoleInParent2["read"] = 1] = "read";
|
|
1120
|
+
RoleInParent2[RoleInParent2["assign"] = 2] = "assign";
|
|
1121
|
+
RoleInParent2[RoleInParent2["call"] = 3] = "call";
|
|
1122
|
+
})(RoleInParent || (RoleInParent = {}));
|
|
1123
|
+
const addExpressionStatus = (statement, patterns, expression, subExpressionsMatching) => {
|
|
1124
|
+
let matchedPattern = {
|
|
1125
|
+
patterns,
|
|
1126
|
+
expression,
|
|
1127
|
+
testId: this.nextId++,
|
|
1128
|
+
subExpressionsMatching
|
|
1129
|
+
};
|
|
1130
|
+
this.analyzedExpressions.set(expression, matchedPattern);
|
|
1131
|
+
this.addPatternToStatement(statement, matchedPattern);
|
|
1132
|
+
};
|
|
1133
|
+
const analyzePropertyExpression = (expression, visitChild, statement, roleInParent) => {
|
|
1134
|
+
let expectedPatternType = roleInParent === 2 ? CompilePatternType.ASSIGNMENT_LEFT_SIDE : CompilePatternType.RETURN;
|
|
1135
|
+
let { matchedPatterns, matchType } = this.matchPattern(
|
|
1136
|
+
expression,
|
|
1137
|
+
expectedPatternType,
|
|
1138
|
+
analysisScope
|
|
1139
|
+
);
|
|
1140
|
+
if (matchType === 0) {
|
|
1141
|
+
addExpressionStatus(statement, matchedPatterns, expression, true);
|
|
1142
|
+
} else {
|
|
1143
|
+
if (ts.isPropertyAccessExpression(expression))
|
|
1144
|
+
visitChild(expression.expression, {
|
|
1145
|
+
statement,
|
|
1146
|
+
roleInParent: 1
|
|
1147
|
+
/* read */
|
|
1148
|
+
});
|
|
1149
|
+
this.markStatementSandbox(statement);
|
|
1150
|
+
}
|
|
1151
|
+
};
|
|
1152
|
+
const analyzeCallParam = (argument, matchedPatterns, index, statement) => {
|
|
1153
|
+
const expressionStatus = this.getExpressionStatus(argument);
|
|
1154
|
+
const patternTypeMatchArgumentType = !!expressionStatus && expressionStatus.patterns.length > 0 && expressionStatus.subExpressionsMatching && areResolvedTypesCompatible(
|
|
1155
|
+
expressionStatus.patterns[0].returnType,
|
|
1156
|
+
matchedPatterns[0].callArgumentTypes[index]
|
|
1157
|
+
);
|
|
1158
|
+
const isLiteral = ts.isLiteralExpression(argument);
|
|
1159
|
+
let isScopedVariableAccess = false;
|
|
1160
|
+
if (isIdentifierOrPropertyAccessExpression(argument)) {
|
|
1161
|
+
const variable = this.bindingResolver.explain(argument);
|
|
1162
|
+
const flattened = flattenVariable(variable);
|
|
1163
|
+
isScopedVariableAccess = isParamVariableRoot(flattened.root) && isChildOf(flattened.root.param, analysisScope);
|
|
1164
|
+
}
|
|
1165
|
+
const paramMatching = patternTypeMatchArgumentType || isLiteral || isScopedVariableAccess;
|
|
1166
|
+
if (!paramMatching)
|
|
1167
|
+
this.markStatementSandbox(statement);
|
|
1168
|
+
return paramMatching;
|
|
1169
|
+
};
|
|
1170
|
+
const analyzeCallOrNewExpression = (node, visitChild, statement, roleInParent) => {
|
|
1171
|
+
if (isIdentifierOrPropertyAccessExpression(node.expression)) {
|
|
1172
|
+
let expression = node.expression;
|
|
1173
|
+
node.arguments.forEach(
|
|
1174
|
+
(argument) => visitChild(argument, {
|
|
1175
|
+
statement,
|
|
1176
|
+
roleInParent: 1
|
|
1177
|
+
/* read */
|
|
1178
|
+
})
|
|
1179
|
+
);
|
|
1180
|
+
let expectedPatternType = roleInParent === 3 ? CompilePatternType.CALL : CompilePatternType.CHAINABLE_CALL;
|
|
1181
|
+
let { matchedPatterns, matchType } = this.matchPattern(
|
|
1182
|
+
expression,
|
|
1183
|
+
expectedPatternType,
|
|
1184
|
+
analysisScope
|
|
1185
|
+
);
|
|
1186
|
+
if (matchType === 0) {
|
|
1187
|
+
let areArgumentsMatching = node.arguments.map((argument, index) => {
|
|
1188
|
+
return analyzeCallParam(argument, matchedPatterns, index, statement);
|
|
1189
|
+
}).reduce(byAnd(), true);
|
|
1190
|
+
addExpressionStatus(statement, matchedPatterns, node, areArgumentsMatching);
|
|
1191
|
+
} else {
|
|
1192
|
+
if (ts.isPropertyAccessExpression(node.expression))
|
|
1193
|
+
visitChild(node.expression.expression, {
|
|
1194
|
+
statement,
|
|
1195
|
+
roleInParent: 1
|
|
1196
|
+
/* read */
|
|
1197
|
+
});
|
|
1198
|
+
this.markStatementSandbox(statement);
|
|
1199
|
+
}
|
|
1200
|
+
} else
|
|
1201
|
+
this.markStatementSandbox(statement);
|
|
1202
|
+
};
|
|
1203
|
+
visitWithContext(
|
|
1204
|
+
this.sourceFile,
|
|
1205
|
+
{
|
|
1206
|
+
roleInParent: 0
|
|
1207
|
+
/* none */
|
|
1208
|
+
},
|
|
1209
|
+
(node, { statement, roleInParent }, visitChild) => {
|
|
1210
|
+
if (ts.isStatement(node))
|
|
1211
|
+
statement = node;
|
|
1212
|
+
if (roleInParent === 1 || roleInParent === 2) {
|
|
1213
|
+
if (isIdentifierOrPropertyAccessExpression(node))
|
|
1214
|
+
analyzePropertyExpression(node, visitChild, statement, roleInParent);
|
|
1215
|
+
else if (ts.isCallExpression(node) || ts.isNewExpression(node)) {
|
|
1216
|
+
analyzeCallOrNewExpression(node, visitChild, statement, roleInParent);
|
|
1217
|
+
return node;
|
|
1218
|
+
} else if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken)
|
|
1219
|
+
this.markStatementSandbox(statement);
|
|
1220
|
+
else if (!ts.isLiteralExpression(node) && !ts.isBinaryExpression(node))
|
|
1221
|
+
this.markStatementSandbox(statement);
|
|
1222
|
+
}
|
|
1223
|
+
if (ts.isCallExpression(node) && isIdentifierOrPropertyAccessExpression(node.expression) && roleInParent === 0) {
|
|
1224
|
+
analyzeCallOrNewExpression(
|
|
1225
|
+
node,
|
|
1226
|
+
visitChild,
|
|
1227
|
+
statement,
|
|
1228
|
+
3
|
|
1229
|
+
/* call */
|
|
1230
|
+
);
|
|
1231
|
+
} else if (ts.isVariableStatement(node)) {
|
|
1232
|
+
node.declarationList.declarations.forEach(
|
|
1233
|
+
(declaration) => visitChild(declaration.initializer, {
|
|
1234
|
+
statement,
|
|
1235
|
+
roleInParent: 1
|
|
1236
|
+
/* read */
|
|
1237
|
+
})
|
|
1238
|
+
);
|
|
1239
|
+
if (this.getStatementStatus(node)?.targetEnv === JayTargetEnv.any)
|
|
1240
|
+
this.getStatementStatus(node).targetEnv = JayTargetEnv.main;
|
|
1241
|
+
} else if (ts.isArrowFunction(node) && !ts.isBlock(node.body)) {
|
|
1242
|
+
visitChild(node.body, {
|
|
1243
|
+
statement,
|
|
1244
|
+
roleInParent: 1
|
|
1245
|
+
/* read */
|
|
1246
|
+
});
|
|
1247
|
+
const bodyStatus = this.getExpressionStatus(node.body);
|
|
1248
|
+
if (!!bodyStatus && bodyStatus.subExpressionsMatching) {
|
|
1249
|
+
addExpressionStatus(
|
|
1250
|
+
statement,
|
|
1251
|
+
[
|
|
1252
|
+
{
|
|
1253
|
+
patternType: CompilePatternType.INLINE_ARROW_FUNCTION,
|
|
1254
|
+
returnType: new FunctionResolvedType(
|
|
1255
|
+
[],
|
|
1256
|
+
bodyStatus.patterns[0].returnType
|
|
1257
|
+
),
|
|
1258
|
+
callArgumentTypes: [],
|
|
1259
|
+
targetEnvForStatement: JayTargetEnv.any,
|
|
1260
|
+
name: INLINE_ARROW_FUNCTION,
|
|
1261
|
+
leftSidePath: [],
|
|
1262
|
+
leftSideType: new FunctionResolvedType(
|
|
1263
|
+
[],
|
|
1264
|
+
bodyStatus.patterns[0].returnType
|
|
1265
|
+
)
|
|
1266
|
+
}
|
|
1267
|
+
],
|
|
1268
|
+
node,
|
|
1269
|
+
true
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1272
|
+
} else if (ts.isIfStatement(node)) {
|
|
1273
|
+
visitChild(node.expression, {
|
|
1274
|
+
statement,
|
|
1275
|
+
roleInParent: 1
|
|
1276
|
+
/* read */
|
|
1277
|
+
});
|
|
1278
|
+
visitChild(node.thenStatement, {
|
|
1279
|
+
statement,
|
|
1280
|
+
roleInParent: 0
|
|
1281
|
+
/* none */
|
|
1282
|
+
});
|
|
1283
|
+
if (node.elseStatement)
|
|
1284
|
+
visitChild(node.elseStatement, {
|
|
1285
|
+
statement,
|
|
1286
|
+
roleInParent: 0
|
|
1287
|
+
/* none */
|
|
1288
|
+
});
|
|
1289
|
+
} else if (ts.isForStatement(node) || ts.isForOfStatement(node) || ts.isForInStatement(node) || ts.isWhileStatement(node) || ts.isDoStatement(node)) {
|
|
1290
|
+
this.markStatementSandbox(statement);
|
|
1291
|
+
node.getChildren().forEach(
|
|
1292
|
+
(child) => visitChild(child, {
|
|
1293
|
+
statement,
|
|
1294
|
+
roleInParent: 0
|
|
1295
|
+
/* none */
|
|
1296
|
+
})
|
|
1297
|
+
);
|
|
1298
|
+
} else if (ts.isBinaryExpression(node)) {
|
|
1299
|
+
visitChild(node.right, {
|
|
1300
|
+
statement,
|
|
1301
|
+
roleInParent: 1
|
|
1302
|
+
/* read */
|
|
1303
|
+
});
|
|
1304
|
+
visitChild(node.left, {
|
|
1305
|
+
statement,
|
|
1306
|
+
roleInParent: node.operatorToken.kind === ts.SyntaxKind.EqualsToken ? 2 : 1
|
|
1307
|
+
/* read */
|
|
1308
|
+
});
|
|
1309
|
+
} else if (ts.isElementAccessExpression(node)) {
|
|
1310
|
+
node.getChildren().forEach(
|
|
1311
|
+
(child) => visitChild(child, {
|
|
1312
|
+
statement,
|
|
1313
|
+
roleInParent: 1
|
|
1314
|
+
/* read */
|
|
1315
|
+
})
|
|
1316
|
+
);
|
|
1317
|
+
} else {
|
|
1318
|
+
node.getChildren().forEach(
|
|
1319
|
+
(child) => visitChild(child, {
|
|
1320
|
+
statement,
|
|
1321
|
+
roleInParent: 0
|
|
1322
|
+
/* none */
|
|
1323
|
+
})
|
|
1324
|
+
);
|
|
1325
|
+
}
|
|
1326
|
+
return node;
|
|
1327
|
+
}
|
|
1328
|
+
);
|
|
1329
|
+
}
|
|
1330
|
+
matchPattern(patternTarget, expectedPatternType, analysisScope) {
|
|
1331
|
+
let variable = this.bindingResolver.explain(patternTarget);
|
|
1332
|
+
let resolvedVariable = flattenVariable(variable);
|
|
1333
|
+
let matchedPatterns = [];
|
|
1334
|
+
let currentVariableType;
|
|
1335
|
+
if (resolvedVariable.root) {
|
|
1336
|
+
if (isParamVariableRoot(resolvedVariable.root))
|
|
1337
|
+
currentVariableType = this.bindingResolver.explainType(
|
|
1338
|
+
resolvedVariable.root.param.type
|
|
1339
|
+
);
|
|
1340
|
+
else if (isGlobalVariableRoot(resolvedVariable.root)) {
|
|
1341
|
+
currentVariableType = this.bindingResolver.globalType(resolvedVariable.root);
|
|
1342
|
+
} else if (isFunctionCallVariableRoot(resolvedVariable.root)) {
|
|
1343
|
+
let matchedPattern = this.getExpressionStatus(resolvedVariable.root.node);
|
|
1344
|
+
if (matchedPattern) {
|
|
1345
|
+
currentVariableType = matchedPattern.patterns.at(-1).returnType;
|
|
1346
|
+
}
|
|
1347
|
+
} else if (isImportModuleVariableRoot(resolvedVariable.root)) {
|
|
1348
|
+
currentVariableType = this.bindingResolver.explainFlattenedVariableType(resolvedVariable);
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
if (resolvedVariable.path.length === 0 && resolvedVariable.root && isLiteralVariableRoot(resolvedVariable.root)) {
|
|
1352
|
+
if (variable.letOrConst === LetOrConst.CONST)
|
|
1353
|
+
return {
|
|
1354
|
+
matchedPatterns: [
|
|
1355
|
+
{
|
|
1356
|
+
patternType: CompilePatternType.CONST_READ,
|
|
1357
|
+
returnType: currentVariableType,
|
|
1358
|
+
callArgumentTypes: [],
|
|
1359
|
+
targetEnvForStatement: JayTargetEnv.any,
|
|
1360
|
+
name: CONST_READ_NAME,
|
|
1361
|
+
leftSidePath: [],
|
|
1362
|
+
leftSideType: currentVariableType
|
|
1363
|
+
}
|
|
1364
|
+
],
|
|
1365
|
+
matchType: 0
|
|
1366
|
+
/* FULL */
|
|
1367
|
+
};
|
|
1368
|
+
else
|
|
1369
|
+
return {
|
|
1370
|
+
matchedPatterns: [],
|
|
1371
|
+
matchType: 2
|
|
1372
|
+
/* NONE */
|
|
1373
|
+
};
|
|
1374
|
+
}
|
|
1375
|
+
if (currentVariableType) {
|
|
1376
|
+
let currentPosition = 0;
|
|
1377
|
+
while (currentPosition <= resolvedVariable.path.length) {
|
|
1378
|
+
if (resolvedVariable.path.length === 0) {
|
|
1379
|
+
if (variable.definingStatement && isChildOf(variable.definingStatement, analysisScope)) {
|
|
1380
|
+
return {
|
|
1381
|
+
matchedPatterns: [
|
|
1382
|
+
{
|
|
1383
|
+
patternType: CompilePatternType.KNOWN_VARIABLE_READ,
|
|
1384
|
+
returnType: currentVariableType,
|
|
1385
|
+
callArgumentTypes: [],
|
|
1386
|
+
targetEnvForStatement: JayTargetEnv.any,
|
|
1387
|
+
name: KNOWN_VARIABLE_READ_NAME,
|
|
1388
|
+
leftSidePath: [],
|
|
1389
|
+
leftSideType: currentVariableType
|
|
1390
|
+
}
|
|
1391
|
+
],
|
|
1392
|
+
matchType: 0
|
|
1393
|
+
/* FULL */
|
|
1394
|
+
};
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
let currentMatch = this.compiledPatterns.find((pattern) => {
|
|
1398
|
+
let leftTypeMatch = areResolvedTypesCompatible(
|
|
1399
|
+
currentVariableType,
|
|
1400
|
+
pattern.leftSideType
|
|
1401
|
+
);
|
|
1402
|
+
let pathMatch = currentPosition + pattern.leftSidePath.length <= resolvedVariable.path.length && pattern.leftSidePath.every(
|
|
1403
|
+
(element, index) => element === resolvedVariable.path[index + currentPosition]
|
|
1404
|
+
);
|
|
1405
|
+
let expectedTypeMatch = currentPosition + pattern.leftSidePath.length === resolvedVariable.path.length ? areCompatiblePatternTypes(pattern.patternType, expectedPatternType) : areCompatiblePatternTypes(
|
|
1406
|
+
pattern.patternType,
|
|
1407
|
+
CompilePatternType.RETURN
|
|
1408
|
+
);
|
|
1409
|
+
return leftTypeMatch && pathMatch && expectedTypeMatch;
|
|
1410
|
+
});
|
|
1411
|
+
if (currentMatch) {
|
|
1412
|
+
matchedPatterns.push(currentMatch);
|
|
1413
|
+
if (currentPosition + currentMatch.leftSidePath.length < resolvedVariable.path.length) {
|
|
1414
|
+
currentVariableType = currentMatch.returnType;
|
|
1415
|
+
currentPosition += currentMatch.leftSidePath.length;
|
|
1416
|
+
} else
|
|
1417
|
+
return {
|
|
1418
|
+
matchedPatterns,
|
|
1419
|
+
matchType: 0
|
|
1420
|
+
/* FULL */
|
|
1421
|
+
};
|
|
1422
|
+
} else
|
|
1423
|
+
return {
|
|
1424
|
+
matchedPatterns,
|
|
1425
|
+
matchType: matchedPatterns.length > 0 ? 1 : 2
|
|
1426
|
+
/* NONE */
|
|
1427
|
+
};
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
return {
|
|
1431
|
+
matchedPatterns: [],
|
|
1432
|
+
matchType: 2
|
|
1433
|
+
/* NONE */
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1436
|
+
getExpressionStatus(expression) {
|
|
1437
|
+
return this.analyzedExpressions.get(expression);
|
|
1438
|
+
}
|
|
1439
|
+
getStatementStatus(statement) {
|
|
1440
|
+
return this.analyzedStatements.get(statement);
|
|
1441
|
+
}
|
|
1442
|
+
getMatchedExpressions() {
|
|
1443
|
+
return this.analyzedExpressions.keys();
|
|
1444
|
+
}
|
|
1445
|
+
getAnalyzedStatements() {
|
|
1446
|
+
return this.analyzedStatements.keys();
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
function isChildOf(node, parent) {
|
|
1450
|
+
if (node === parent)
|
|
1451
|
+
return false;
|
|
1452
|
+
if (!node.parent)
|
|
1453
|
+
return false;
|
|
1454
|
+
for (const sibling of node.parent.getChildren())
|
|
1455
|
+
if (sibling === node)
|
|
1456
|
+
return true;
|
|
1457
|
+
return isChildOf(node.parent, parent);
|
|
1458
|
+
}
|
|
1459
|
+
var FindComponentConstructorType = /* @__PURE__ */ ((FindComponentConstructorType2) => {
|
|
1460
|
+
FindComponentConstructorType2["makeJayComponent"] = "makeJayComponent";
|
|
1461
|
+
FindComponentConstructorType2["makeJayTsxComponent"] = "makeJayTsxComponent";
|
|
1462
|
+
return FindComponentConstructorType2;
|
|
1463
|
+
})(FindComponentConstructorType || {});
|
|
1464
|
+
function findComponentConstructorCalls(findType, bindingResolver, node) {
|
|
1465
|
+
const foundConstructorCalls = [];
|
|
1466
|
+
if (ts.isVariableStatement(node)) {
|
|
1467
|
+
node.declarationList.declarations.forEach((declaration) => {
|
|
1468
|
+
if (declaration.initializer && ts.isCallExpression(declaration.initializer) && isIdentifierOrPropertyAccessExpression(declaration.initializer.expression)) {
|
|
1469
|
+
const explainedInitializer = bindingResolver.explain(
|
|
1470
|
+
declaration.initializer.expression
|
|
1471
|
+
);
|
|
1472
|
+
const flattened = flattenVariable(explainedInitializer);
|
|
1473
|
+
if (flattened.path.length === 1 && flattened.path[0] === findType && flattened.root && isImportModuleVariableRoot(flattened.root) && ts.isStringLiteral(flattened.root.module) && flattened.root.module.text === compilerShared.JAY_COMPONENT) {
|
|
1474
|
+
let render = findType === "makeJayComponent" ? declaration.initializer.arguments[0] : void 0;
|
|
1475
|
+
let comp = findType === "makeJayComponent" ? declaration.initializer.arguments[1] : declaration.initializer.arguments[0];
|
|
1476
|
+
let foundConstructor = {
|
|
1477
|
+
type: findType,
|
|
1478
|
+
name: declaration.name,
|
|
1479
|
+
render,
|
|
1480
|
+
comp
|
|
1481
|
+
};
|
|
1482
|
+
foundConstructorCalls.push(foundConstructor);
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
});
|
|
1486
|
+
}
|
|
1487
|
+
return foundConstructorCalls;
|
|
1488
|
+
}
|
|
1489
|
+
function findComponentConstructorCallsBlock(findType, bindingResolver, sourceFile) {
|
|
1490
|
+
const foundConstructorCalls = [];
|
|
1491
|
+
function visit(node) {
|
|
1492
|
+
foundConstructorCalls.push(
|
|
1493
|
+
...findComponentConstructorCalls(findType, bindingResolver, node)
|
|
1494
|
+
);
|
|
1495
|
+
ts.forEachChild(node, visit);
|
|
1496
|
+
}
|
|
1497
|
+
ts.forEachChild(sourceFile, visit);
|
|
1498
|
+
return foundConstructorCalls;
|
|
1499
|
+
}
|
|
1500
|
+
class GeneratedFunctionRepository {
|
|
1501
|
+
constructor(hasFunctionRepository, functionRepository) {
|
|
1502
|
+
this.hasFunctionRepository = hasFunctionRepository;
|
|
1503
|
+
this.functionRepository = functionRepository;
|
|
1504
|
+
}
|
|
1505
|
+
map(mapper) {
|
|
1506
|
+
return new GeneratedFunctionRepository(
|
|
1507
|
+
this.hasFunctionRepository,
|
|
1508
|
+
mapper(this.functionRepository)
|
|
1509
|
+
);
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
class FunctionRepositoryBuilder {
|
|
1513
|
+
constructor() {
|
|
1514
|
+
__publicField(this, "fragments", []);
|
|
1515
|
+
__publicField(this, "consts", []);
|
|
1516
|
+
__publicField(this, "nextIndex", 0);
|
|
1517
|
+
}
|
|
1518
|
+
addFunction(handlerCode) {
|
|
1519
|
+
if (!handlerCode)
|
|
1520
|
+
return void 0;
|
|
1521
|
+
const key = `${this.nextIndex++}`;
|
|
1522
|
+
this.fragments.push({ key, handlerCode });
|
|
1523
|
+
return key;
|
|
1524
|
+
}
|
|
1525
|
+
addConst(constCode) {
|
|
1526
|
+
if (!constCode)
|
|
1527
|
+
return;
|
|
1528
|
+
this.consts.push(constCode);
|
|
1529
|
+
}
|
|
1530
|
+
generate() {
|
|
1531
|
+
if (this.fragments.length > 0) {
|
|
1532
|
+
let fragments = [
|
|
1533
|
+
...new Set(this.fragments.map((_) => `'${_.key}': ${_.handlerCode}`))
|
|
1534
|
+
].join(",\n");
|
|
1535
|
+
let uniqueConstants = [...new Set(this.consts)];
|
|
1536
|
+
let constantsCodeFragment = uniqueConstants.length > 0 ? uniqueConstants.join("\n") + "\n\n" : "";
|
|
1537
|
+
let functionRepository = `${constantsCodeFragment}const funcRepository: FunctionsRepository = {
|
|
1538
|
+
${fragments}
|
|
1539
|
+
};`;
|
|
1540
|
+
return new GeneratedFunctionRepository(true, functionRepository);
|
|
1541
|
+
} else
|
|
1542
|
+
return new GeneratedFunctionRepository(
|
|
1543
|
+
false,
|
|
1544
|
+
"const funcRepository: FunctionsRepository = {}"
|
|
1545
|
+
);
|
|
1546
|
+
}
|
|
1547
|
+
generateGlobalFile() {
|
|
1548
|
+
return this.generate().map(
|
|
1549
|
+
(_) => `import {FunctionsRepository} from "@jay-framework/secure";
|
|
1550
|
+
|
|
1551
|
+
export ${_}`
|
|
1552
|
+
);
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
function findExec$(bindingResolver, sourceFile) {
|
|
1556
|
+
const foundExec$ = [];
|
|
1557
|
+
function visit(node) {
|
|
1558
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
|
|
1559
|
+
const functionVariable = bindingResolver.explain(node.expression);
|
|
1560
|
+
const accessChain = flattenVariable(functionVariable);
|
|
1561
|
+
if (accessChain.path.length === 1 && accessChain.path[0] === "exec$" && isImportModuleVariableRoot(accessChain.root) && ts.isStringLiteral(accessChain.root.module) && accessChain.root.module.text === "@jay-framework/secure")
|
|
1562
|
+
foundExec$.push(node);
|
|
1563
|
+
}
|
|
1564
|
+
ts.forEachChild(node, visit);
|
|
1565
|
+
}
|
|
1566
|
+
ts.forEachChild(sourceFile, visit);
|
|
1567
|
+
return foundExec$;
|
|
1568
|
+
}
|
|
1569
|
+
function analyzeGlobalExec$(context, analyzer, functionRepositoryBuilder, foundExec$) {
|
|
1570
|
+
const scopedAnalyzer = analyzer.analyzeForScope(foundExec$);
|
|
1571
|
+
let foundUnsafeExpression = false;
|
|
1572
|
+
const visitor = (node) => {
|
|
1573
|
+
if (ts.isExpression(node)) {
|
|
1574
|
+
const matchedPattern = scopedAnalyzer.getExpressionStatus(node);
|
|
1575
|
+
foundUnsafeExpression = foundUnsafeExpression || !matchedPattern || !matchedPattern.subExpressionsMatching;
|
|
1576
|
+
} else {
|
|
1577
|
+
node.getChildren().forEach((child) => ts.visitNode(child, visitor));
|
|
1578
|
+
}
|
|
1579
|
+
return node;
|
|
1580
|
+
};
|
|
1581
|
+
if (ts.isArrowFunction(foundExec$.arguments[0]))
|
|
1582
|
+
ts.visitNode(foundExec$.arguments[0].body, visitor);
|
|
1583
|
+
if (foundUnsafeExpression)
|
|
1584
|
+
return { foundExec$, wasTransformed: false };
|
|
1585
|
+
else {
|
|
1586
|
+
const key = functionRepositoryBuilder.addFunction(astToCode(foundExec$.arguments[0]));
|
|
1587
|
+
const transformedExec$ = codeToAst(`exec$(funcGlobal$('${key}'))`, context).map(
|
|
1588
|
+
(_) => _.expression
|
|
1589
|
+
)[0];
|
|
1590
|
+
return { foundExec$, wasTransformed: true, transformedExec$ };
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
function analyseGlobalExec$s(context, analyzer, functionRepositoryBuilder, foundExec$s) {
|
|
1594
|
+
return foundExec$s.map(
|
|
1595
|
+
(foundExec$) => analyzeGlobalExec$(context, analyzer, functionRepositoryBuilder, foundExec$)
|
|
1596
|
+
);
|
|
1597
|
+
}
|
|
1598
|
+
function transformedGlobalExec$toReplaceMap(transformedGlobalExec$s) {
|
|
1599
|
+
const map = /* @__PURE__ */ new Map();
|
|
1600
|
+
transformedGlobalExec$s.filter((_) => _.wasTransformed).forEach((_) => {
|
|
1601
|
+
map.set(_.foundExec$, _.transformedExec$);
|
|
1602
|
+
});
|
|
1603
|
+
return map;
|
|
1604
|
+
}
|
|
1605
|
+
function generateComponentConstructorCalls(context, componentConstructorCalls, hasFunctionRepository) {
|
|
1606
|
+
let optionsParam = hasFunctionRepository ? ", { funcRepository }" : "";
|
|
1607
|
+
let transformedConstructors = componentConstructorCalls.map(({ name, render }) => {
|
|
1608
|
+
return `${astToCode(name)} = makeJayComponentBridge(${astToCode(render)}${optionsParam})`;
|
|
1609
|
+
});
|
|
1610
|
+
if (transformedConstructors.length > 0) {
|
|
1611
|
+
let declarationCode = `export const ${transformedConstructors.join(", ")}`;
|
|
1612
|
+
return codeToAst(declarationCode, context)[0];
|
|
1613
|
+
} else
|
|
1614
|
+
return void 0;
|
|
1615
|
+
}
|
|
1616
|
+
function getRenderImportSpecifier(node) {
|
|
1617
|
+
const namedBindings = node.importClause?.namedBindings;
|
|
1618
|
+
switch (namedBindings?.kind) {
|
|
1619
|
+
case ts.SyntaxKind.NamedImports: {
|
|
1620
|
+
return namedBindings.elements.find((binding) => getImportName(binding) === "render");
|
|
1621
|
+
}
|
|
1622
|
+
default:
|
|
1623
|
+
return void 0;
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
function transformImport(node, importerMode, context, hasFunctionRepository) {
|
|
1627
|
+
if (ts.isStringLiteral(node.moduleSpecifier)) {
|
|
1628
|
+
if (findMakeJayComponentImport(compilerShared.MAKE_JAY_COMPONENT, node)) {
|
|
1629
|
+
const code = hasFunctionRepository ? `import { makeJayComponentBridge, FunctionsRepository } from '@jay-framework/secure';` : `import { makeJayComponentBridge } from '@jay-framework/secure';`;
|
|
1630
|
+
return codeToAst(code, context)[0];
|
|
1631
|
+
}
|
|
1632
|
+
const renderImportSpecifier = getRenderImportSpecifier(node);
|
|
1633
|
+
if (Boolean(renderImportSpecifier)) {
|
|
1634
|
+
const importModule = `${node.moduleSpecifier.text}${compilerShared.getModeFileExtension(
|
|
1635
|
+
true,
|
|
1636
|
+
importerMode
|
|
1637
|
+
)}`;
|
|
1638
|
+
return codeToAst(
|
|
1639
|
+
`import { ${astToCode(renderImportSpecifier)} } from '${importModule}'`,
|
|
1640
|
+
context
|
|
1641
|
+
)[0];
|
|
1642
|
+
}
|
|
1643
|
+
if (node.moduleSpecifier.text === "@jay-framework/runtime")
|
|
1644
|
+
return node;
|
|
1645
|
+
if (node.moduleSpecifier.text.endsWith(".css") && !node.importClause)
|
|
1646
|
+
return node;
|
|
1647
|
+
return void 0;
|
|
1648
|
+
}
|
|
1649
|
+
return void 0;
|
|
1650
|
+
}
|
|
1651
|
+
function transformSourceFile(sourceFile, factory, context, importerMode, componentConstructorCalls, componentFunctionRepository) {
|
|
1652
|
+
let { functionRepository, hasFunctionRepository } = componentFunctionRepository.generate();
|
|
1653
|
+
let generatedComponentConstructorCalls = generateComponentConstructorCalls(
|
|
1654
|
+
context,
|
|
1655
|
+
componentConstructorCalls,
|
|
1656
|
+
hasFunctionRepository
|
|
1657
|
+
);
|
|
1658
|
+
let transformedStatements = sourceFile.statements.map((statement) => {
|
|
1659
|
+
if (ts.isInterfaceDeclaration(statement))
|
|
1660
|
+
return statement;
|
|
1661
|
+
else if (ts.isImportDeclaration(statement))
|
|
1662
|
+
return transformImport(statement, importerMode, context, hasFunctionRepository);
|
|
1663
|
+
else
|
|
1664
|
+
return void 0;
|
|
1665
|
+
}).filter((_) => !!_);
|
|
1666
|
+
const funcRepositoryStatements = hasFunctionRepository ? codeToAst(functionRepository, context) : [];
|
|
1667
|
+
let allStatements = [
|
|
1668
|
+
...transformedStatements,
|
|
1669
|
+
...funcRepositoryStatements,
|
|
1670
|
+
generatedComponentConstructorCalls
|
|
1671
|
+
].filter((_) => !!_);
|
|
1672
|
+
return factory.updateSourceFile(sourceFile, allStatements);
|
|
1673
|
+
}
|
|
1674
|
+
function mkComponentBridgeTransformer({
|
|
1675
|
+
factory,
|
|
1676
|
+
sourceFile,
|
|
1677
|
+
context,
|
|
1678
|
+
importerMode,
|
|
1679
|
+
patterns,
|
|
1680
|
+
globalFunctionRepository
|
|
1681
|
+
}) {
|
|
1682
|
+
let bindingResolver = new SourceFileBindingResolver(sourceFile);
|
|
1683
|
+
let calls = findComponentConstructorCallsBlock(
|
|
1684
|
+
FindComponentConstructorType.makeJayComponent,
|
|
1685
|
+
bindingResolver,
|
|
1686
|
+
sourceFile
|
|
1687
|
+
);
|
|
1688
|
+
let constructorExpressions = calls.map(({ comp }) => comp);
|
|
1689
|
+
let constructorDefinitions = findComponentConstructorsBlock(constructorExpressions, sourceFile);
|
|
1690
|
+
let foundEventHandlers = constructorDefinitions.flatMap(
|
|
1691
|
+
(constructorDefinition) => findEventHandlersBlock(constructorDefinition, bindingResolver)
|
|
1692
|
+
);
|
|
1693
|
+
const elementsEventHandlers = filterEventHandlersToHaveJayEventType(
|
|
1694
|
+
foundEventHandlers,
|
|
1695
|
+
bindingResolver
|
|
1696
|
+
);
|
|
1697
|
+
let analyzer = new SourceFileStatementAnalyzer(sourceFile, bindingResolver, patterns);
|
|
1698
|
+
const componentFunctionRepository = new FunctionRepositoryBuilder();
|
|
1699
|
+
analyzeEventHandlers(
|
|
1700
|
+
context,
|
|
1701
|
+
bindingResolver,
|
|
1702
|
+
analyzer,
|
|
1703
|
+
factory,
|
|
1704
|
+
elementsEventHandlers,
|
|
1705
|
+
componentFunctionRepository
|
|
1706
|
+
);
|
|
1707
|
+
const foundExec$ = findExec$(bindingResolver, sourceFile);
|
|
1708
|
+
analyseGlobalExec$s(context, analyzer, globalFunctionRepository, foundExec$);
|
|
1709
|
+
return transformSourceFile(
|
|
1710
|
+
sourceFile,
|
|
1711
|
+
factory,
|
|
1712
|
+
context,
|
|
1713
|
+
importerMode,
|
|
1714
|
+
calls,
|
|
1715
|
+
componentFunctionRepository
|
|
1716
|
+
);
|
|
1717
|
+
}
|
|
1718
|
+
function transformComponentBridge(importerMode, patterns = [], globalFunctionRepository) {
|
|
1719
|
+
return mkTransformer(mkComponentBridgeTransformer, {
|
|
1720
|
+
importerMode,
|
|
1721
|
+
patterns,
|
|
1722
|
+
globalFunctionRepository
|
|
1723
|
+
});
|
|
1724
|
+
}
|
|
1725
|
+
function transformImportModeFileExtension(node, factory, importerMode) {
|
|
1726
|
+
if (!ts.isStringLiteral(node.moduleSpecifier))
|
|
1727
|
+
return void 0;
|
|
1728
|
+
const originalTarget = node.moduleSpecifier.text;
|
|
1729
|
+
if (!isRelativeImport(originalTarget))
|
|
1730
|
+
return node;
|
|
1731
|
+
return factory.updateImportDeclaration(
|
|
1732
|
+
node,
|
|
1733
|
+
node.modifiers,
|
|
1734
|
+
node.importClause,
|
|
1735
|
+
factory.createStringLiteral(`${originalTarget}${compilerShared.getModeFileExtension(true, importerMode)}`),
|
|
1736
|
+
node.attributes
|
|
1737
|
+
);
|
|
1738
|
+
}
|
|
1739
|
+
function findAfterImportStatementIndex(statements) {
|
|
1740
|
+
let lastIndex = 0;
|
|
1741
|
+
while (ts.isImportDeclaration(statements[lastIndex]))
|
|
1742
|
+
lastIndex += 1;
|
|
1743
|
+
return lastIndex;
|
|
1744
|
+
}
|
|
1745
|
+
function transformComponentImports(needsHandler$, needsFunc$, needsFuncGlobal$, transformedSourceFile, context, factory, sourceFile) {
|
|
1746
|
+
if (needsHandler$ || needsFunc$ || needsFuncGlobal$) {
|
|
1747
|
+
const statements = [...transformedSourceFile.statements];
|
|
1748
|
+
const afterImportStatementIndex = findAfterImportStatementIndex(statements);
|
|
1749
|
+
const importClause = [
|
|
1750
|
+
...needsHandler$ ? ["handler$"] : [],
|
|
1751
|
+
...needsFunc$ ? ["func$"] : [],
|
|
1752
|
+
...needsFuncGlobal$ ? ["funcGlobal$"] : []
|
|
1753
|
+
].join(", ");
|
|
1754
|
+
const allStatements = [
|
|
1755
|
+
...statements.slice(0, afterImportStatementIndex),
|
|
1756
|
+
codeToAst(
|
|
1757
|
+
`import { ${importClause} } from '${compilerShared.JAY_SECURE}';`,
|
|
1758
|
+
context
|
|
1759
|
+
)[0],
|
|
1760
|
+
...statements.slice(afterImportStatementIndex)
|
|
1761
|
+
];
|
|
1762
|
+
return factory.updateSourceFile(sourceFile, allStatements);
|
|
1763
|
+
} else
|
|
1764
|
+
return transformedSourceFile;
|
|
1765
|
+
}
|
|
1766
|
+
function isCssImport(node) {
|
|
1767
|
+
return ts.isStringLiteral(node.moduleSpecifier) && node.moduleSpecifier.text.endsWith(".css");
|
|
1768
|
+
}
|
|
1769
|
+
function mkComponentTransformer(sftContext) {
|
|
1770
|
+
const { patterns, globalFunctionRepository, context, factory, sourceFile } = sftContext;
|
|
1771
|
+
const bindingResolver = new SourceFileBindingResolver(sourceFile);
|
|
1772
|
+
const calls = findComponentConstructorCallsBlock(
|
|
1773
|
+
FindComponentConstructorType.makeJayComponent,
|
|
1774
|
+
bindingResolver,
|
|
1775
|
+
sourceFile
|
|
1776
|
+
);
|
|
1777
|
+
const constructorExpressions = calls.map(({ comp }) => comp);
|
|
1778
|
+
const constructorDefinitions = findComponentConstructorsBlock(
|
|
1779
|
+
constructorExpressions,
|
|
1780
|
+
sourceFile
|
|
1781
|
+
);
|
|
1782
|
+
const foundEventHandlers = constructorDefinitions.flatMap(
|
|
1783
|
+
(constructorDefinition) => findEventHandlersBlock(constructorDefinition, bindingResolver)
|
|
1784
|
+
);
|
|
1785
|
+
const elementsEventHandlers = filterEventHandlersToHaveJayEventType(
|
|
1786
|
+
foundEventHandlers,
|
|
1787
|
+
bindingResolver
|
|
1788
|
+
);
|
|
1789
|
+
const analyzer = new SourceFileStatementAnalyzer(sourceFile, bindingResolver, patterns);
|
|
1790
|
+
const componentFunctionRepository = new FunctionRepositoryBuilder();
|
|
1791
|
+
const transformedEventHandlers = analyzeEventHandlers(
|
|
1792
|
+
context,
|
|
1793
|
+
bindingResolver,
|
|
1794
|
+
analyzer,
|
|
1795
|
+
factory,
|
|
1796
|
+
elementsEventHandlers,
|
|
1797
|
+
componentFunctionRepository
|
|
1798
|
+
);
|
|
1799
|
+
const eventsReplaceMap = analyzedEventHandlersToReplaceMap(transformedEventHandlers);
|
|
1800
|
+
const foundExec$ = findExec$(bindingResolver, sourceFile);
|
|
1801
|
+
const transformedGlobalExec$ = analyseGlobalExec$s(
|
|
1802
|
+
context,
|
|
1803
|
+
analyzer,
|
|
1804
|
+
globalFunctionRepository,
|
|
1805
|
+
foundExec$
|
|
1806
|
+
);
|
|
1807
|
+
const globalExec$ReplaceMap = transformedGlobalExec$toReplaceMap(transformedGlobalExec$);
|
|
1808
|
+
const replaceMap = new Map([...eventsReplaceMap, ...globalExec$ReplaceMap]);
|
|
1809
|
+
let visitor = (node) => {
|
|
1810
|
+
if (replaceMap.has(node)) {
|
|
1811
|
+
node = replaceMap.get(node);
|
|
1812
|
+
return ts.visitEachChild(node, visitor, context);
|
|
1813
|
+
}
|
|
1814
|
+
if (ts.isImportDeclaration(node)) {
|
|
1815
|
+
if (isCssImport(node))
|
|
1816
|
+
return void 0;
|
|
1817
|
+
else
|
|
1818
|
+
return transformImportModeFileExtension(node, factory, compilerShared.RuntimeMode.WorkerSandbox);
|
|
1819
|
+
}
|
|
1820
|
+
return ts.visitEachChild(node, visitor, context);
|
|
1821
|
+
};
|
|
1822
|
+
let transformedSourceFile = ts.visitEachChild(sftContext.sourceFile, visitor, context);
|
|
1823
|
+
return transformComponentImports(
|
|
1824
|
+
transformedEventHandlers.length > 0,
|
|
1825
|
+
false,
|
|
1826
|
+
transformedGlobalExec$.length > 0,
|
|
1827
|
+
transformedSourceFile,
|
|
1828
|
+
context,
|
|
1829
|
+
factory,
|
|
1830
|
+
sourceFile
|
|
1831
|
+
);
|
|
1832
|
+
}
|
|
1833
|
+
function transformComponent(patterns = [], globalFunctionRepository) {
|
|
1834
|
+
return mkTransformer(mkComponentTransformer, { patterns, globalFunctionRepository });
|
|
1835
|
+
}
|
|
1836
|
+
function createTsSourceFileFromSource(filePath, sourceCode, scriptKind = ts__namespace.ScriptKind.TS) {
|
|
1837
|
+
try {
|
|
1838
|
+
return ts__namespace.createSourceFile(filePath, sourceCode, ts__namespace.ScriptTarget.Latest, true, scriptKind);
|
|
1839
|
+
} catch (error) {
|
|
1840
|
+
throw compilerShared.withOriginalTrace(
|
|
1841
|
+
new Error(`Failed to create TypeScript source file for ${filePath}`),
|
|
1842
|
+
error
|
|
1843
|
+
);
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
function generateImportsFileFromTsSource(filename, source) {
|
|
1847
|
+
const sourceFile = createTsSourceFileFromSource(filename, source);
|
|
1848
|
+
return fromImportModules(extractImportedModules(sourceFile));
|
|
1849
|
+
}
|
|
1850
|
+
function generateImportsFileFromJayFile(jayFile) {
|
|
1851
|
+
return fromImportModules(jayFile.imports.map((link) => link.module));
|
|
1852
|
+
}
|
|
1853
|
+
function fromImportModules(modules) {
|
|
1854
|
+
return modules.filter(isRelativeImport).map((module2) => `import '${module2}${compilerShared.JAY_QUERY_WORKER_TRUSTED}'`).join("\n");
|
|
1855
|
+
}
|
|
1856
|
+
function parseImportLinks(sourceFile) {
|
|
1857
|
+
const importDeclarations = extractImportDeclarations(sourceFile).filter(
|
|
1858
|
+
(importDeclaration) => ts__namespace.isStringLiteral(importDeclaration.moduleSpecifier)
|
|
1859
|
+
);
|
|
1860
|
+
const importLinks = importDeclarations.map((importDeclaration) => {
|
|
1861
|
+
const module2 = importDeclaration.moduleSpecifier.text;
|
|
1862
|
+
const sandbox = compilerShared.hasExtension(module2, compilerShared.JAY_QUERY_MAIN_SANDBOX) || compilerShared.hasExtension(module2, compilerShared.JAY_QUERY_WORKER_SANDBOX);
|
|
1863
|
+
const names = getJayImportNames(importDeclaration);
|
|
1864
|
+
return { module: module2, names, sandbox };
|
|
1865
|
+
});
|
|
1866
|
+
return importLinks;
|
|
1867
|
+
}
|
|
1868
|
+
function getJayImportNames(importDeclaration) {
|
|
1869
|
+
const importSpecifiers = getImportSpecifiers(importDeclaration);
|
|
1870
|
+
return importSpecifiers?.map((importSpecifier) => {
|
|
1871
|
+
const as = importSpecifier.propertyName?.text ? importSpecifier.name.text : void 0;
|
|
1872
|
+
const name = getImportName(importSpecifier);
|
|
1873
|
+
return {
|
|
1874
|
+
name,
|
|
1875
|
+
...as && { as },
|
|
1876
|
+
type: compilerShared.JayUnknown
|
|
1877
|
+
};
|
|
1878
|
+
}) || [];
|
|
1879
|
+
}
|
|
1880
|
+
function parseGenericTypescriptFile(filePath, code) {
|
|
1881
|
+
const sourceFile = createTsSourceFileFromSource(filePath, code);
|
|
1882
|
+
const imports = parseImportLinks(sourceFile);
|
|
1883
|
+
const filename = path.basename(filePath);
|
|
1884
|
+
const baseElementName = changeCase.capitalCase(
|
|
1885
|
+
compilerShared.hasExtension(filename, compilerShared.JAY_EXTENSION) ? compilerShared.withoutExtension(filename, compilerShared.JAY_TS_EXTENSION) : filename.split(".").shift(),
|
|
1886
|
+
{ delimiter: "" }
|
|
1887
|
+
);
|
|
1888
|
+
return new compilerShared.WithValidations(
|
|
1889
|
+
{
|
|
1890
|
+
format: compilerShared.SourceFileFormat.TypeScript,
|
|
1891
|
+
imports,
|
|
1892
|
+
baseElementName
|
|
1893
|
+
},
|
|
1894
|
+
[]
|
|
1895
|
+
);
|
|
1896
|
+
}
|
|
1897
|
+
function generateElementFile(jayFile, importerMode, generateTarget = compilerShared.GenerateTarget.jay) {
|
|
1898
|
+
return generateTarget === compilerShared.GenerateTarget.jay ? compilerJayHtml.generateElementFile(jayFile, importerMode) : compilerJayHtml.generateElementFileReactTarget(jayFile, importerMode);
|
|
1899
|
+
}
|
|
1900
|
+
Object.defineProperty(exports, "generateElementDefinitionFile", {
|
|
1901
|
+
enumerable: true,
|
|
1902
|
+
get: () => compilerJayHtml.generateElementDefinitionFile
|
|
1903
|
+
});
|
|
1904
|
+
exports.FunctionRepositoryBuilder = FunctionRepositoryBuilder;
|
|
1905
|
+
exports.compileFunctionSplitPatternsBlock = compileFunctionSplitPatternsBlock;
|
|
1906
|
+
exports.createTsSourceFileFromSource = createTsSourceFileFromSource;
|
|
1907
|
+
exports.extractImportDeclarations = extractImportDeclarations;
|
|
1908
|
+
exports.extractImportedModules = extractImportedModules;
|
|
1909
|
+
exports.generateElementFile = generateElementFile;
|
|
1910
|
+
exports.generateImportsFileFromJayFile = generateImportsFileFromJayFile;
|
|
1911
|
+
exports.generateImportsFileFromTsSource = generateImportsFileFromTsSource;
|
|
1912
|
+
exports.getImportName = getImportName;
|
|
1913
|
+
exports.getImportSpecifiers = getImportSpecifiers;
|
|
1914
|
+
exports.isRelativeImport = isRelativeImport;
|
|
1915
|
+
exports.parseGenericTypescriptFile = parseGenericTypescriptFile;
|
|
1916
|
+
exports.transformComponent = transformComponent;
|
|
1917
|
+
exports.transformComponentBridge = transformComponentBridge;
|
|
1918
|
+
exports.transformComponentImports = transformComponentImports;
|