jsxpression 0.1.40 → 0.2.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/lib/analyze/analysis-error.d.ts.map +1 -1
- package/lib/analyze/analysis-error.js +2 -7
- package/lib/analyze/analysis-error.js.map +1 -1
- package/lib/analyze/analysis-report.d.ts +13 -13
- package/lib/analyze/analysis-report.d.ts.map +1 -1
- package/lib/analyze/analysis-report.js +48 -45
- package/lib/analyze/analysis-report.js.map +1 -1
- package/lib/analyze/analyze.d.ts +1 -1
- package/lib/analyze/analyze.d.ts.map +1 -1
- package/lib/analyze/analyze.js +4 -4
- package/lib/analyze/analyze.js.map +1 -1
- package/lib/analyze/data/analyze.d.ts +1 -1
- package/lib/analyze/data/analyze.d.ts.map +1 -1
- package/lib/analyze/data/analyze.js +5 -5
- package/lib/analyze/data/analyze.js.map +1 -1
- package/lib/analyze/data/data-access.d.ts +1 -1
- package/lib/analyze/data/data-access.d.ts.map +1 -1
- package/lib/analyze/data/data-access.js +19 -15
- package/lib/analyze/data/data-access.js.map +1 -1
- package/lib/analyze/data/method-calls.d.ts +1 -1
- package/lib/analyze/data/method-calls.d.ts.map +1 -1
- package/lib/analyze/data/method-calls.js +5 -5
- package/lib/analyze/data/method-calls.js.map +1 -1
- package/lib/analyze/data/utils.d.ts +3 -3
- package/lib/analyze/data/utils.d.ts.map +1 -1
- package/lib/analyze/data/utils.js +6 -5
- package/lib/analyze/data/utils.js.map +1 -1
- package/lib/analyze/index.d.ts +1 -1
- package/lib/analyze/index.d.ts.map +1 -1
- package/lib/analyze/index.js +1 -1
- package/lib/analyze/index.js.map +1 -1
- package/lib/analyze/jsx/analyze.d.ts +1 -1
- package/lib/analyze/jsx/analyze.d.ts.map +1 -1
- package/lib/analyze/jsx/analyze.js +4 -4
- package/lib/analyze/jsx/analyze.js.map +1 -1
- package/lib/analyze/jsx/element-attributes.d.ts +1 -1
- package/lib/analyze/jsx/element-attributes.d.ts.map +1 -1
- package/lib/analyze/jsx/element-attributes.js +3 -3
- package/lib/analyze/jsx/element-attributes.js.map +1 -1
- package/lib/analyze/jsx/element-children.d.ts +1 -1
- package/lib/analyze/jsx/element-children.d.ts.map +1 -1
- package/lib/analyze/jsx/element-children.js +8 -9
- package/lib/analyze/jsx/element-children.js.map +1 -1
- package/lib/analyze/jsx/element-tags.d.ts +1 -1
- package/lib/analyze/jsx/element-tags.d.ts.map +1 -1
- package/lib/analyze/jsx/element-tags.js +2 -2
- package/lib/analyze/jsx/element-tags.js.map +1 -1
- package/lib/analyze/security/analyze.d.ts +1 -1
- package/lib/analyze/security/analyze.d.ts.map +1 -1
- package/lib/analyze/security/analyze.js +4 -4
- package/lib/analyze/security/analyze.js.map +1 -1
- package/lib/analyze/security/call-expressions.d.ts +1 -1
- package/lib/analyze/security/call-expressions.d.ts.map +1 -1
- package/lib/analyze/security/call-expressions.js +3 -5
- package/lib/analyze/security/call-expressions.js.map +1 -1
- package/lib/analyze/security/declarations.d.ts +1 -1
- package/lib/analyze/security/declarations.d.ts.map +1 -1
- package/lib/analyze/security/declarations.js +6 -6
- package/lib/analyze/security/declarations.js.map +1 -1
- package/lib/analyze/security/expressions.d.ts +1 -1
- package/lib/analyze/security/expressions.d.ts.map +1 -1
- package/lib/analyze/security/expressions.js +3 -6
- package/lib/analyze/security/expressions.js.map +1 -1
- package/lib/analyze/security/identifiers.d.ts +1 -1
- package/lib/analyze/security/identifiers.d.ts.map +1 -1
- package/lib/analyze/security/identifiers.js +19 -22
- package/lib/analyze/security/identifiers.js.map +1 -1
- package/lib/analyze/utils.d.ts +4 -4
- package/lib/analyze/utils.d.ts.map +1 -1
- package/lib/analyze/utils.js +5 -3
- package/lib/analyze/utils.js.map +1 -1
- package/lib/analyze/validation-context.d.ts +8 -8
- package/lib/analyze/validation-context.d.ts.map +1 -1
- package/lib/analyze/validation-context.js +23 -21
- package/lib/analyze/validation-context.js.map +1 -1
- package/lib/builtins.d.ts +6 -6
- package/lib/builtins.d.ts.map +1 -1
- package/lib/builtins.js +9 -8
- package/lib/builtins.js.map +1 -1
- package/lib/codegen/builtins/builtin-types.d.ts.map +1 -1
- package/lib/codegen/builtins/builtin-types.js +9 -13
- package/lib/codegen/builtins/builtin-types.js.map +1 -1
- package/lib/codegen/generate-typescript-definitions.d.ts +18 -17
- package/lib/codegen/generate-typescript-definitions.d.ts.map +1 -1
- package/lib/codegen/generate-typescript-definitions.js +19 -23
- package/lib/codegen/generate-typescript-definitions.js.map +1 -1
- package/lib/codegen/schema/component-types.d.ts.map +1 -1
- package/lib/codegen/schema/component-types.js +7 -4
- package/lib/codegen/schema/component-types.js.map +1 -1
- package/lib/codegen/schema/data-types.d.ts.map +1 -1
- package/lib/codegen/schema/data-types.js +1 -1
- package/lib/codegen/schema/data-types.js.map +1 -1
- package/lib/codegen/schema/function-types.js.map +1 -1
- package/lib/codegen/schema/utils.d.ts +4 -3
- package/lib/codegen/schema/utils.d.ts.map +1 -1
- package/lib/codegen/schema/utils.js +12 -8
- package/lib/codegen/schema/utils.js.map +1 -1
- package/lib/compile/compilation-error.d.ts +1 -1
- package/lib/compile/compilation-error.d.ts.map +1 -1
- package/lib/compile/compilation-error.js +3 -1
- package/lib/compile/compilation-error.js.map +1 -1
- package/lib/compile/compile.d.ts.map +1 -1
- package/lib/compile/compile.js +5 -11
- package/lib/compile/compile.js.map +1 -1
- package/lib/evaluate/evaluate.d.ts +6 -6
- package/lib/evaluate/evaluate.d.ts.map +1 -1
- package/lib/evaluate/evaluate.js +2 -2
- package/lib/evaluate/evaluate.js.map +1 -1
- package/lib/evaluate/evaluation-error.d.ts.map +1 -1
- package/lib/evaluate/evaluation-error.js +1 -0
- package/lib/evaluate/evaluation-error.js.map +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/jsx.d.ts +3 -3
- package/lib/jsx.d.ts.map +1 -1
- package/lib/jsx.js.map +1 -1
- package/lib/parse/parse-error.d.ts.map +1 -1
- package/lib/parse/parse-error.js +1 -0
- package/lib/parse/parse-error.js.map +1 -1
- package/lib/render.d.ts +25 -33
- package/lib/render.d.ts.map +1 -1
- package/lib/render.js +21 -26
- package/lib/render.js.map +1 -1
- package/lib/schema.d.ts +9 -9
- package/lib/schema.d.ts.map +1 -1
- package/lib/schema.js +1 -1
- package/lib/schema.js.map +1 -1
- package/lib/traverse.d.ts.map +1 -1
- package/lib/traverse.js +0 -1
- package/lib/traverse.js.map +1 -1
- package/lib/validate.d.ts +14 -17
- package/lib/validate.d.ts.map +1 -1
- package/lib/validate.js +13 -14
- package/lib/validate.js.map +1 -1
- package/package.json +14 -14
- package/src/analyze/analysis-error.ts +2 -6
- package/src/analyze/analysis-report.ts +73 -62
- package/src/analyze/analyze.test.ts +14 -18
- package/src/analyze/analyze.ts +4 -4
- package/src/analyze/data/analyze.ts +5 -8
- package/src/analyze/data/data-access.ts +49 -46
- package/src/analyze/data/method-calls.ts +9 -18
- package/src/analyze/data/utils.ts +15 -19
- package/src/analyze/index.ts +1 -1
- package/src/analyze/jsx/analyze.ts +4 -4
- package/src/analyze/jsx/element-attributes.ts +6 -19
- package/src/analyze/jsx/element-children.ts +9 -13
- package/src/analyze/jsx/element-tags.ts +2 -2
- package/src/analyze/security/analyze.ts +4 -4
- package/src/analyze/security/call-expressions.ts +5 -18
- package/src/analyze/security/declarations.ts +14 -43
- package/src/analyze/security/expressions.ts +12 -49
- package/src/analyze/security/identifiers.ts +39 -41
- package/src/analyze/utils.ts +25 -19
- package/src/analyze/validation-context.ts +32 -23
- package/src/builtins.ts +28 -39
- package/src/codegen/builtins/builtin-types.ts +13 -20
- package/src/codegen/generate-typescript-definitions.test.ts +29 -29
- package/src/codegen/generate-typescript-definitions.ts +19 -23
- package/src/codegen/schema/component-types.ts +22 -12
- package/src/codegen/schema/data-types.ts +6 -6
- package/src/codegen/schema/function-types.ts +1 -1
- package/src/codegen/schema/utils.ts +24 -23
- package/src/compile/compilation-error.ts +5 -1
- package/src/compile/compile.test.ts +7 -21
- package/src/compile/compile.ts +33 -45
- package/src/evaluate/evaluate.test.ts +95 -111
- package/src/evaluate/evaluate.ts +16 -21
- package/src/evaluate/evaluation-error.ts +1 -0
- package/src/index.ts +1 -7
- package/src/jsx.ts +4 -6
- package/src/parse/parse-error.ts +1 -0
- package/src/parse/parse.test.ts +1 -1
- package/src/render.test.ts +4 -4
- package/src/render.ts +27 -39
- package/src/schema.ts +12 -12
- package/src/traverse.test.ts +6 -6
- package/src/traverse.ts +15 -16
- package/src/validate.ts +14 -17
- package/CHANGELOG.md +0 -8
|
@@ -1,50 +1,56 @@
|
|
|
1
|
-
|
|
1
|
+
import type { PropertySchema } from "../../schema.js";
|
|
2
|
+
|
|
3
|
+
export function mapSchemaTypeToTypeScript(prop: PropertySchema, depth: number = 0): string {
|
|
2
4
|
switch (prop.type) {
|
|
3
5
|
case "string":
|
|
4
6
|
if (prop.enum && Array.isArray(prop.enum)) {
|
|
5
|
-
return prop.enum.map((value
|
|
7
|
+
return prop.enum.map((value) => `"${value}"`).join(" | ");
|
|
6
8
|
}
|
|
7
9
|
return "string";
|
|
8
10
|
case "number":
|
|
9
11
|
if (prop.enum && Array.isArray(prop.enum)) {
|
|
10
|
-
return prop.enum.map((value
|
|
12
|
+
return prop.enum.map((value) => String(value)).join(" | ");
|
|
11
13
|
}
|
|
12
14
|
return "number";
|
|
13
15
|
case "boolean":
|
|
14
16
|
if (prop.enum && Array.isArray(prop.enum)) {
|
|
15
|
-
return prop.enum.map((value
|
|
17
|
+
return prop.enum.map((value) => String(value)).join(" | ");
|
|
16
18
|
}
|
|
17
19
|
return "boolean";
|
|
18
|
-
case "array":
|
|
20
|
+
case "array": {
|
|
19
21
|
const itemType = prop.shape ? mapSchemaTypeToTypeScript(prop.shape, depth) : "any";
|
|
20
22
|
return `${itemType}[]`;
|
|
21
|
-
|
|
23
|
+
}
|
|
24
|
+
case "object": {
|
|
22
25
|
if (prop.shape && typeof prop.shape === "object") {
|
|
23
26
|
return generateObjectTypeWithJSDoc(prop.shape, depth);
|
|
24
27
|
}
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
// oxlint-disable-next-line typescript/no-explicit-any -- "properties" isn't an ObjectPropertySchema field; kept as a legacy fallback rather than removed by this type-only pass
|
|
29
|
+
const propAsAny = prop as any;
|
|
30
|
+
if (propAsAny.properties && typeof propAsAny.properties === "object") {
|
|
31
|
+
return generateObjectTypeWithJSDoc(propAsAny.properties, depth);
|
|
27
32
|
}
|
|
28
33
|
return "object";
|
|
29
|
-
|
|
34
|
+
}
|
|
35
|
+
case "record": {
|
|
30
36
|
const valueType = prop.shape ? mapSchemaTypeToTypeScript(prop.shape) : "any";
|
|
31
37
|
return `Record<string, ${valueType}>`;
|
|
38
|
+
}
|
|
32
39
|
case "function":
|
|
33
40
|
return "(...args: any[]) => any";
|
|
34
41
|
case "union": {
|
|
35
|
-
return
|
|
42
|
+
return prop.shape.map((p) => mapSchemaTypeToTypeScript(p)).join(" | ");
|
|
36
43
|
}
|
|
37
44
|
default:
|
|
38
|
-
console.warn(`Unknown schema type: ${prop.type}`);
|
|
39
45
|
return "any";
|
|
40
46
|
}
|
|
41
47
|
}
|
|
42
48
|
|
|
43
|
-
export function generateObjectTypeWithJSDoc(properties:
|
|
49
|
+
export function generateObjectTypeWithJSDoc(properties: Record<string, PropertySchema>, depth: number = 0): string {
|
|
44
50
|
let result = "{\n";
|
|
45
51
|
|
|
46
52
|
// Generate each property with inline JSDoc
|
|
47
|
-
Object.entries(properties).forEach(([key, value]
|
|
53
|
+
Object.entries(properties).forEach(([key, value]) => {
|
|
48
54
|
// Generate comprehensive JSDoc for this property
|
|
49
55
|
const propertyJSDoc = generatePropertyJSDoc(key, value, " ", depth);
|
|
50
56
|
result += propertyJSDoc;
|
|
@@ -59,13 +65,8 @@ export function generateObjectTypeWithJSDoc(properties: any, depth: number = 0):
|
|
|
59
65
|
return result;
|
|
60
66
|
}
|
|
61
67
|
|
|
62
|
-
export function generatePropertyJSDoc(
|
|
63
|
-
|
|
64
|
-
propertySchema: any,
|
|
65
|
-
indent: string = "",
|
|
66
|
-
_depth: number = 0
|
|
67
|
-
): string {
|
|
68
|
-
const comments: string[] = [];
|
|
68
|
+
export function generatePropertyJSDoc(_propertyName: string, propertySchema: PropertySchema, indent: string = "", _depth: number = 0): string {
|
|
69
|
+
const comments: Array<string> = [];
|
|
69
70
|
|
|
70
71
|
// Main description
|
|
71
72
|
if (propertySchema.description) {
|
|
@@ -76,16 +77,16 @@ export function generatePropertyJSDoc(
|
|
|
76
77
|
let hasNestedProperties = false;
|
|
77
78
|
if (propertySchema.type === "object" && propertySchema.shape) {
|
|
78
79
|
comments.push("");
|
|
79
|
-
Object.entries(propertySchema.shape).forEach(([key, value]
|
|
80
|
+
Object.entries(propertySchema.shape).forEach(([key, value]) => {
|
|
80
81
|
if (value.description) {
|
|
81
82
|
comments.push(`@property ${key} ${value.description}`);
|
|
82
83
|
hasNestedProperties = true;
|
|
83
84
|
}
|
|
84
85
|
});
|
|
85
|
-
} else if (propertySchema.type === "array" && propertySchema.shape
|
|
86
|
+
} else if (propertySchema.type === "array" && propertySchema.shape.type === "object" && propertySchema.shape.shape) {
|
|
86
87
|
// For arrays of objects, document the object structure
|
|
87
88
|
comments.push("");
|
|
88
|
-
Object.entries(propertySchema.shape.shape).forEach(([key, value]
|
|
89
|
+
Object.entries(propertySchema.shape.shape).forEach(([key, value]) => {
|
|
89
90
|
if (value.description) {
|
|
90
91
|
comments.push(`@property ${key} ${value.description}`);
|
|
91
92
|
hasNestedProperties = true;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Node } from "acorn";
|
|
2
|
+
|
|
1
3
|
type Loc = {
|
|
2
4
|
start: {
|
|
3
5
|
line: number;
|
|
@@ -9,8 +11,10 @@ type Loc = {
|
|
|
9
11
|
};
|
|
10
12
|
};
|
|
11
13
|
|
|
14
|
+
// oxlint-disable-next-line functional/no-classes -- extends Error, which requires a class
|
|
12
15
|
export class CompilationError extends Error {
|
|
13
|
-
static fromNode(message: string,
|
|
16
|
+
static fromNode(message: string, nodeParam: unknown): CompilationError {
|
|
17
|
+
const node = nodeParam as Node;
|
|
14
18
|
const loc = node.loc
|
|
15
19
|
? {
|
|
16
20
|
start: {
|
|
@@ -30,9 +30,7 @@ describe("compile", () => {
|
|
|
30
30
|
it("should compile nested ternary expressions", () => {
|
|
31
31
|
const ast = parse("<div>{props.level > 2 ? 'high' : props.level > 1 ? 'medium' : 'low'}</div>");
|
|
32
32
|
const result = compile(ast);
|
|
33
|
-
expect(result).toBe(
|
|
34
|
-
'"use strict";return h("div", null, ((props.level > 2)?"high":((props.level > 1)?"medium":"low")));'
|
|
35
|
-
);
|
|
33
|
+
expect(result).toBe('"use strict";return h("div", null, ((props.level > 2)?"high":((props.level > 1)?"medium":"low")));');
|
|
36
34
|
});
|
|
37
35
|
|
|
38
36
|
it("should compile nested JSX elements", () => {
|
|
@@ -44,9 +42,7 @@ describe("compile", () => {
|
|
|
44
42
|
it("should compile nested array operations", () => {
|
|
45
43
|
const ast = parse("<div>{props.items.map(x => x.split(',').map(y => y.trim()).join(' ')).join(' | ')}</div>");
|
|
46
44
|
const result = compile(ast);
|
|
47
|
-
expect(result).toBe(
|
|
48
|
-
'"use strict";return h("div", null, props.items.map((x) => x.split(",").map((y) => y.trim()).join(" ")).join(" | "));'
|
|
49
|
-
);
|
|
45
|
+
expect(result).toBe('"use strict";return h("div", null, props.items.map((x) => x.split(",").map((y) => y.trim()).join(" ")).join(" | "));');
|
|
50
46
|
});
|
|
51
47
|
|
|
52
48
|
it("should compile bare expression containers", () => {
|
|
@@ -217,23 +213,17 @@ describe("compile", () => {
|
|
|
217
213
|
it("should compile function with props parameter", () => {
|
|
218
214
|
const ast = parse('function Badge({ label }) {\n return <span>{label}</span>\n}\nreturn <Badge label="hi" />');
|
|
219
215
|
const result = compile(ast);
|
|
220
|
-
expect(result).toBe(
|
|
221
|
-
'"use strict";function Badge({ label }) { return h("span", null, label); }return h(Badge, { label: "hi" });'
|
|
222
|
-
);
|
|
216
|
+
expect(result).toBe('"use strict";function Badge({ label }) { return h("span", null, label); }return h(Badge, { label: "hi" });');
|
|
223
217
|
});
|
|
224
218
|
|
|
225
219
|
it("should compile function with default parameter", () => {
|
|
226
220
|
const ast = parse("function Badge({ label = 'default' }) {\n return <span>{label}</span>\n}\nreturn <Badge />");
|
|
227
221
|
const result = compile(ast);
|
|
228
|
-
expect(result).toBe(
|
|
229
|
-
'"use strict";function Badge({ label = "default" }) { return h("span", null, label); }return h(Badge, null);'
|
|
230
|
-
);
|
|
222
|
+
expect(result).toBe('"use strict";function Badge({ label = "default" }) { return h("span", null, label); }return h(Badge, null);');
|
|
231
223
|
});
|
|
232
224
|
|
|
233
225
|
it("should compile function with const inside body", () => {
|
|
234
|
-
const ast = parse(
|
|
235
|
-
"function Badge({ value }) {\n const doubled = value * 2;\n return <span>{doubled}</span>\n}\nreturn <Badge value={5} />"
|
|
236
|
-
);
|
|
226
|
+
const ast = parse("function Badge({ value }) {\n const doubled = value * 2;\n return <span>{doubled}</span>\n}\nreturn <Badge value={5} />");
|
|
237
227
|
const result = compile(ast);
|
|
238
228
|
expect(result).toContain("const doubled = (value * 2);");
|
|
239
229
|
expect(result).toContain('return h("span", null, doubled);');
|
|
@@ -248,9 +238,7 @@ describe("compile", () => {
|
|
|
248
238
|
});
|
|
249
239
|
|
|
250
240
|
it("should compile multiple function declarations", () => {
|
|
251
|
-
const ast = parse(
|
|
252
|
-
"function A() {\n return <span>a</span>\n}\nfunction B() {\n return <span>b</span>\n}\nreturn <div><A /><B /></div>"
|
|
253
|
-
);
|
|
241
|
+
const ast = parse("function A() {\n return <span>a</span>\n}\nfunction B() {\n return <span>b</span>\n}\nreturn <div><A /><B /></div>");
|
|
254
242
|
const result = compile(ast);
|
|
255
243
|
expect(result).toContain("function A()");
|
|
256
244
|
expect(result).toContain("function B()");
|
|
@@ -259,9 +247,7 @@ describe("compile", () => {
|
|
|
259
247
|
});
|
|
260
248
|
|
|
261
249
|
it("should compile function calling another function", () => {
|
|
262
|
-
const ast = parse(
|
|
263
|
-
"function Inner() {\n return <span>inner</span>\n}\nfunction Outer() {\n return <div><Inner /></div>\n}\nreturn <Outer />"
|
|
264
|
-
);
|
|
250
|
+
const ast = parse("function Inner() {\n return <span>inner</span>\n}\nfunction Outer() {\n return <div><Inner /></div>\n}\nreturn <Outer />");
|
|
265
251
|
const result = compile(ast);
|
|
266
252
|
expect(result).toContain("function Inner()");
|
|
267
253
|
expect(result).toContain("function Outer()");
|
package/src/compile/compile.ts
CHANGED
|
@@ -11,7 +11,6 @@ import type {
|
|
|
11
11
|
Super,
|
|
12
12
|
VariableDeclaration,
|
|
13
13
|
} from "acorn";
|
|
14
|
-
|
|
15
14
|
import {
|
|
16
15
|
isJsxElement,
|
|
17
16
|
isJsxEmptyExpression,
|
|
@@ -40,7 +39,7 @@ export function compile(ast: Program): string {
|
|
|
40
39
|
}
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
const parts: string
|
|
42
|
+
const parts: Array<string> = ['"use strict";'];
|
|
44
43
|
|
|
45
44
|
const hasDeclarations = ast.body.some((s) => s.type === "VariableDeclaration" || s.type === "FunctionDeclaration");
|
|
46
45
|
|
|
@@ -48,7 +47,7 @@ export function compile(ast: Program): string {
|
|
|
48
47
|
if (statement.type === "VariableDeclaration") {
|
|
49
48
|
parts.push(emitVariableDeclaration(statement, localFunctions));
|
|
50
49
|
} else if (statement.type === "FunctionDeclaration") {
|
|
51
|
-
parts.push(emitFunctionDeclaration(statement
|
|
50
|
+
parts.push(emitFunctionDeclaration(statement, localFunctions));
|
|
52
51
|
} else if (statement.type === "ReturnStatement" && statement.argument && isJsxRoot(statement.argument)) {
|
|
53
52
|
parts.push(`return ${emitJsxRoot(statement.argument, localFunctions)};`);
|
|
54
53
|
} else if (!hasDeclarations && statement.type === "ExpressionStatement" && isJsxRoot(statement.expression)) {
|
|
@@ -108,13 +107,13 @@ function emitJsxName(nameNode: JSXNameNode, localFunctions: Set<string>): string
|
|
|
108
107
|
return JSON.stringify(JSON.parse(left) + "." + JSON.parse(right));
|
|
109
108
|
}
|
|
110
109
|
default:
|
|
111
|
-
throw CompilationError.fromNode(`Unsupported JSX name: ${(nameNode as
|
|
110
|
+
throw CompilationError.fromNode(`Unsupported JSX name: ${(nameNode as { type: string }).type}`, nameNode);
|
|
112
111
|
}
|
|
113
112
|
}
|
|
114
113
|
|
|
115
|
-
function emitAttributes(attributes:
|
|
116
|
-
const parts: string
|
|
117
|
-
let currentObj: string
|
|
114
|
+
function emitAttributes(attributes: Array<JSXAttribute | JSXSpreadAttribute>, localFunctions: Set<string>): string {
|
|
115
|
+
const parts: Array<string> = [];
|
|
116
|
+
let currentObj: Array<string> = [];
|
|
118
117
|
|
|
119
118
|
const flushCurrent = (): void => {
|
|
120
119
|
if (currentObj.length) {
|
|
@@ -134,15 +133,15 @@ function emitAttributes(attributes: (JSXAttribute | JSXSpreadAttribute)[], local
|
|
|
134
133
|
throw CompilationError.fromNode("Only simple JSX attributes allowed", attribute);
|
|
135
134
|
}
|
|
136
135
|
|
|
137
|
-
const key = attribute.name?.name
|
|
136
|
+
const key = attribute.name?.name;
|
|
138
137
|
|
|
139
|
-
let value: string;
|
|
138
|
+
let value: string = "";
|
|
140
139
|
if (!attribute.value) {
|
|
141
140
|
value = "true";
|
|
142
141
|
} else if (attribute.value.type === "Literal") {
|
|
143
142
|
value = JSON.stringify(attribute.value.value);
|
|
144
143
|
} else if (attribute.value.type === "JSXExpressionContainer") {
|
|
145
|
-
value = emitExpression(attribute.value.expression
|
|
144
|
+
value = emitExpression(attribute.value.expression, localFunctions);
|
|
146
145
|
} else {
|
|
147
146
|
throw CompilationError.fromNode("Unsupported attribute value", attribute.value);
|
|
148
147
|
}
|
|
@@ -163,8 +162,8 @@ function emitAttributes(attributes: (JSXAttribute | JSXSpreadAttribute)[], local
|
|
|
163
162
|
return `Object.assign({}, ${parts.join(", ")})`;
|
|
164
163
|
}
|
|
165
164
|
|
|
166
|
-
function emitJsxChildren(children: JSXNode
|
|
167
|
-
const result: string
|
|
165
|
+
function emitJsxChildren(children: Array<JSXNode>, localFunctions: Set<string>): Array<string> {
|
|
166
|
+
const result: Array<string> = [];
|
|
168
167
|
|
|
169
168
|
for (const child of children) {
|
|
170
169
|
if (isJsxText(child)) {
|
|
@@ -174,7 +173,7 @@ function emitJsxChildren(children: JSXNode[], localFunctions: Set<string>): stri
|
|
|
174
173
|
}
|
|
175
174
|
} else if (isJsxExpressionContainer(child)) {
|
|
176
175
|
if (!isJsxEmptyExpression(child.expression)) {
|
|
177
|
-
result.push(emitExpression(child.expression
|
|
176
|
+
result.push(emitExpression(child.expression, localFunctions));
|
|
178
177
|
}
|
|
179
178
|
} else if (isJsxElement(child)) {
|
|
180
179
|
result.push(emitJsxElement(child, localFunctions));
|
|
@@ -195,7 +194,7 @@ function emitExpression(node: CompilableExpression, localFunctions: Set<string>)
|
|
|
195
194
|
case "Identifier":
|
|
196
195
|
return node.name;
|
|
197
196
|
case "TemplateLiteral": {
|
|
198
|
-
const bits: string
|
|
197
|
+
const bits: Array<string> = [];
|
|
199
198
|
node.quasis.forEach((quasi, index) => {
|
|
200
199
|
bits.push(JSON.stringify(quasi.value.cooked ?? ""));
|
|
201
200
|
if (node.expressions.length > index) {
|
|
@@ -210,10 +209,7 @@ function emitExpression(node: CompilableExpression, localFunctions: Set<string>)
|
|
|
210
209
|
return `${node.operator}${emitExpression(node.argument, localFunctions)}`;
|
|
211
210
|
case "BinaryExpression":
|
|
212
211
|
case "LogicalExpression":
|
|
213
|
-
return `(${emitExpression(node.left, localFunctions)} ${node.operator} ${emitExpression(
|
|
214
|
-
node.right,
|
|
215
|
-
localFunctions
|
|
216
|
-
)})`;
|
|
212
|
+
return `(${emitExpression(node.left, localFunctions)} ${node.operator} ${emitExpression(node.right, localFunctions)})`;
|
|
217
213
|
case "ConditionalExpression":
|
|
218
214
|
return `(${emitExpression(node.test, localFunctions)}?${emitExpression(
|
|
219
215
|
node.consequent,
|
|
@@ -226,16 +222,16 @@ function emitExpression(node: CompilableExpression, localFunctions: Set<string>)
|
|
|
226
222
|
return "undefined";
|
|
227
223
|
}
|
|
228
224
|
if (element.type === "SpreadElement") {
|
|
229
|
-
return `...${emitExpression(element.argument
|
|
225
|
+
return `...${emitExpression(element.argument, localFunctions)}`;
|
|
230
226
|
}
|
|
231
|
-
return emitExpression(element
|
|
227
|
+
return emitExpression(element, localFunctions);
|
|
232
228
|
})
|
|
233
229
|
.join(", ")}]`;
|
|
234
230
|
case "ObjectExpression": {
|
|
235
231
|
const keyValuePairs = node.properties
|
|
236
232
|
.map((property) => {
|
|
237
233
|
if (property.type === "SpreadElement") {
|
|
238
|
-
return `...${emitExpression(property.argument
|
|
234
|
+
return `...${emitExpression(property.argument, localFunctions)}`;
|
|
239
235
|
}
|
|
240
236
|
const key = getAstKeyString(property.key as Identifier | Literal);
|
|
241
237
|
return `${key}: ${emitExpression(property.value, localFunctions)}`;
|
|
@@ -245,12 +241,9 @@ function emitExpression(node: CompilableExpression, localFunctions: Set<string>)
|
|
|
245
241
|
}
|
|
246
242
|
case "MemberExpression": {
|
|
247
243
|
const obj = emitExpression(node.object, localFunctions);
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
} else {
|
|
252
|
-
prop = `.${getAstKeyString(node.property as Identifier | Literal)}`;
|
|
253
|
-
}
|
|
244
|
+
const prop: string = node.computed
|
|
245
|
+
? `[${emitExpression(node.property, localFunctions)}]`
|
|
246
|
+
: `.${getAstKeyString(node.property as Identifier | Literal)}`;
|
|
254
247
|
return `${obj}${prop}`;
|
|
255
248
|
}
|
|
256
249
|
case "CallExpression": {
|
|
@@ -258,17 +251,15 @@ function emitExpression(node: CompilableExpression, localFunctions: Set<string>)
|
|
|
258
251
|
const args = node.arguments
|
|
259
252
|
.map((argument) => {
|
|
260
253
|
if (argument.type === "SpreadElement") {
|
|
261
|
-
return `...${emitExpression(argument.argument
|
|
254
|
+
return `...${emitExpression(argument.argument, localFunctions)}`;
|
|
262
255
|
}
|
|
263
|
-
return emitExpression(argument
|
|
256
|
+
return emitExpression(argument, localFunctions);
|
|
264
257
|
})
|
|
265
258
|
.join(", ");
|
|
266
259
|
return `${callee}(${args})`;
|
|
267
260
|
}
|
|
268
261
|
case "ArrowFunctionExpression": {
|
|
269
|
-
const params = node.params
|
|
270
|
-
.map((param) => emitExpression(param as CompilableExpression, localFunctions))
|
|
271
|
-
.join(", ");
|
|
262
|
+
const params = node.params.map((param) => emitExpression(param as CompilableExpression, localFunctions)).join(", ");
|
|
272
263
|
const body = emitExpression(node.body as CompilableExpression, localFunctions);
|
|
273
264
|
return `(${params}) => ${body}`;
|
|
274
265
|
}
|
|
@@ -287,7 +278,7 @@ function emitVariableDeclaration(node: VariableDeclaration, localFunctions: Set<
|
|
|
287
278
|
const decls = node.declarations
|
|
288
279
|
.map((d) => {
|
|
289
280
|
const name = (d.id as Identifier).name;
|
|
290
|
-
const init = d.init ? emitExpression(d.init
|
|
281
|
+
const init = d.init ? emitExpression(d.init, localFunctions) : "undefined";
|
|
291
282
|
return `${name} = ${init}`;
|
|
292
283
|
})
|
|
293
284
|
.join(", ");
|
|
@@ -295,9 +286,9 @@ function emitVariableDeclaration(node: VariableDeclaration, localFunctions: Set<
|
|
|
295
286
|
}
|
|
296
287
|
|
|
297
288
|
function emitFunctionDeclaration(node: FunctionDeclaration, localFunctions: Set<string>): string {
|
|
298
|
-
const name = node.id
|
|
289
|
+
const name = node.id.name;
|
|
299
290
|
const params = node.params.map((p) => emitParam(p, localFunctions)).join(", ");
|
|
300
|
-
const body = emitFunctionBody(node.body
|
|
291
|
+
const body = emitFunctionBody(node.body, localFunctions);
|
|
301
292
|
return `function ${name}(${params}) ${body}`;
|
|
302
293
|
}
|
|
303
294
|
|
|
@@ -312,11 +303,11 @@ function emitStatement(statement: Statement, localFunctions: Set<string>): strin
|
|
|
312
303
|
if (!statement.argument) {
|
|
313
304
|
return "return;";
|
|
314
305
|
}
|
|
315
|
-
return `return ${emitExpression(statement.argument
|
|
306
|
+
return `return ${emitExpression(statement.argument, localFunctions)};`;
|
|
316
307
|
case "VariableDeclaration":
|
|
317
308
|
return emitVariableDeclaration(statement, localFunctions);
|
|
318
309
|
case "ExpressionStatement":
|
|
319
|
-
return `${emitExpression(statement.expression
|
|
310
|
+
return `${emitExpression(statement.expression, localFunctions)};`;
|
|
320
311
|
default:
|
|
321
312
|
throw CompilationError.fromNode(`Unsupported statement: ${statement.type}`, statement);
|
|
322
313
|
}
|
|
@@ -325,15 +316,15 @@ function emitStatement(statement: Statement, localFunctions: Set<string>): strin
|
|
|
325
316
|
function emitParam(param: Pattern, localFunctions: Set<string>): string {
|
|
326
317
|
switch (param.type) {
|
|
327
318
|
case "Identifier":
|
|
328
|
-
return
|
|
319
|
+
return param.name;
|
|
329
320
|
case "ObjectPattern": {
|
|
330
|
-
const props =
|
|
321
|
+
const props = param.properties.map((p) => {
|
|
331
322
|
if (p.type === "RestElement") {
|
|
332
323
|
return `...${emitParam(p.argument, localFunctions)}`;
|
|
333
324
|
}
|
|
334
325
|
const key = (p.key as Identifier).name;
|
|
335
326
|
if (p.value.type === "AssignmentPattern") {
|
|
336
|
-
return `${key} = ${emitExpression(p.value.right
|
|
327
|
+
return `${key} = ${emitExpression(p.value.right, localFunctions)}`;
|
|
337
328
|
}
|
|
338
329
|
if (p.value !== p.key && p.value.type === "Identifier" && p.value.name !== key) {
|
|
339
330
|
return `${key}: ${emitParam(p.value, localFunctions)}`;
|
|
@@ -343,12 +334,9 @@ function emitParam(param: Pattern, localFunctions: Set<string>): string {
|
|
|
343
334
|
return `{ ${props.join(", ")} }`;
|
|
344
335
|
}
|
|
345
336
|
case "AssignmentPattern":
|
|
346
|
-
return `${emitParam(
|
|
347
|
-
(param as any).right as CompilableExpression,
|
|
348
|
-
localFunctions
|
|
349
|
-
)}`;
|
|
337
|
+
return `${emitParam(param.left, localFunctions)} = ${emitExpression(param.right, localFunctions)}`;
|
|
350
338
|
case "RestElement":
|
|
351
|
-
return `...${emitParam(
|
|
339
|
+
return `...${emitParam(param.argument, localFunctions)}`;
|
|
352
340
|
default:
|
|
353
341
|
throw CompilationError.fromNode(`Unsupported parameter: ${param.type}`, param);
|
|
354
342
|
}
|