jsxpression 0.1.0 → 0.1.2
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 +7 -0
- package/lib/analyze/analysis-error.d.ts.map +1 -1
- package/lib/analyze/analysis-error.js +26 -0
- package/lib/analyze/analysis-error.js.map +1 -0
- package/lib/analyze/analysis-report.d.ts +2 -2
- package/lib/analyze/analysis-report.d.ts.map +1 -1
- package/lib/analyze/analyze.d.ts +5 -0
- package/lib/analyze/analyze.d.ts.map +1 -1
- package/lib/analyze/analyze.js +11 -0
- package/lib/analyze/analyze.js.map +1 -0
- package/lib/analyze/analyze.test.js +312 -312
- package/lib/analyze/analyze.test.js.map +1 -1
- package/lib/analyze/data/analyze.d.ts +5 -0
- package/lib/analyze/data/analyze.d.ts.map +1 -1
- package/lib/analyze/data/analyze.js +12 -0
- package/lib/analyze/data/analyze.js.map +1 -0
- package/lib/analyze/data/data-access.d.ts +7 -0
- package/lib/analyze/data/data-access.d.ts.map +1 -1
- package/lib/analyze/data/data-access.js +275 -0
- package/lib/analyze/data/data-access.js.map +1 -0
- package/lib/analyze/data/index.d.ts +2 -0
- package/lib/analyze/data/index.d.ts.map +1 -1
- package/lib/analyze/data/index.js +6 -0
- package/lib/analyze/data/index.js.map +1 -0
- package/lib/analyze/data/method-calls.d.ts +6 -0
- package/lib/analyze/data/method-calls.d.ts.map +1 -1
- package/lib/analyze/data/method-calls.js +58 -0
- package/lib/analyze/data/method-calls.js.map +1 -0
- package/lib/analyze/data/utils.d.ts +10 -0
- package/lib/analyze/data/utils.d.ts.map +1 -1
- package/lib/analyze/data/utils.js +212 -0
- package/lib/analyze/data/utils.js.map +1 -0
- package/lib/analyze/index.d.ts +4 -0
- package/lib/analyze/index.d.ts.map +1 -1
- package/lib/analyze/index.js +10 -0
- package/lib/analyze/index.js.map +1 -0
- package/lib/analyze/jsx/analyze.d.ts +5 -0
- package/lib/analyze/jsx/analyze.d.ts.map +1 -1
- package/lib/analyze/jsx/analyze.js +13 -0
- package/lib/analyze/jsx/analyze.js.map +1 -0
- package/lib/analyze/jsx/element-attributes.d.ts +6 -0
- package/lib/analyze/jsx/element-attributes.d.ts.map +1 -1
- package/lib/analyze/jsx/element-attributes.js +20 -20
- package/lib/analyze/jsx/element-attributes.js.map +1 -1
- package/lib/analyze/jsx/element-children.d.ts +6 -0
- package/lib/analyze/jsx/element-children.d.ts.map +1 -1
- package/lib/analyze/jsx/element-children.js +69 -0
- package/lib/analyze/jsx/element-children.js.map +1 -0
- package/lib/analyze/jsx/element-tags.d.ts +6 -0
- package/lib/analyze/jsx/element-tags.d.ts.map +1 -1
- package/lib/analyze/jsx/element-tags.js +41 -0
- package/lib/analyze/jsx/element-tags.js.map +1 -0
- package/lib/analyze/jsx/index.d.ts +2 -0
- package/lib/analyze/jsx/index.d.ts.map +1 -1
- package/lib/analyze/jsx/index.js +6 -0
- package/lib/analyze/jsx/index.js.map +1 -0
- package/lib/analyze/security/analyze.d.ts +5 -0
- package/lib/analyze/security/analyze.d.ts.map +1 -1
- package/lib/analyze/security/analyze.js +15 -0
- package/lib/analyze/security/analyze.js.map +1 -0
- package/lib/analyze/security/call-expressions.d.ts +6 -0
- package/lib/analyze/security/call-expressions.d.ts.map +1 -1
- package/lib/analyze/security/call-expressions.js +23 -0
- package/lib/analyze/security/call-expressions.js.map +1 -0
- package/lib/analyze/security/declarations.d.ts +6 -0
- package/lib/analyze/security/declarations.d.ts.map +1 -1
- package/lib/analyze/security/declarations.js +31 -0
- package/lib/analyze/security/declarations.js.map +1 -0
- package/lib/analyze/security/expressions.d.ts +6 -0
- package/lib/analyze/security/expressions.d.ts.map +1 -1
- package/lib/analyze/security/expressions.js +52 -0
- package/lib/analyze/security/expressions.js.map +1 -0
- package/lib/analyze/security/identifiers.d.ts +6 -0
- package/lib/analyze/security/identifiers.d.ts.map +1 -1
- package/lib/analyze/security/identifiers.js +87 -0
- package/lib/analyze/security/identifiers.js.map +1 -0
- package/lib/analyze/security/index.d.ts +2 -0
- package/lib/analyze/security/index.d.ts.map +1 -1
- package/lib/analyze/security/index.js +6 -0
- package/lib/analyze/security/index.js.map +1 -0
- package/lib/analyze/security/member-access.d.ts +6 -0
- package/lib/analyze/security/member-access.d.ts.map +1 -1
- package/lib/analyze/security/member-access.js +24 -0
- package/lib/analyze/security/member-access.js.map +1 -0
- package/lib/analyze/utils.d.ts.map +1 -0
- package/lib/analyze/utils.js +92 -0
- package/lib/analyze/utils.js.map +1 -0
- package/lib/analyze/validation-context.d.ts.map +1 -0
- package/lib/analyze/validation-context.js +27 -0
- package/lib/analyze/validation-context.js.map +1 -0
- package/lib/codegen/generate-typescript-definitions.test.js +190 -190
- package/lib/codegen/generate-typescript-definitions.test.js.map +1 -1
- package/lib/compile/compilation-error.d.ts.map +1 -0
- package/lib/compile/compilation-error.js +28 -0
- package/lib/compile/compilation-error.js.map +1 -0
- package/lib/compile/compile.d.ts +3 -0
- package/lib/compile/compile.d.ts.map +1 -1
- package/lib/compile/compile.js +17 -17
- package/lib/compile/compile.js.map +1 -1
- package/lib/compile/compile.test.js +110 -110
- package/lib/compile/compile.test.js.map +1 -1
- package/lib/compile/index.d.ts +3 -0
- package/lib/compile/index.d.ts.map +1 -0
- package/lib/compile/index.js +8 -0
- package/lib/compile/index.js.map +1 -0
- package/lib/evaluate/evaluate.js +9 -5
- package/lib/evaluate/evaluate.js.map +1 -0
- package/lib/evaluate/evaluate.test.d.ts.map +1 -0
- package/lib/evaluate/evaluate.test.js +252 -0
- package/lib/evaluate/evaluate.test.js.map +1 -0
- package/lib/evaluate/evaluation-error.js +6 -1
- package/lib/evaluate/evaluation-error.js.map +1 -0
- package/lib/evaluate/index.d.ts +3 -0
- package/lib/evaluate/index.d.ts.map +1 -0
- package/lib/evaluate/index.js +8 -0
- package/lib/evaluate/index.js.map +1 -0
- package/lib/index.d.ts +7 -7
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +12 -12
- package/lib/index.js.map +1 -1
- package/lib/jsx.d.ts +92 -0
- package/lib/jsx.d.ts.map +1 -0
- package/lib/jsx.js +43 -0
- package/lib/jsx.js.map +1 -0
- package/lib/parse/index.d.ts +3 -0
- package/lib/parse/index.d.ts.map +1 -0
- package/lib/parse/index.js +8 -0
- package/lib/parse/index.js.map +1 -0
- package/lib/parse/parse-error.d.ts.map +1 -0
- package/lib/parse/parse-error.js +13 -0
- package/lib/parse/parse-error.js.map +1 -0
- package/lib/parse/parse.d.ts +3 -0
- package/lib/parse/parse.d.ts.map +1 -0
- package/lib/parse/parse.js +35 -0
- package/lib/parse/parse.js.map +1 -0
- package/lib/parse/parse.test.d.ts.map +1 -0
- package/lib/parse/parse.test.js +82 -0
- package/lib/parse/parse.test.js.map +1 -0
- package/lib/render.d.ts +2 -2
- package/lib/render.d.ts.map +1 -1
- package/lib/render.js +13 -9
- package/lib/render.js.map +1 -0
- package/lib/render.test.js +303 -0
- package/lib/render.test.js.map +1 -0
- package/lib/schema.js +39 -18
- package/lib/schema.js.map +1 -0
- package/lib/traverse.d.ts +15 -0
- package/lib/traverse.d.ts.map +1 -0
- package/lib/traverse.js +49 -0
- package/lib/traverse.js.map +1 -0
- package/lib/traverse.test.d.ts.map +1 -0
- package/lib/traverse.test.js +86 -0
- package/lib/traverse.test.js.map +1 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +3 -0
- package/lib/types.js.map +1 -0
- package/lib/validate.d.ts +3 -3
- package/lib/validate.d.ts.map +1 -1
- package/lib/validate.js +11 -7
- package/lib/validate.js.map +1 -0
- package/package.json +2 -1
- package/src/analyze/analysis-error.ts +1 -1
- package/src/analyze/analysis-report.ts +2 -2
- package/src/analyze/analyze.test.ts +4 -4
- package/src/analyze/analyze.ts +5 -5
- package/src/analyze/data/analyze.ts +5 -5
- package/src/analyze/data/data-access.ts +6 -6
- package/src/analyze/data/index.ts +1 -1
- package/src/analyze/data/method-calls.ts +7 -7
- package/src/analyze/data/utils.ts +5 -5
- package/src/analyze/index.ts +3 -3
- package/src/analyze/jsx/analyze.ts +6 -6
- package/src/analyze/jsx/element-attributes.ts +6 -6
- package/src/analyze/jsx/element-children.ts +6 -6
- package/src/analyze/jsx/element-tags.ts +5 -5
- package/src/analyze/jsx/index.ts +1 -1
- package/src/analyze/security/analyze.ts +8 -8
- package/src/analyze/security/call-expressions.ts +5 -5
- package/src/analyze/security/declarations.ts +5 -5
- package/src/analyze/security/expressions.ts +5 -5
- package/src/analyze/security/identifiers.ts +6 -6
- package/src/analyze/security/index.ts +1 -1
- package/src/analyze/security/member-access.ts +5 -5
- package/src/codegen/generate-typescript-definitions.test.ts +2 -2
- package/src/compile/compile.test.ts +2 -2
- package/src/compile/compile.ts +2 -2
- package/src/compile/index.ts +2 -2
- package/src/evaluate/evaluate.test.ts +4 -4
- package/src/evaluate/evaluate.ts +1 -1
- package/src/evaluate/index.ts +2 -2
- package/src/index.ts +7 -7
- package/src/parse/index.ts +2 -2
- package/src/parse/parse.test.ts +2 -2
- package/src/parse/parse.ts +1 -1
- package/src/render.test.ts +4 -4
- package/src/render.ts +5 -5
- package/src/traverse.test.ts +2 -2
- package/src/traverse.ts +1 -1
- package/src/validate.ts +3 -3
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
(0,
|
|
3
|
+
const vitest_js_1 = require("vitest.js");
|
|
4
|
+
const index_js_1 = require("./analyze/index.js");
|
|
5
|
+
const index_js_2 = require("../parse/index.js");
|
|
6
|
+
const builtins_js_1 = require("../builtins.js");
|
|
7
|
+
(0, vitest_js_1.describe)("analyze - consolidated tests", () => {
|
|
8
8
|
const baseSchema = {
|
|
9
9
|
data: {
|
|
10
10
|
user: {
|
|
@@ -71,164 +71,164 @@ const builtins_1 = require("../builtins");
|
|
|
71
71
|
span: { props: {} },
|
|
72
72
|
},
|
|
73
73
|
};
|
|
74
|
-
(0,
|
|
75
|
-
(0,
|
|
76
|
-
(0,
|
|
77
|
-
const ast = (0,
|
|
78
|
-
const result = (0,
|
|
79
|
-
(0,
|
|
80
|
-
});
|
|
81
|
-
(0,
|
|
82
|
-
const ast = (0,
|
|
83
|
-
const result = (0,
|
|
84
|
-
(0,
|
|
85
|
-
});
|
|
86
|
-
(0,
|
|
87
|
-
const ast = (0,
|
|
88
|
-
const result = (0,
|
|
89
|
-
(0,
|
|
90
|
-
(0,
|
|
91
|
-
});
|
|
92
|
-
(0,
|
|
93
|
-
const ast = (0,
|
|
94
|
-
const result = (0,
|
|
95
|
-
(0,
|
|
96
|
-
(0,
|
|
74
|
+
(0, vitest_js_1.describe)("data access validation", () => {
|
|
75
|
+
(0, vitest_js_1.describe)("basic data access", () => {
|
|
76
|
+
(0, vitest_js_1.it)("should allow valid data access", () => {
|
|
77
|
+
const ast = (0, index_js_2.parse)("<Text>{data.user.name}</Text>");
|
|
78
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
79
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
80
|
+
});
|
|
81
|
+
(0, vitest_js_1.it)("should allow nested object access", () => {
|
|
82
|
+
const ast = (0, index_js_2.parse)("<Text>{data.user.profile.avatar}</Text>");
|
|
83
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
84
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
85
|
+
});
|
|
86
|
+
(0, vitest_js_1.it)("should block invalid data properties", () => {
|
|
87
|
+
const ast = (0, index_js_2.parse)("<Text>{data.user.invalid}</Text>");
|
|
88
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
89
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(true);
|
|
90
|
+
(0, vitest_js_1.expect)(result.errors[0].message).toContain("Property 'data.user.invalid' does not exist in schema");
|
|
91
|
+
});
|
|
92
|
+
(0, vitest_js_1.it)("should block invalid nested properties", () => {
|
|
93
|
+
const ast = (0, index_js_2.parse)("<Text>{data.user.profile.invalid}</Text>");
|
|
94
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
95
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(true);
|
|
96
|
+
(0, vitest_js_1.expect)(result.errors[0].message).toContain("Property 'data.user.profile.invalid' does not exist in schema");
|
|
97
97
|
});
|
|
98
98
|
});
|
|
99
|
-
(0,
|
|
100
|
-
(0,
|
|
101
|
-
const ast = (0,
|
|
102
|
-
const result = (0,
|
|
103
|
-
(0,
|
|
104
|
-
});
|
|
105
|
-
(0,
|
|
106
|
-
const ast = (0,
|
|
107
|
-
const result = (0,
|
|
108
|
-
(0,
|
|
109
|
-
});
|
|
110
|
-
(0,
|
|
111
|
-
const ast = (0,
|
|
112
|
-
const result = (0,
|
|
113
|
-
(0,
|
|
114
|
-
});
|
|
115
|
-
(0,
|
|
116
|
-
const ast = (0,
|
|
117
|
-
const result = (0,
|
|
118
|
-
(0,
|
|
119
|
-
});
|
|
120
|
-
(0,
|
|
121
|
-
const ast = (0,
|
|
122
|
-
const result = (0,
|
|
123
|
-
(0,
|
|
124
|
-
(0,
|
|
125
|
-
});
|
|
126
|
-
(0,
|
|
127
|
-
const ast = (0,
|
|
128
|
-
const result = (0,
|
|
129
|
-
(0,
|
|
130
|
-
(0,
|
|
131
|
-
(0,
|
|
132
|
-
});
|
|
133
|
-
(0,
|
|
134
|
-
const ast = (0,
|
|
135
|
-
const result = (0,
|
|
136
|
-
(0,
|
|
137
|
-
});
|
|
138
|
-
(0,
|
|
139
|
-
const ast = (0,
|
|
140
|
-
const result = (0,
|
|
141
|
-
(0,
|
|
142
|
-
});
|
|
143
|
-
(0,
|
|
144
|
-
const ast = (0,
|
|
145
|
-
const result = (0,
|
|
146
|
-
(0,
|
|
147
|
-
});
|
|
148
|
-
(0,
|
|
149
|
-
const ast = (0,
|
|
150
|
-
const result = (0,
|
|
151
|
-
(0,
|
|
152
|
-
});
|
|
153
|
-
(0,
|
|
154
|
-
const ast = (0,
|
|
155
|
-
const result = (0,
|
|
156
|
-
(0,
|
|
157
|
-
(0,
|
|
158
|
-
});
|
|
159
|
-
(0,
|
|
160
|
-
const ast = (0,
|
|
161
|
-
const result = (0,
|
|
162
|
-
(0,
|
|
163
|
-
(0,
|
|
164
|
-
});
|
|
165
|
-
(0,
|
|
166
|
-
const ast = (0,
|
|
167
|
-
const result = (0,
|
|
168
|
-
(0,
|
|
169
|
-
(0,
|
|
99
|
+
(0, vitest_js_1.describe)("array access", () => {
|
|
100
|
+
(0, vitest_js_1.it)("should allow array access with valid methods", () => {
|
|
101
|
+
const ast = (0, index_js_2.parse)("<Text>{data.items.map(item => item)}</Text>");
|
|
102
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
103
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
104
|
+
});
|
|
105
|
+
(0, vitest_js_1.it)("should allow numeric array index access", () => {
|
|
106
|
+
const ast = (0, index_js_2.parse)("<Text>{data.items[0]}</Text>");
|
|
107
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
108
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
109
|
+
});
|
|
110
|
+
(0, vitest_js_1.it)("should allow various numeric array indices", () => {
|
|
111
|
+
const ast = (0, index_js_2.parse)("<Text>{data.items[42]} and {data.numbers[1]}</Text>");
|
|
112
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
113
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
114
|
+
});
|
|
115
|
+
(0, vitest_js_1.it)("should allow nested array access with indices", () => {
|
|
116
|
+
const ast = (0, index_js_2.parse)("<Text>{data.products[0].tags[1]}</Text>");
|
|
117
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
118
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
119
|
+
});
|
|
120
|
+
(0, vitest_js_1.it)("should require array indices for nested object access", () => {
|
|
121
|
+
const ast = (0, index_js_2.parse)("<Text>{data.products.tags}</Text>");
|
|
122
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
123
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(true);
|
|
124
|
+
(0, vitest_js_1.expect)(result.errors[0].message).toContain("data.products.tags");
|
|
125
|
+
});
|
|
126
|
+
(0, vitest_js_1.it)("should detect typos on array properties", () => {
|
|
127
|
+
const ast = (0, index_js_2.parse)("<Text>{data.departments.lengdth}</Text>");
|
|
128
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
129
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(true);
|
|
130
|
+
(0, vitest_js_1.expect)(result.errors[0].code).toBe("INVALID_DATA_ACCESS");
|
|
131
|
+
(0, vitest_js_1.expect)(result.errors[0].suggestions).toContain("length");
|
|
132
|
+
});
|
|
133
|
+
(0, vitest_js_1.it)("should allow string members on array elements", () => {
|
|
134
|
+
const ast = (0, index_js_2.parse)("<Text>{data.items[0].length}</Text>");
|
|
135
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
136
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
137
|
+
});
|
|
138
|
+
(0, vitest_js_1.it)("should allow array.at() method with positive index", () => {
|
|
139
|
+
const ast = (0, index_js_2.parse)("<Text>{data.items.at(0)}</Text>");
|
|
140
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
141
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
142
|
+
});
|
|
143
|
+
(0, vitest_js_1.it)("should allow array.at() method with negative index", () => {
|
|
144
|
+
const ast = (0, index_js_2.parse)("<Text>{data.items.at(-1)}</Text>");
|
|
145
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
146
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
147
|
+
});
|
|
148
|
+
(0, vitest_js_1.it)("should allow array.at() method in complex expressions", () => {
|
|
149
|
+
const ast = (0, index_js_2.parse)("<Text>{data.products.at(-1).name}</Text>");
|
|
150
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
151
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
152
|
+
});
|
|
153
|
+
(0, vitest_js_1.it)("should block dynamic array access with variables", () => {
|
|
154
|
+
const ast = (0, index_js_2.parse)("<Text>{data.items[variable]}</Text>");
|
|
155
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
156
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(true);
|
|
157
|
+
(0, vitest_js_1.expect)(result.errors.some((e) => e.message.includes("variable") || e.message.includes("not allowed"))).toBe(true);
|
|
158
|
+
});
|
|
159
|
+
(0, vitest_js_1.it)("should block string-based computed access on objects", () => {
|
|
160
|
+
const ast = (0, index_js_2.parse)("<Text>{data.user['name']}</Text>");
|
|
161
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
162
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(true);
|
|
163
|
+
(0, vitest_js_1.expect)(result.errors.some((e) => e.message.includes("computed member access not allowed"))).toBe(true);
|
|
164
|
+
});
|
|
165
|
+
(0, vitest_js_1.it)("should block mutating array methods", () => {
|
|
166
|
+
const ast = (0, index_js_2.parse)("<Text>{data.items.push('new')}</Text>");
|
|
167
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
168
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(true);
|
|
169
|
+
(0, vitest_js_1.expect)(result.errors[0].message).toContain("method .push not allowed");
|
|
170
170
|
});
|
|
171
171
|
});
|
|
172
|
-
(0,
|
|
173
|
-
(0,
|
|
174
|
-
const ast = (0,
|
|
175
|
-
const result = (0,
|
|
176
|
-
(0,
|
|
177
|
-
});
|
|
178
|
-
(0,
|
|
179
|
-
const ast = (0,
|
|
180
|
-
const result = (0,
|
|
181
|
-
(0,
|
|
182
|
-
(0,
|
|
183
|
-
});
|
|
184
|
-
(0,
|
|
185
|
-
const ast = (0,
|
|
186
|
-
const result = (0,
|
|
187
|
-
(0,
|
|
188
|
-
});
|
|
189
|
-
(0,
|
|
190
|
-
const ast = (0,
|
|
191
|
-
const result = (0,
|
|
192
|
-
(0,
|
|
193
|
-
(0,
|
|
194
|
-
});
|
|
195
|
-
(0,
|
|
196
|
-
const ast = (0,
|
|
197
|
-
const result = (0,
|
|
198
|
-
(0,
|
|
199
|
-
});
|
|
200
|
-
(0,
|
|
201
|
-
const ast = (0,
|
|
202
|
-
const result = (0,
|
|
203
|
-
(0,
|
|
204
|
-
(0,
|
|
205
|
-
});
|
|
206
|
-
(0,
|
|
207
|
-
const ast = (0,
|
|
208
|
-
const result = (0,
|
|
209
|
-
(0,
|
|
210
|
-
});
|
|
211
|
-
(0,
|
|
212
|
-
const ast = (0,
|
|
213
|
-
const result = (0,
|
|
214
|
-
(0,
|
|
215
|
-
(0,
|
|
216
|
-
(0,
|
|
172
|
+
(0, vitest_js_1.describe)("arrow function parameter validation", () => {
|
|
173
|
+
(0, vitest_js_1.it)("should validate arrow function parameters - valid access", () => {
|
|
174
|
+
const ast = (0, index_js_2.parse)("<Text>{data.products.map((product, i) => product.name)}</Text>");
|
|
175
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
176
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
177
|
+
});
|
|
178
|
+
(0, vitest_js_1.it)("should validate arrow function parameters - invalid property", () => {
|
|
179
|
+
const ast = (0, index_js_2.parse)("<Text>{data.products.map((product, i) => product.invalid)}</Text>");
|
|
180
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
181
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(true);
|
|
182
|
+
(0, vitest_js_1.expect)(result.errors[0].message).toContain("Property 'invalid' does not exist on parameter 'product'");
|
|
183
|
+
});
|
|
184
|
+
(0, vitest_js_1.it)("should validate nested arrow functions", () => {
|
|
185
|
+
const ast = (0, index_js_2.parse)("<Text>{data.products.map(product => product.tags.map(tag => tag))}</Text>");
|
|
186
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
187
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
188
|
+
});
|
|
189
|
+
(0, vitest_js_1.it)("should catch errors in nested arrow functions", () => {
|
|
190
|
+
const ast = (0, index_js_2.parse)("<Text>{data.products.map(product => product.tags.map(tag => tag.invalid))}</Text>");
|
|
191
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
192
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(true);
|
|
193
|
+
(0, vitest_js_1.expect)(result.errors[0].message).toContain("Cannot access property 'invalid' on string type");
|
|
194
|
+
});
|
|
195
|
+
(0, vitest_js_1.it)("should validate index parameters", () => {
|
|
196
|
+
const ast = (0, index_js_2.parse)("<Text>{data.items.map((item, i) => i + 1)}</Text>");
|
|
197
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
198
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
199
|
+
});
|
|
200
|
+
(0, vitest_js_1.it)("should catch invalid index parameter access", () => {
|
|
201
|
+
const ast = (0, index_js_2.parse)("<Text>{data.items.map((item, i) => i.invalid)}</Text>");
|
|
202
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
203
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(true);
|
|
204
|
+
(0, vitest_js_1.expect)(result.errors[0].message).toContain("Cannot access property 'invalid' on number type");
|
|
205
|
+
});
|
|
206
|
+
(0, vitest_js_1.it)("should handle complex nested scenarios", () => {
|
|
207
|
+
const ast = (0, index_js_2.parse)("<Text>{data.departments.map((dept) => dept.employees.map((employee) => employee.salary))}</Text>");
|
|
208
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
209
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
210
|
+
});
|
|
211
|
+
(0, vitest_js_1.it)("should detect typos in complex nested scenarios", () => {
|
|
212
|
+
const ast = (0, index_js_2.parse)("<Text>{data.departments.map((dept) => dept.employees.map((employee) => employee.saladry))}</Text>");
|
|
213
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
214
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(true);
|
|
215
|
+
(0, vitest_js_1.expect)(result.errors[0].message).toContain("Property 'saladry' does not exist on parameter 'employee'");
|
|
216
|
+
(0, vitest_js_1.expect)(result.errors[0].suggestions).toEqual(["name", "role", "salary"]);
|
|
217
217
|
});
|
|
218
218
|
});
|
|
219
219
|
});
|
|
220
|
-
(0,
|
|
220
|
+
(0, vitest_js_1.describe)("method calls validation", () => {
|
|
221
221
|
// Dynamic builtin schema tests - generates tests for all methods in BUILTINS
|
|
222
|
-
(0,
|
|
223
|
-
const builtins = (0,
|
|
222
|
+
(0, vitest_js_1.describe)("builtin methods - dynamic validation", () => {
|
|
223
|
+
const builtins = (0, builtins_js_1.getBuiltins)();
|
|
224
224
|
// Test each builtin object (Math, Array.prototype, String.prototype)
|
|
225
225
|
Object.entries(builtins).forEach(([objectName, schema]) => {
|
|
226
226
|
if (!schema.methods)
|
|
227
227
|
return;
|
|
228
|
-
(0,
|
|
228
|
+
(0, vitest_js_1.describe)(`${objectName} methods`, () => {
|
|
229
229
|
Object.entries(schema.methods).forEach(([methodName, methodDef]) => {
|
|
230
230
|
const displayName = objectName === "Math" ? `Math.${methodName}` : methodName;
|
|
231
|
-
(0,
|
|
231
|
+
(0, vitest_js_1.it)(`should allow ${displayName} with valid parameters`, () => {
|
|
232
232
|
let testExpression;
|
|
233
233
|
if (objectName === "Math") {
|
|
234
234
|
// Math methods
|
|
@@ -296,15 +296,15 @@ const builtins_1 = require("../builtins");
|
|
|
296
296
|
// Fallback
|
|
297
297
|
testExpression = `<Text>{${objectName}.${methodName}()}</Text>`;
|
|
298
298
|
}
|
|
299
|
-
const ast = (0,
|
|
300
|
-
const result = (0,
|
|
301
|
-
(0,
|
|
299
|
+
const ast = (0, index_js_2.parse)(testExpression);
|
|
300
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
301
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
302
302
|
});
|
|
303
303
|
// Test parameter validation for methods that have parameter constraints
|
|
304
304
|
const requiredParams = methodDef.params.filter((p) => p.required);
|
|
305
305
|
const nonVariadicParams = methodDef.params.filter((p) => !p.variadic);
|
|
306
306
|
if (requiredParams.length > 0) {
|
|
307
|
-
(0,
|
|
307
|
+
(0, vitest_js_1.it)(`should validate ${displayName} minimum parameters`, () => {
|
|
308
308
|
let testExpression;
|
|
309
309
|
if (objectName === "Math") {
|
|
310
310
|
testExpression = `<Text>{Math.${methodName}()}</Text>`;
|
|
@@ -318,15 +318,15 @@ const builtins_1 = require("../builtins");
|
|
|
318
318
|
else {
|
|
319
319
|
testExpression = `<Text>{${objectName}.${methodName}()}</Text>`;
|
|
320
320
|
}
|
|
321
|
-
const ast = (0,
|
|
322
|
-
const result = (0,
|
|
323
|
-
(0,
|
|
324
|
-
(0,
|
|
321
|
+
const ast = (0, index_js_2.parse)(testExpression);
|
|
322
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
323
|
+
(0, vitest_js_1.expect)(result.hasWarnings).toBe(true);
|
|
324
|
+
(0, vitest_js_1.expect)(result.warnings[0].message).toContain(`${displayName} expects at least ${requiredParams.length} parameter`);
|
|
325
325
|
});
|
|
326
326
|
}
|
|
327
327
|
// Test maximum parameters for non-variadic methods
|
|
328
328
|
if (nonVariadicParams.length === methodDef.params.length && methodDef.params.length > 0) {
|
|
329
|
-
(0,
|
|
329
|
+
(0, vitest_js_1.it)(`should validate ${displayName} maximum parameters`, () => {
|
|
330
330
|
// Create a call with too many parameters
|
|
331
331
|
const maxParams = methodDef.params.length;
|
|
332
332
|
const extraParams = Array(maxParams + 2)
|
|
@@ -350,24 +350,24 @@ const builtins_1 = require("../builtins");
|
|
|
350
350
|
else {
|
|
351
351
|
testExpression = `<Text>{${objectName}.${methodName}(${extraParams})}</Text>`;
|
|
352
352
|
}
|
|
353
|
-
const ast = (0,
|
|
354
|
-
const result = (0,
|
|
355
|
-
(0,
|
|
356
|
-
(0,
|
|
353
|
+
const ast = (0, index_js_2.parse)(testExpression);
|
|
354
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
355
|
+
(0, vitest_js_1.expect)(result.hasWarnings).toBe(true);
|
|
356
|
+
(0, vitest_js_1.expect)(result.warnings[0].message).toContain(`${displayName} expects at most ${maxParams} parameter`);
|
|
357
357
|
});
|
|
358
358
|
}
|
|
359
359
|
});
|
|
360
360
|
});
|
|
361
361
|
});
|
|
362
362
|
});
|
|
363
|
-
(0,
|
|
364
|
-
const builtins = (0,
|
|
363
|
+
(0, vitest_js_1.describe)("builtin properties - dynamic validation", () => {
|
|
364
|
+
const builtins = (0, builtins_js_1.getBuiltins)();
|
|
365
365
|
Object.entries(builtins).forEach(([objectName, schema]) => {
|
|
366
366
|
if (!schema.properties)
|
|
367
367
|
return;
|
|
368
|
-
(0,
|
|
368
|
+
(0, vitest_js_1.describe)(`${objectName} properties`, () => {
|
|
369
369
|
Object.entries(schema.properties).forEach(([propName, propDef]) => {
|
|
370
|
-
(0,
|
|
370
|
+
(0, vitest_js_1.it)(`should allow ${objectName}.${propName} property access`, () => {
|
|
371
371
|
let testExpression;
|
|
372
372
|
if (objectName === "Array.prototype") {
|
|
373
373
|
testExpression = `<Text>{data.items.${propName}}</Text>`;
|
|
@@ -378,39 +378,39 @@ const builtins_1 = require("../builtins");
|
|
|
378
378
|
else {
|
|
379
379
|
testExpression = `<Text>{${objectName}.${propName}}</Text>`;
|
|
380
380
|
}
|
|
381
|
-
const ast = (0,
|
|
382
|
-
const result = (0,
|
|
383
|
-
(0,
|
|
381
|
+
const ast = (0, index_js_2.parse)(testExpression);
|
|
382
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
383
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
384
384
|
});
|
|
385
385
|
});
|
|
386
386
|
});
|
|
387
387
|
});
|
|
388
388
|
});
|
|
389
|
-
(0,
|
|
390
|
-
(0,
|
|
389
|
+
(0, vitest_js_1.describe)("blocked methods", () => {
|
|
390
|
+
(0, vitest_js_1.it)("should block mutating array methods", () => {
|
|
391
391
|
const blockedMethods = ["push", "pop", "shift", "unshift", "splice", "reverse", "sort"];
|
|
392
392
|
blockedMethods.forEach((method) => {
|
|
393
|
-
const ast = (0,
|
|
394
|
-
const result = (0,
|
|
395
|
-
(0,
|
|
396
|
-
(0,
|
|
393
|
+
const ast = (0, index_js_2.parse)(`<Text>{data.items.${method}()}</Text>`);
|
|
394
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
395
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(true);
|
|
396
|
+
(0, vitest_js_1.expect)(result.errors[0].message).toContain(`method .${method} not allowed`);
|
|
397
397
|
});
|
|
398
398
|
});
|
|
399
|
-
(0,
|
|
400
|
-
const ast = (0,
|
|
401
|
-
const result = (0,
|
|
402
|
-
(0,
|
|
403
|
-
(0,
|
|
399
|
+
(0, vitest_js_1.it)("should block Math.random (non-deterministic)", () => {
|
|
400
|
+
const ast = (0, index_js_2.parse)("<Text>{Math.random()}</Text>");
|
|
401
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
402
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(true);
|
|
403
|
+
(0, vitest_js_1.expect)(result.errors[0].message).toContain("method Math.random not allowed");
|
|
404
404
|
});
|
|
405
|
-
(0,
|
|
406
|
-
const ast = (0,
|
|
407
|
-
const result = (0,
|
|
408
|
-
(0,
|
|
409
|
-
(0,
|
|
405
|
+
(0, vitest_js_1.it)("should block unknown methods", () => {
|
|
406
|
+
const ast = (0, index_js_2.parse)("<Text>{Math.unknownMethod()}</Text>");
|
|
407
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
408
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(true);
|
|
409
|
+
(0, vitest_js_1.expect)(result.errors[0].message).toContain("method Math.unknownMethod not allowed");
|
|
410
410
|
});
|
|
411
411
|
});
|
|
412
|
-
(0,
|
|
413
|
-
(0,
|
|
412
|
+
(0, vitest_js_1.describe)("custom builtin schema", () => {
|
|
413
|
+
(0, vitest_js_1.it)("should work with custom builtin schema", () => {
|
|
414
414
|
const customSchema = {
|
|
415
415
|
data: {
|
|
416
416
|
value: { type: "number" },
|
|
@@ -420,15 +420,15 @@ const builtins_1 = require("../builtins");
|
|
|
420
420
|
},
|
|
421
421
|
};
|
|
422
422
|
// Math.max should work with default builtins
|
|
423
|
-
const ast1 = (0,
|
|
424
|
-
const result1 = (0,
|
|
425
|
-
(0,
|
|
423
|
+
const ast1 = (0, index_js_2.parse)("<Text>{Math.max(data.value, 10)}</Text>");
|
|
424
|
+
const result1 = (0, index_js_1.analyze)(ast1, customSchema);
|
|
425
|
+
(0, vitest_js_1.expect)(result1.hasErrors).toBe(false);
|
|
426
426
|
// Math.min should also work since we use BUILTINS
|
|
427
|
-
const ast2 = (0,
|
|
428
|
-
const result2 = (0,
|
|
429
|
-
(0,
|
|
427
|
+
const ast2 = (0, index_js_2.parse)("<Text>{Math.min(data.value, 10)}</Text>");
|
|
428
|
+
const result2 = (0, index_js_1.analyze)(ast2, customSchema);
|
|
429
|
+
(0, vitest_js_1.expect)(result2.hasErrors).toBe(false);
|
|
430
430
|
});
|
|
431
|
-
(0,
|
|
431
|
+
(0, vitest_js_1.it)("should allow custom String methods in builtin schema", () => {
|
|
432
432
|
const customSchema = {
|
|
433
433
|
data: {
|
|
434
434
|
text: { type: "string" },
|
|
@@ -437,14 +437,14 @@ const builtins_1 = require("../builtins");
|
|
|
437
437
|
Text: { props: {} },
|
|
438
438
|
},
|
|
439
439
|
};
|
|
440
|
-
const ast1 = (0,
|
|
441
|
-
const result1 = (0,
|
|
442
|
-
(0,
|
|
443
|
-
const ast2 = (0,
|
|
444
|
-
const result2 = (0,
|
|
445
|
-
(0,
|
|
446
|
-
});
|
|
447
|
-
(0,
|
|
440
|
+
const ast1 = (0, index_js_2.parse)("<Text>{data.text.toUpperCase()}</Text>");
|
|
441
|
+
const result1 = (0, index_js_1.analyze)(ast1, customSchema);
|
|
442
|
+
(0, vitest_js_1.expect)(result1.hasErrors).toBe(false);
|
|
443
|
+
const ast2 = (0, index_js_2.parse)("<Text>{data.text.toLowerCase()}</Text>");
|
|
444
|
+
const result2 = (0, index_js_1.analyze)(ast2, customSchema);
|
|
445
|
+
(0, vitest_js_1.expect)(result2.hasErrors).toBe(false);
|
|
446
|
+
});
|
|
447
|
+
(0, vitest_js_1.it)("should fall back to default builtin schema when not specified", () => {
|
|
448
448
|
const schemaWithoutBuiltins = {
|
|
449
449
|
data: {
|
|
450
450
|
x: { type: "number" },
|
|
@@ -455,20 +455,20 @@ const builtins_1 = require("../builtins");
|
|
|
455
455
|
// No builtins specified - should use default
|
|
456
456
|
};
|
|
457
457
|
// Should work with default builtin schema
|
|
458
|
-
const ast = (0,
|
|
459
|
-
const result = (0,
|
|
460
|
-
(0,
|
|
458
|
+
const ast = (0, index_js_2.parse)("<Text>{Math.max(data.x, 10)}</Text>");
|
|
459
|
+
const result = (0, index_js_1.analyze)(ast, schemaWithoutBuiltins);
|
|
460
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
461
461
|
});
|
|
462
462
|
});
|
|
463
463
|
});
|
|
464
|
-
(0,
|
|
465
|
-
(0,
|
|
466
|
-
(0,
|
|
467
|
-
const ast = (0,
|
|
468
|
-
const result = (0,
|
|
469
|
-
(0,
|
|
470
|
-
});
|
|
471
|
-
(0,
|
|
464
|
+
(0, vitest_js_1.describe)("JSX validation", () => {
|
|
465
|
+
(0, vitest_js_1.describe)("elements", () => {
|
|
466
|
+
(0, vitest_js_1.it)("should allow valid elements", () => {
|
|
467
|
+
const ast = (0, index_js_2.parse)("<Text>Hello</Text>");
|
|
468
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
469
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
470
|
+
});
|
|
471
|
+
(0, vitest_js_1.it)("should accept enum-constrained attribute values", () => {
|
|
472
472
|
const schema = {
|
|
473
473
|
...baseSchema,
|
|
474
474
|
elements: {
|
|
@@ -480,12 +480,12 @@ const builtins_1 = require("../builtins");
|
|
|
480
480
|
},
|
|
481
481
|
},
|
|
482
482
|
};
|
|
483
|
-
const ast = (0,
|
|
484
|
-
const result = (0,
|
|
485
|
-
(0,
|
|
486
|
-
(0,
|
|
483
|
+
const ast = (0, index_js_2.parse)('<Badge variant="primary" />');
|
|
484
|
+
const result = (0, index_js_1.analyze)(ast, schema);
|
|
485
|
+
(0, vitest_js_1.expect)(result.hasWarnings).toBe(false);
|
|
486
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
487
487
|
});
|
|
488
|
-
(0,
|
|
488
|
+
(0, vitest_js_1.it)("should report invalid enum attribute values", () => {
|
|
489
489
|
const schema = {
|
|
490
490
|
...baseSchema,
|
|
491
491
|
elements: {
|
|
@@ -497,31 +497,31 @@ const builtins_1 = require("../builtins");
|
|
|
497
497
|
},
|
|
498
498
|
},
|
|
499
499
|
};
|
|
500
|
-
const ast = (0,
|
|
501
|
-
const result = (0,
|
|
502
|
-
(0,
|
|
503
|
-
(0,
|
|
504
|
-
(0,
|
|
505
|
-
});
|
|
506
|
-
(0,
|
|
507
|
-
const ast = (0,
|
|
508
|
-
const result = (0,
|
|
509
|
-
(0,
|
|
510
|
-
(0,
|
|
511
|
-
});
|
|
512
|
-
(0,
|
|
513
|
-
const ast = (0,
|
|
500
|
+
const ast = (0, index_js_2.parse)('<Badge variant="danger" />');
|
|
501
|
+
const result = (0, index_js_1.analyze)(ast, schema);
|
|
502
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(true);
|
|
503
|
+
(0, vitest_js_1.expect)(result.errors[0].code).toBe("INVALID_ATTRIBUTE_VALUE");
|
|
504
|
+
(0, vitest_js_1.expect)(result.errors[0].suggestions).toEqual(["primary", "secondary"]);
|
|
505
|
+
});
|
|
506
|
+
(0, vitest_js_1.it)("should block invalid elements", () => {
|
|
507
|
+
const ast = (0, index_js_2.parse)("<InvalidElement>Hello</InvalidElement>");
|
|
508
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
509
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(true);
|
|
510
|
+
(0, vitest_js_1.expect)(result.errors[0].message).toContain("Element <InvalidElement> not allowed");
|
|
511
|
+
});
|
|
512
|
+
(0, vitest_js_1.it)("should allow nested valid elements", () => {
|
|
513
|
+
const ast = (0, index_js_2.parse)(`
|
|
514
514
|
<div>
|
|
515
515
|
<Text>Hello</Text>
|
|
516
516
|
<span>World</span>
|
|
517
517
|
</div>
|
|
518
518
|
`);
|
|
519
|
-
const result = (0,
|
|
520
|
-
(0,
|
|
519
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
520
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
521
521
|
});
|
|
522
522
|
});
|
|
523
|
-
(0,
|
|
524
|
-
(0,
|
|
523
|
+
(0, vitest_js_1.describe)("spread attributes", () => {
|
|
524
|
+
(0, vitest_js_1.it)("should allow spread with data object", () => {
|
|
525
525
|
const schema = {
|
|
526
526
|
data: {
|
|
527
527
|
props: {
|
|
@@ -541,11 +541,11 @@ const builtins_1 = require("../builtins");
|
|
|
541
541
|
},
|
|
542
542
|
},
|
|
543
543
|
};
|
|
544
|
-
const ast = (0,
|
|
545
|
-
const result = (0,
|
|
546
|
-
(0,
|
|
544
|
+
const ast = (0, index_js_2.parse)("<Card {...data.props} />");
|
|
545
|
+
const result = (0, index_js_1.analyze)(ast, schema);
|
|
546
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
547
547
|
});
|
|
548
|
-
(0,
|
|
548
|
+
(0, vitest_js_1.it)("should allow spread with nested data object", () => {
|
|
549
549
|
const schema = {
|
|
550
550
|
data: {
|
|
551
551
|
user: {
|
|
@@ -570,11 +570,11 @@ const builtins_1 = require("../builtins");
|
|
|
570
570
|
},
|
|
571
571
|
},
|
|
572
572
|
};
|
|
573
|
-
const ast = (0,
|
|
574
|
-
const result = (0,
|
|
575
|
-
(0,
|
|
573
|
+
const ast = (0, index_js_2.parse)("<Text {...data.user.attributes} />");
|
|
574
|
+
const result = (0, index_js_1.analyze)(ast, schema);
|
|
575
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
576
576
|
});
|
|
577
|
-
(0,
|
|
577
|
+
(0, vitest_js_1.it)("should allow spread with arrow function parameter", () => {
|
|
578
578
|
const schema = {
|
|
579
579
|
data: {
|
|
580
580
|
items: {
|
|
@@ -606,11 +606,11 @@ const builtins_1 = require("../builtins");
|
|
|
606
606
|
},
|
|
607
607
|
},
|
|
608
608
|
};
|
|
609
|
-
const ast = (0,
|
|
610
|
-
const result = (0,
|
|
611
|
-
(0,
|
|
609
|
+
const ast = (0, index_js_2.parse)("<div>{data.items.map(item => <Item {...item.props} />)}</div>");
|
|
610
|
+
const result = (0, index_js_1.analyze)(ast, schema);
|
|
611
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
612
612
|
});
|
|
613
|
-
(0,
|
|
613
|
+
(0, vitest_js_1.it)("should allow spread with the parameter itself", () => {
|
|
614
614
|
const schema = {
|
|
615
615
|
data: {
|
|
616
616
|
items: {
|
|
@@ -636,11 +636,11 @@ const builtins_1 = require("../builtins");
|
|
|
636
636
|
},
|
|
637
637
|
},
|
|
638
638
|
};
|
|
639
|
-
const ast = (0,
|
|
640
|
-
const result = (0,
|
|
641
|
-
(0,
|
|
639
|
+
const ast = (0, index_js_2.parse)("<div>{data.items.map(item => <Item {...item} />)}</div>");
|
|
640
|
+
const result = (0, index_js_1.analyze)(ast, schema);
|
|
641
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
642
642
|
});
|
|
643
|
-
(0,
|
|
643
|
+
(0, vitest_js_1.it)("should allow spread combined with regular attributes", () => {
|
|
644
644
|
const schema = {
|
|
645
645
|
data: {
|
|
646
646
|
props: {
|
|
@@ -659,11 +659,11 @@ const builtins_1 = require("../builtins");
|
|
|
659
659
|
},
|
|
660
660
|
},
|
|
661
661
|
};
|
|
662
|
-
const ast = (0,
|
|
663
|
-
const result = (0,
|
|
664
|
-
(0,
|
|
662
|
+
const ast = (0, index_js_2.parse)("<Card {...data.props} highlighted={true} />");
|
|
663
|
+
const result = (0, index_js_1.analyze)(ast, schema);
|
|
664
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
665
665
|
});
|
|
666
|
-
(0,
|
|
666
|
+
(0, vitest_js_1.it)("should allow multiple spreads", () => {
|
|
667
667
|
const schema = {
|
|
668
668
|
data: {
|
|
669
669
|
baseProps: {
|
|
@@ -688,77 +688,77 @@ const builtins_1 = require("../builtins");
|
|
|
688
688
|
},
|
|
689
689
|
},
|
|
690
690
|
};
|
|
691
|
-
const ast = (0,
|
|
692
|
-
const result = (0,
|
|
693
|
-
(0,
|
|
691
|
+
const ast = (0, index_js_2.parse)("<Card {...data.baseProps} {...data.extraProps} />");
|
|
692
|
+
const result = (0, index_js_1.analyze)(ast, schema);
|
|
693
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
694
694
|
});
|
|
695
695
|
});
|
|
696
|
-
(0,
|
|
697
|
-
(0,
|
|
698
|
-
const ast = (0,
|
|
699
|
-
const result = (0,
|
|
700
|
-
(0,
|
|
701
|
-
});
|
|
702
|
-
(0,
|
|
703
|
-
const ast = (0,
|
|
704
|
-
const result = (0,
|
|
705
|
-
(0,
|
|
706
|
-
});
|
|
707
|
-
(0,
|
|
708
|
-
const ast = (0,
|
|
709
|
-
const result = (0,
|
|
710
|
-
(0,
|
|
711
|
-
});
|
|
712
|
-
(0,
|
|
713
|
-
const ast = (0,
|
|
714
|
-
const result = (0,
|
|
715
|
-
(0,
|
|
716
|
-
(0,
|
|
717
|
-
(0,
|
|
696
|
+
(0, vitest_js_1.describe)("empty expressions", () => {
|
|
697
|
+
(0, vitest_js_1.it)("should allow empty JSX expressions {} in children", () => {
|
|
698
|
+
const ast = (0, index_js_2.parse)("<Text>{}</Text>");
|
|
699
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
700
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
701
|
+
});
|
|
702
|
+
(0, vitest_js_1.it)("should allow multiple empty expressions in children", () => {
|
|
703
|
+
const ast = (0, index_js_2.parse)("<Text>{}{}{}</Text>");
|
|
704
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
705
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
706
|
+
});
|
|
707
|
+
(0, vitest_js_1.it)("should allow empty expressions mixed with content in children", () => {
|
|
708
|
+
const ast = (0, index_js_2.parse)("<Text>Hello {}{data.user.name}{} World</Text>");
|
|
709
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
710
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
711
|
+
});
|
|
712
|
+
(0, vitest_js_1.it)("should handle empty expressions without compile errors", () => {
|
|
713
|
+
const ast = (0, index_js_2.parse)("<Text>{}</Text>");
|
|
714
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
715
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(false);
|
|
716
|
+
(0, vitest_js_1.expect)(ast).toBeDefined();
|
|
717
|
+
(0, vitest_js_1.expect)(ast.body).toHaveLength(1);
|
|
718
718
|
});
|
|
719
719
|
});
|
|
720
720
|
});
|
|
721
|
-
(0,
|
|
722
|
-
(0,
|
|
723
|
-
(0,
|
|
724
|
-
const ast = (0,
|
|
725
|
-
const result = (0,
|
|
726
|
-
(0,
|
|
727
|
-
(0,
|
|
728
|
-
});
|
|
729
|
-
(0,
|
|
730
|
-
const ast = (0,
|
|
731
|
-
const result = (0,
|
|
732
|
-
(0,
|
|
733
|
-
(0,
|
|
721
|
+
(0, vitest_js_1.describe)("security validation", () => {
|
|
722
|
+
(0, vitest_js_1.describe)("disallowed identifiers", () => {
|
|
723
|
+
(0, vitest_js_1.it)("should block window access", () => {
|
|
724
|
+
const ast = (0, index_js_2.parse)("<Text>{window.alert('hack')}</Text>");
|
|
725
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
726
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(true);
|
|
727
|
+
(0, vitest_js_1.expect)(result.errors[0].message).toContain('Identifier "window" not allowed');
|
|
728
|
+
});
|
|
729
|
+
(0, vitest_js_1.it)("should block document access", () => {
|
|
730
|
+
const ast = (0, index_js_2.parse)("<Text>{document.body}</Text>");
|
|
731
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
732
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(true);
|
|
733
|
+
(0, vitest_js_1.expect)(result.errors[0].message).toContain('Identifier "document" not allowed');
|
|
734
734
|
});
|
|
735
735
|
});
|
|
736
|
-
(0,
|
|
737
|
-
(0,
|
|
738
|
-
const ast = (0,
|
|
739
|
-
const result = (0,
|
|
740
|
-
(0,
|
|
741
|
-
(0,
|
|
742
|
-
});
|
|
743
|
-
(0,
|
|
744
|
-
const ast = (0,
|
|
745
|
-
const result = (0,
|
|
746
|
-
(0,
|
|
747
|
-
(0,
|
|
736
|
+
(0, vitest_js_1.describe)("dangerous expressions", () => {
|
|
737
|
+
(0, vitest_js_1.it)("should block eval", () => {
|
|
738
|
+
const ast = (0, index_js_2.parse)("<Text>{eval('alert(1)')}</Text>");
|
|
739
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
740
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(true);
|
|
741
|
+
(0, vitest_js_1.expect)(result.errors[0].message).toContain('Identifier "eval" not allowed');
|
|
742
|
+
});
|
|
743
|
+
(0, vitest_js_1.it)("should block Function constructor", () => {
|
|
744
|
+
const ast = (0, index_js_2.parse)("<Text>{new Function('return 1')()}</Text>");
|
|
745
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
746
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(true);
|
|
747
|
+
(0, vitest_js_1.expect)(result.errors[0].message).toContain('Identifier "Function" not allowed');
|
|
748
748
|
});
|
|
749
749
|
});
|
|
750
750
|
});
|
|
751
|
-
(0,
|
|
752
|
-
(0,
|
|
753
|
-
const ast = (0,
|
|
751
|
+
(0, vitest_js_1.describe)("integration scenarios", () => {
|
|
752
|
+
(0, vitest_js_1.it)("should catch multiple errors in complex expressions", () => {
|
|
753
|
+
const ast = (0, index_js_2.parse)(`
|
|
754
754
|
<InvalidElement>
|
|
755
755
|
<Text>{data.user.invalid}</Text>
|
|
756
756
|
<span>{window.location}</span>
|
|
757
757
|
</InvalidElement>
|
|
758
758
|
`);
|
|
759
|
-
const result = (0,
|
|
760
|
-
(0,
|
|
761
|
-
(0,
|
|
759
|
+
const result = (0, index_js_1.analyze)(ast, baseSchema);
|
|
760
|
+
(0, vitest_js_1.expect)(result.hasErrors).toBe(true);
|
|
761
|
+
(0, vitest_js_1.expect)(result.errors.length).toBeGreaterThan(1);
|
|
762
762
|
});
|
|
763
763
|
});
|
|
764
764
|
});
|