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.
Files changed (180) hide show
  1. package/lib/analyze/analysis-error.d.ts.map +1 -1
  2. package/lib/analyze/analysis-error.js +2 -7
  3. package/lib/analyze/analysis-error.js.map +1 -1
  4. package/lib/analyze/analysis-report.d.ts +13 -13
  5. package/lib/analyze/analysis-report.d.ts.map +1 -1
  6. package/lib/analyze/analysis-report.js +48 -45
  7. package/lib/analyze/analysis-report.js.map +1 -1
  8. package/lib/analyze/analyze.d.ts +1 -1
  9. package/lib/analyze/analyze.d.ts.map +1 -1
  10. package/lib/analyze/analyze.js +4 -4
  11. package/lib/analyze/analyze.js.map +1 -1
  12. package/lib/analyze/data/analyze.d.ts +1 -1
  13. package/lib/analyze/data/analyze.d.ts.map +1 -1
  14. package/lib/analyze/data/analyze.js +5 -5
  15. package/lib/analyze/data/analyze.js.map +1 -1
  16. package/lib/analyze/data/data-access.d.ts +1 -1
  17. package/lib/analyze/data/data-access.d.ts.map +1 -1
  18. package/lib/analyze/data/data-access.js +19 -15
  19. package/lib/analyze/data/data-access.js.map +1 -1
  20. package/lib/analyze/data/method-calls.d.ts +1 -1
  21. package/lib/analyze/data/method-calls.d.ts.map +1 -1
  22. package/lib/analyze/data/method-calls.js +5 -5
  23. package/lib/analyze/data/method-calls.js.map +1 -1
  24. package/lib/analyze/data/utils.d.ts +3 -3
  25. package/lib/analyze/data/utils.d.ts.map +1 -1
  26. package/lib/analyze/data/utils.js +6 -5
  27. package/lib/analyze/data/utils.js.map +1 -1
  28. package/lib/analyze/index.d.ts +1 -1
  29. package/lib/analyze/index.d.ts.map +1 -1
  30. package/lib/analyze/index.js +1 -1
  31. package/lib/analyze/index.js.map +1 -1
  32. package/lib/analyze/jsx/analyze.d.ts +1 -1
  33. package/lib/analyze/jsx/analyze.d.ts.map +1 -1
  34. package/lib/analyze/jsx/analyze.js +4 -4
  35. package/lib/analyze/jsx/analyze.js.map +1 -1
  36. package/lib/analyze/jsx/element-attributes.d.ts +1 -1
  37. package/lib/analyze/jsx/element-attributes.d.ts.map +1 -1
  38. package/lib/analyze/jsx/element-attributes.js +3 -3
  39. package/lib/analyze/jsx/element-attributes.js.map +1 -1
  40. package/lib/analyze/jsx/element-children.d.ts +1 -1
  41. package/lib/analyze/jsx/element-children.d.ts.map +1 -1
  42. package/lib/analyze/jsx/element-children.js +8 -9
  43. package/lib/analyze/jsx/element-children.js.map +1 -1
  44. package/lib/analyze/jsx/element-tags.d.ts +1 -1
  45. package/lib/analyze/jsx/element-tags.d.ts.map +1 -1
  46. package/lib/analyze/jsx/element-tags.js +2 -2
  47. package/lib/analyze/jsx/element-tags.js.map +1 -1
  48. package/lib/analyze/security/analyze.d.ts +1 -1
  49. package/lib/analyze/security/analyze.d.ts.map +1 -1
  50. package/lib/analyze/security/analyze.js +4 -4
  51. package/lib/analyze/security/analyze.js.map +1 -1
  52. package/lib/analyze/security/call-expressions.d.ts +1 -1
  53. package/lib/analyze/security/call-expressions.d.ts.map +1 -1
  54. package/lib/analyze/security/call-expressions.js +3 -5
  55. package/lib/analyze/security/call-expressions.js.map +1 -1
  56. package/lib/analyze/security/declarations.d.ts +1 -1
  57. package/lib/analyze/security/declarations.d.ts.map +1 -1
  58. package/lib/analyze/security/declarations.js +6 -6
  59. package/lib/analyze/security/declarations.js.map +1 -1
  60. package/lib/analyze/security/expressions.d.ts +1 -1
  61. package/lib/analyze/security/expressions.d.ts.map +1 -1
  62. package/lib/analyze/security/expressions.js +3 -6
  63. package/lib/analyze/security/expressions.js.map +1 -1
  64. package/lib/analyze/security/identifiers.d.ts +1 -1
  65. package/lib/analyze/security/identifiers.d.ts.map +1 -1
  66. package/lib/analyze/security/identifiers.js +19 -22
  67. package/lib/analyze/security/identifiers.js.map +1 -1
  68. package/lib/analyze/utils.d.ts +4 -4
  69. package/lib/analyze/utils.d.ts.map +1 -1
  70. package/lib/analyze/utils.js +5 -3
  71. package/lib/analyze/utils.js.map +1 -1
  72. package/lib/analyze/validation-context.d.ts +8 -8
  73. package/lib/analyze/validation-context.d.ts.map +1 -1
  74. package/lib/analyze/validation-context.js +23 -21
  75. package/lib/analyze/validation-context.js.map +1 -1
  76. package/lib/builtins.d.ts +6 -6
  77. package/lib/builtins.d.ts.map +1 -1
  78. package/lib/builtins.js +9 -8
  79. package/lib/builtins.js.map +1 -1
  80. package/lib/codegen/builtins/builtin-types.d.ts.map +1 -1
  81. package/lib/codegen/builtins/builtin-types.js +9 -13
  82. package/lib/codegen/builtins/builtin-types.js.map +1 -1
  83. package/lib/codegen/generate-typescript-definitions.d.ts +18 -17
  84. package/lib/codegen/generate-typescript-definitions.d.ts.map +1 -1
  85. package/lib/codegen/generate-typescript-definitions.js +19 -23
  86. package/lib/codegen/generate-typescript-definitions.js.map +1 -1
  87. package/lib/codegen/schema/component-types.d.ts.map +1 -1
  88. package/lib/codegen/schema/component-types.js +7 -4
  89. package/lib/codegen/schema/component-types.js.map +1 -1
  90. package/lib/codegen/schema/data-types.d.ts.map +1 -1
  91. package/lib/codegen/schema/data-types.js +1 -1
  92. package/lib/codegen/schema/data-types.js.map +1 -1
  93. package/lib/codegen/schema/function-types.js.map +1 -1
  94. package/lib/codegen/schema/utils.d.ts +4 -3
  95. package/lib/codegen/schema/utils.d.ts.map +1 -1
  96. package/lib/codegen/schema/utils.js +12 -8
  97. package/lib/codegen/schema/utils.js.map +1 -1
  98. package/lib/compile/compilation-error.d.ts +1 -1
  99. package/lib/compile/compilation-error.d.ts.map +1 -1
  100. package/lib/compile/compilation-error.js +3 -1
  101. package/lib/compile/compilation-error.js.map +1 -1
  102. package/lib/compile/compile.d.ts.map +1 -1
  103. package/lib/compile/compile.js +5 -11
  104. package/lib/compile/compile.js.map +1 -1
  105. package/lib/evaluate/evaluate.d.ts +6 -6
  106. package/lib/evaluate/evaluate.d.ts.map +1 -1
  107. package/lib/evaluate/evaluate.js +2 -2
  108. package/lib/evaluate/evaluate.js.map +1 -1
  109. package/lib/evaluate/evaluation-error.d.ts.map +1 -1
  110. package/lib/evaluate/evaluation-error.js +1 -0
  111. package/lib/evaluate/evaluation-error.js.map +1 -1
  112. package/lib/index.d.ts.map +1 -1
  113. package/lib/index.js.map +1 -1
  114. package/lib/jsx.d.ts +3 -3
  115. package/lib/jsx.d.ts.map +1 -1
  116. package/lib/jsx.js.map +1 -1
  117. package/lib/parse/parse-error.d.ts.map +1 -1
  118. package/lib/parse/parse-error.js +1 -0
  119. package/lib/parse/parse-error.js.map +1 -1
  120. package/lib/render.d.ts +25 -33
  121. package/lib/render.d.ts.map +1 -1
  122. package/lib/render.js +21 -26
  123. package/lib/render.js.map +1 -1
  124. package/lib/schema.d.ts +9 -9
  125. package/lib/schema.d.ts.map +1 -1
  126. package/lib/schema.js +1 -1
  127. package/lib/schema.js.map +1 -1
  128. package/lib/traverse.d.ts.map +1 -1
  129. package/lib/traverse.js +0 -1
  130. package/lib/traverse.js.map +1 -1
  131. package/lib/validate.d.ts +14 -17
  132. package/lib/validate.d.ts.map +1 -1
  133. package/lib/validate.js +13 -14
  134. package/lib/validate.js.map +1 -1
  135. package/package.json +14 -14
  136. package/src/analyze/analysis-error.ts +2 -6
  137. package/src/analyze/analysis-report.ts +73 -62
  138. package/src/analyze/analyze.test.ts +14 -18
  139. package/src/analyze/analyze.ts +4 -4
  140. package/src/analyze/data/analyze.ts +5 -8
  141. package/src/analyze/data/data-access.ts +49 -46
  142. package/src/analyze/data/method-calls.ts +9 -18
  143. package/src/analyze/data/utils.ts +15 -19
  144. package/src/analyze/index.ts +1 -1
  145. package/src/analyze/jsx/analyze.ts +4 -4
  146. package/src/analyze/jsx/element-attributes.ts +6 -19
  147. package/src/analyze/jsx/element-children.ts +9 -13
  148. package/src/analyze/jsx/element-tags.ts +2 -2
  149. package/src/analyze/security/analyze.ts +4 -4
  150. package/src/analyze/security/call-expressions.ts +5 -18
  151. package/src/analyze/security/declarations.ts +14 -43
  152. package/src/analyze/security/expressions.ts +12 -49
  153. package/src/analyze/security/identifiers.ts +39 -41
  154. package/src/analyze/utils.ts +25 -19
  155. package/src/analyze/validation-context.ts +32 -23
  156. package/src/builtins.ts +28 -39
  157. package/src/codegen/builtins/builtin-types.ts +13 -20
  158. package/src/codegen/generate-typescript-definitions.test.ts +29 -29
  159. package/src/codegen/generate-typescript-definitions.ts +19 -23
  160. package/src/codegen/schema/component-types.ts +22 -12
  161. package/src/codegen/schema/data-types.ts +6 -6
  162. package/src/codegen/schema/function-types.ts +1 -1
  163. package/src/codegen/schema/utils.ts +24 -23
  164. package/src/compile/compilation-error.ts +5 -1
  165. package/src/compile/compile.test.ts +7 -21
  166. package/src/compile/compile.ts +33 -45
  167. package/src/evaluate/evaluate.test.ts +95 -111
  168. package/src/evaluate/evaluate.ts +16 -21
  169. package/src/evaluate/evaluation-error.ts +1 -0
  170. package/src/index.ts +1 -7
  171. package/src/jsx.ts +4 -6
  172. package/src/parse/parse-error.ts +1 -0
  173. package/src/parse/parse.test.ts +1 -1
  174. package/src/render.test.ts +4 -4
  175. package/src/render.ts +27 -39
  176. package/src/schema.ts +12 -12
  177. package/src/traverse.test.ts +6 -6
  178. package/src/traverse.ts +15 -16
  179. package/src/validate.ts +14 -17
  180. package/CHANGELOG.md +0 -8
@@ -1,35 +1,35 @@
1
1
  import { describe, it, expect, vi } from "vitest";
2
- import { evaluate, type EvaluateOptions } from "./evaluate.js";
3
2
  import { compile } from "../compile/index.js";
4
3
  import { parse } from "../parse/index.js";
5
4
  import type { Schema } from "../schema.js";
6
-
5
+ import { evaluate, type Component, type EvaluateOptions, type PropsDict } from "./evaluate.js";
7
6
  import { EvaluationError } from "./evaluation-error.js";
8
7
 
9
8
  type Node = {
10
9
  type: string;
11
10
  props: Record<string, unknown>;
12
- children: Node[];
11
+ children: Array<Node>;
13
12
  };
14
13
 
15
- function createPermissiveSchema(componentNames: string[]): Schema {
14
+ function createPermissiveSchema(componentNames: Array<string>): Schema {
16
15
  return {
17
16
  elements: Object.fromEntries(componentNames.map((name) => [name, {}])),
18
17
  };
19
18
  }
20
19
 
21
20
  describe("evaluate", () => {
22
- const compileAndEvaluate = (source: string, options: EvaluateOptions = {}): Node => {
23
- const componentNames = Object.keys(options.components || {});
21
+ const compileAndEvaluate = (source: string, options: EvaluateOptions<Node> = {}): Node => {
22
+ const componentNames = Object.keys(options.components ?? {});
24
23
  const schema = createPermissiveSchema(componentNames);
25
24
  return evaluate(compile(parse(source)), schema, options);
26
25
  };
27
26
 
28
27
  it("should evaluate JSX with props", () => {
29
- const TestComponent = (props: any): Node => ({
28
+ const TestComponent = (props: PropsDict): Node => ({
30
29
  type: "TestComponent",
31
30
  props: { x: props.x, y: props.y },
32
- children: props.children,
31
+ // props.children is genuinely dynamic (mixed strings/numbers/nested Node results); this fixture assumes the Node shape its own assertions expect.
32
+ children: props.children as Array<Node>,
33
33
  });
34
34
 
35
35
  const result = compileAndEvaluate("<Test x={x} y={y}>Hello</Test>", {
@@ -47,7 +47,7 @@ describe("evaluate", () => {
47
47
  });
48
48
 
49
49
  it("should evaluate JSX with Math operations", () => {
50
- const TestComponent = (props: any): Node => ({
50
+ const TestComponent = (props: PropsDict): Node => ({
51
51
  type: "TestComponent",
52
52
  props,
53
53
  children: [],
@@ -60,7 +60,7 @@ describe("evaluate", () => {
60
60
  },
61
61
  });
62
62
 
63
- expect(result.props!.value).toBe(15); // floor(5 * 3.14159...) = 15
63
+ expect(result.props.value).toBe(15); // floor(5 * 3.14159...) = 15
64
64
  });
65
65
 
66
66
  it("should throw EvaluationError for unknown component", () => {
@@ -68,15 +68,14 @@ describe("evaluate", () => {
68
68
  const emptySchema = createPermissiveSchema([]);
69
69
 
70
70
  expect(() => evaluate(compiled, emptySchema, { components: {} })).toThrow(EvaluationError);
71
- expect(() => evaluate(compiled, emptySchema, { components: {} })).toThrow(
72
- 'component "UnknownComponent" is not allowed'
73
- );
71
+ expect(() => evaluate(compiled, emptySchema, { components: {} })).toThrow('component "UnknownComponent" is not allowed');
74
72
  });
75
73
 
76
74
  it("should deep-freeze props to prevent mutations", () => {
77
- const TestComponent = (props: any): Node => {
75
+ const TestComponent = (props: PropsDict): Node => {
78
76
  expect(() => {
79
- props.nested.value = 999;
77
+ // props.nested's shape isn't known statically; this test only cares that mutating it throws once frozen.
78
+ (props.nested as Record<string, unknown>).value = 999;
80
79
  }).toThrow();
81
80
  return { type: "Test", props, children: [] };
82
81
  };
@@ -93,16 +92,16 @@ describe("evaluate", () => {
93
92
  });
94
93
 
95
94
  it("should evaluate nested elements", () => {
96
- const OuterComponent = (props: any): Node => ({
95
+ const OuterComponent = (props: PropsDict): Node => ({
97
96
  type: "Outer",
98
97
  props: { x: props.x },
99
- children: props.children,
98
+ children: props.children as Array<Node>,
100
99
  });
101
100
 
102
- const InnerComponent = (props: any): Node => ({
101
+ const InnerComponent = (props: PropsDict): Node => ({
103
102
  type: "Inner",
104
103
  props: { y: props.y },
105
- children: props.children,
104
+ children: props.children as Array<Node>,
106
105
  });
107
106
 
108
107
  const result = compileAndEvaluate("<Outer x={x}><Inner y={y}>Text</Inner></Outer>", {
@@ -116,17 +115,17 @@ describe("evaluate", () => {
116
115
  expect(result.type).toBe("Outer");
117
116
  expect(result.props).toEqual({ x: 10 });
118
117
  expect(result.children).toHaveLength(1);
119
- const innerNode = result.children[0] as Node;
118
+ const innerNode = result.children[0];
120
119
  expect(innerNode.type).toBe("Inner");
121
120
  expect(innerNode.props).toEqual({ y: 20 });
122
121
  expect(innerNode.children).toEqual(["Text"]);
123
122
  });
124
123
 
125
124
  it("should use custom createElement when provided", () => {
126
- const customCreateElement = (type: any, props: any, ...children: any[]): Node => ({
127
- type: type.name || "Unknown",
125
+ const customCreateElement = (type: Component, props: PropsDict | undefined, ...children: Array<unknown>): Node => ({
126
+ type: type.name,
128
127
  props: { ...props, custom: true },
129
- children,
128
+ children: children as Array<Node>,
130
129
  });
131
130
 
132
131
  const TestComponent = (): Node => ({ type: "Test", props: {}, children: [] });
@@ -146,7 +145,7 @@ describe("evaluate", () => {
146
145
  });
147
146
 
148
147
  it("should evaluate conditional expressions with props", () => {
149
- const TestComponent = (props: any): Node => ({
148
+ const TestComponent = (props: PropsDict): Node => ({
150
149
  type: "TestComponent",
151
150
  props,
152
151
  children: [],
@@ -159,11 +158,11 @@ describe("evaluate", () => {
159
158
  },
160
159
  });
161
160
 
162
- expect(result.props!.msg).toBe("visible");
161
+ expect(result.props.msg).toBe("visible");
163
162
  });
164
163
 
165
164
  it("should evaluate array methods on props", () => {
166
- const TestComponent = (props: any): Node => ({
165
+ const TestComponent = (props: PropsDict): Node => ({
167
166
  type: "TestComponent",
168
167
  props,
169
168
  children: [],
@@ -176,7 +175,7 @@ describe("evaluate", () => {
176
175
  },
177
176
  });
178
177
 
179
- expect(result.props!.values).toEqual([6, 8, 10]);
178
+ expect(result.props.values).toEqual([6, 8, 10]);
180
179
  });
181
180
 
182
181
  it("should handle runtime errors gracefully", () => {
@@ -195,7 +194,7 @@ describe("evaluate", () => {
195
194
  });
196
195
 
197
196
  it("should evaluate logical operators with props", () => {
198
- const TestComponent = (props: any): Node => ({
197
+ const TestComponent = (props: PropsDict): Node => ({
199
198
  type: "TestComponent",
200
199
  props,
201
200
  children: [],
@@ -208,14 +207,14 @@ describe("evaluate", () => {
208
207
  },
209
208
  });
210
209
 
211
- expect(result.props!.msg).toBe("Anonymous");
210
+ expect(result.props.msg).toBe("Anonymous");
212
211
  });
213
212
 
214
213
  it("should flatten and filter children correctly", () => {
215
- const TestComponent = (props: any): Node => ({
214
+ const TestComponent = (props: PropsDict): Node => ({
216
215
  type: "Test",
217
216
  props: {},
218
- children: props.children,
217
+ children: props.children as Array<Node>,
219
218
  });
220
219
 
221
220
  const result = compileAndEvaluate("<Test>{show && 'Visible'}{false}{'Always'}</Test>", {
@@ -240,10 +239,10 @@ describe("evaluate", () => {
240
239
  });
241
240
 
242
241
  it("should handle empty JSX expressions", () => {
243
- const TestComponent = (props: any): Node => ({
242
+ const TestComponent = (props: PropsDict): Node => ({
244
243
  type: "Test",
245
244
  props: {},
246
- children: props.children,
245
+ children: props.children as Array<Node>,
247
246
  });
248
247
 
249
248
  const result = compileAndEvaluate("<Test>{}{value}{}</Test>", {
@@ -255,21 +254,18 @@ describe("evaluate", () => {
255
254
  });
256
255
 
257
256
  it("should evaluate complex nested expressions", () => {
258
- const TestComponent = (props: any): Node => ({
257
+ const TestComponent = (props: PropsDict): Node => ({
259
258
  type: "Test",
260
259
  props,
261
260
  children: [],
262
261
  });
263
262
 
264
- const result = compileAndEvaluate(
265
- "<Test values={items.filter(x => x > 2).map(x => x * 2).join(', ')}>Text</Test>",
266
- {
267
- data: { items: [1, 2, 3, 4, 5] },
268
- components: { Test: TestComponent },
269
- }
270
- );
263
+ const result = compileAndEvaluate("<Test values={items.filter(x => x > 2).map(x => x * 2).join(', ')}>Text</Test>", {
264
+ data: { items: [1, 2, 3, 4, 5] },
265
+ components: { Test: TestComponent },
266
+ });
271
267
 
272
- expect(result.props!.values).toBe("6, 8, 10");
268
+ expect(result.props.values).toBe("6, 8, 10");
273
269
  });
274
270
 
275
271
  it("should pass correct parameters to custom createElement", () => {
@@ -284,7 +280,7 @@ describe("evaluate", () => {
284
280
  });
285
281
 
286
282
  it("should handle string literals in expressions", () => {
287
- const TestComponent = (props: any): Node => ({
283
+ const TestComponent = (props: PropsDict): Node => ({
288
284
  type: "Test",
289
285
  props,
290
286
  children: [],
@@ -295,11 +291,11 @@ describe("evaluate", () => {
295
291
  components: { Test: TestComponent },
296
292
  });
297
293
 
298
- expect(result.props!.msg).toBe("Hello World");
294
+ expect(result.props.msg).toBe("Hello World");
299
295
  });
300
296
 
301
297
  it("should handle numeric operations", () => {
302
- const TestComponent = (props: any): Node => ({
298
+ const TestComponent = (props: PropsDict): Node => ({
303
299
  type: "Test",
304
300
  props,
305
301
  children: [],
@@ -310,14 +306,14 @@ describe("evaluate", () => {
310
306
  components: { Test: TestComponent },
311
307
  });
312
308
 
313
- expect(result.props!.value).toBe(11); // 5 + (3 * 2)
309
+ expect(result.props.value).toBe(11); // 5 + (3 * 2)
314
310
  });
315
311
 
316
312
  it("should handle data access in children", () => {
317
- const TestComponent = (props: any): Node => ({
313
+ const TestComponent = (props: PropsDict): Node => ({
318
314
  type: "Test",
319
315
  props: {},
320
- children: props.children,
316
+ children: props.children as Array<Node>,
321
317
  });
322
318
 
323
319
  const result = compileAndEvaluate("<Test>Hello {name}!</Test>", {
@@ -330,7 +326,7 @@ describe("evaluate", () => {
330
326
 
331
327
  describe("const declarations", () => {
332
328
  it("should evaluate const with literal value", () => {
333
- const TestComponent = (props: any): Node => ({
329
+ const TestComponent = (props: PropsDict): Node => ({
334
330
  type: "Test",
335
331
  props,
336
332
  children: [],
@@ -340,11 +336,11 @@ describe("evaluate", () => {
340
336
  components: { Test: TestComponent },
341
337
  });
342
338
 
343
- expect(result.props!.value).toBe(42);
339
+ expect(result.props.value).toBe(42);
344
340
  });
345
341
 
346
342
  it("should evaluate const with computed expression", () => {
347
- const TestComponent = (props: any): Node => ({
343
+ const TestComponent = (props: PropsDict): Node => ({
348
344
  type: "Test",
349
345
  props,
350
346
  children: [],
@@ -355,11 +351,11 @@ describe("evaluate", () => {
355
351
  components: { Test: TestComponent },
356
352
  });
357
353
 
358
- expect(result.props!.value).toBe(8); // (3+1)*2
354
+ expect(result.props.value).toBe(8); // (3+1)*2
359
355
  });
360
356
 
361
357
  it("should evaluate const referencing data", () => {
362
- const TestComponent = (props: any): Node => ({
358
+ const TestComponent = (props: PropsDict): Node => ({
363
359
  type: "Test",
364
360
  props,
365
361
  children: [],
@@ -370,49 +366,43 @@ describe("evaluate", () => {
370
366
  components: { Test: TestComponent },
371
367
  });
372
368
 
373
- expect(result.props!.msg).toBe("Hello World");
369
+ expect(result.props.msg).toBe("Hello World");
374
370
  });
375
371
 
376
372
  it("should evaluate const with computed array", () => {
377
- const TestComponent = (props: any): Node => ({
373
+ const TestComponent = (props: PropsDict): Node => ({
378
374
  type: "Test",
379
375
  props,
380
376
  children: [],
381
377
  });
382
378
 
383
- const result = compileAndEvaluate(
384
- "const filtered = items.filter(x => x > 2);\nreturn <Test count={filtered.length}>Text</Test>",
385
- {
386
- data: { items: [1, 2, 3, 4, 5] },
387
- components: { Test: TestComponent },
388
- }
389
- );
379
+ const result = compileAndEvaluate("const filtered = items.filter(x => x > 2);\nreturn <Test count={filtered.length}>Text</Test>", {
380
+ data: { items: [1, 2, 3, 4, 5] },
381
+ components: { Test: TestComponent },
382
+ });
390
383
 
391
- expect(result.props!.count).toBe(3);
384
+ expect(result.props.count).toBe(3);
392
385
  });
393
386
  });
394
387
 
395
388
  describe("function declarations", () => {
396
389
  it("should evaluate user-defined component", () => {
397
- const Span = (props: any): Node => ({
390
+ const Span = (props: PropsDict): Node => ({
398
391
  type: "Span",
399
392
  props: {},
400
- children: props.children,
393
+ children: props.children as Array<Node>,
401
394
  });
402
395
 
403
- const result = compileAndEvaluate(
404
- 'function Badge({ label }) {\n return <Span>{label}</Span>\n}\nreturn <Badge label="hello" />',
405
- {
406
- components: { Span },
407
- }
408
- );
396
+ const result = compileAndEvaluate('function Badge({ label }) {\n return <Span>{label}</Span>\n}\nreturn <Badge label="hello" />', {
397
+ components: { Span },
398
+ });
409
399
 
410
400
  expect(result.type).toBe("Span");
411
401
  expect(result.children).toEqual(["hello"]);
412
402
  });
413
403
 
414
404
  it("should evaluate function with const inside", () => {
415
- const Span = (props: any): Node => ({
405
+ const Span = (props: PropsDict): Node => ({
416
406
  type: "Span",
417
407
  props,
418
408
  children: [],
@@ -425,20 +415,20 @@ describe("evaluate", () => {
425
415
  }
426
416
  );
427
417
 
428
- expect(result.props!.result).toBe(10);
418
+ expect(result.props.result).toBe(10);
429
419
  });
430
420
 
431
421
  it("should evaluate nested user-defined components", () => {
432
- const Span = (props: any): Node => ({
422
+ const Span = (props: PropsDict): Node => ({
433
423
  type: "Span",
434
424
  props: {},
435
- children: props.children,
425
+ children: props.children as Array<Node>,
436
426
  });
437
427
 
438
- const Div = (props: any): Node => ({
428
+ const Div = (props: PropsDict): Node => ({
439
429
  type: "Div",
440
430
  props: {},
441
- children: props.children,
431
+ children: props.children as Array<Node>,
442
432
  });
443
433
 
444
434
  const result = compileAndEvaluate(
@@ -450,21 +440,21 @@ describe("evaluate", () => {
450
440
 
451
441
  expect(result.type).toBe("Div");
452
442
  expect(result.children).toHaveLength(1);
453
- expect((result.children[0] as Node).type).toBe("Span");
454
- expect((result.children[0] as Node).children).toEqual(["hi"]);
443
+ expect(result.children[0].type).toBe("Span");
444
+ expect(result.children[0].children).toEqual(["hi"]);
455
445
  });
456
446
 
457
447
  it("should evaluate function with children", () => {
458
- const Div = (props: any): Node => ({
448
+ const Div = (props: PropsDict): Node => ({
459
449
  type: "Div",
460
450
  props: {},
461
- children: props.children,
451
+ children: props.children as Array<Node>,
462
452
  });
463
453
 
464
- const Span = (props: any): Node => ({
454
+ const Span = (props: PropsDict): Node => ({
465
455
  type: "Span",
466
456
  props: {},
467
- children: props.children,
457
+ children: props.children as Array<Node>,
468
458
  });
469
459
 
470
460
  const result = compileAndEvaluate(
@@ -476,40 +466,34 @@ describe("evaluate", () => {
476
466
 
477
467
  expect(result.type).toBe("Div");
478
468
  expect(result.children).toHaveLength(1);
479
- expect((result.children[0] as Node).type).toBe("Span");
469
+ expect(result.children[0].type).toBe("Span");
480
470
  });
481
471
 
482
472
  it("should evaluate function with default parameter values", () => {
483
- const Span = (props: any): Node => ({
473
+ const Span = (props: PropsDict): Node => ({
484
474
  type: "Span",
485
475
  props: {},
486
- children: props.children,
476
+ children: props.children as Array<Node>,
487
477
  });
488
478
 
489
- const result = compileAndEvaluate(
490
- "function Badge({ label = 'default' }) {\n return <Span>{label}</Span>\n}\nreturn <Badge />",
491
- {
492
- components: { Span },
493
- }
494
- );
479
+ const result = compileAndEvaluate("function Badge({ label = 'default' }) {\n return <Span>{label}</Span>\n}\nreturn <Badge />", {
480
+ components: { Span },
481
+ });
495
482
 
496
483
  expect(result.children).toEqual(["default"]);
497
484
  });
498
485
 
499
486
  it("should evaluate function with data access", () => {
500
- const Span = (props: any): Node => ({
487
+ const Span = (props: PropsDict): Node => ({
501
488
  type: "Span",
502
489
  props: {},
503
- children: props.children,
490
+ children: props.children as Array<Node>,
504
491
  });
505
492
 
506
- const result = compileAndEvaluate(
507
- "function Greeting() {\n return <Span>Hello {name}</Span>\n}\nreturn <Greeting />",
508
- {
509
- data: { name: "World" },
510
- components: { Span },
511
- }
512
- );
493
+ const result = compileAndEvaluate("function Greeting() {\n return <Span>Hello {name}</Span>\n}\nreturn <Greeting />", {
494
+ data: { name: "World" },
495
+ components: { Span },
496
+ });
513
497
 
514
498
  expect(result.children).toEqual(["Hello", "World"]);
515
499
  });
@@ -517,7 +501,7 @@ describe("evaluate", () => {
517
501
 
518
502
  describe("const and function combined", () => {
519
503
  it("should evaluate const used in function body", () => {
520
- const Span = (props: any): Node => ({
504
+ const Span = (props: PropsDict): Node => ({
521
505
  type: "Span",
522
506
  props,
523
507
  children: [],
@@ -530,20 +514,20 @@ describe("evaluate", () => {
530
514
  }
531
515
  );
532
516
 
533
- expect(result.props!.result).toBe(12);
517
+ expect(result.props.result).toBe(12);
534
518
  });
535
519
 
536
520
  it("should evaluate function used in map with const", () => {
537
- const Div = (props: any): Node => ({
521
+ const Div = (props: PropsDict): Node => ({
538
522
  type: "Div",
539
523
  props: {},
540
- children: props.children,
524
+ children: props.children as Array<Node>,
541
525
  });
542
526
 
543
- const Span = (props: any): Node => ({
527
+ const Span = (props: PropsDict): Node => ({
544
528
  type: "Span",
545
529
  props: {},
546
- children: props.children,
530
+ children: props.children as Array<Node>,
547
531
  });
548
532
 
549
533
  const result = compileAndEvaluate(
@@ -561,7 +545,7 @@ describe("evaluate", () => {
561
545
 
562
546
  describe("String builtin", () => {
563
547
  it("should evaluate String() conversion", () => {
564
- const TestComponent = (props: any): Node => ({
548
+ const TestComponent = (props: PropsDict): Node => ({
565
549
  type: "Test",
566
550
  props,
567
551
  children: [],
@@ -571,11 +555,11 @@ describe("evaluate", () => {
571
555
  components: { Test: TestComponent },
572
556
  });
573
557
 
574
- expect(result.props!.value).toBe("42");
558
+ expect(result.props.value).toBe("42");
575
559
  });
576
560
 
577
561
  it("should evaluate String() with boolean", () => {
578
- const TestComponent = (props: any): Node => ({
562
+ const TestComponent = (props: PropsDict): Node => ({
579
563
  type: "Test",
580
564
  props,
581
565
  children: [],
@@ -586,7 +570,7 @@ describe("evaluate", () => {
586
570
  components: { Test: TestComponent },
587
571
  });
588
572
 
589
- expect(result.props!.value).toBe("true");
573
+ expect(result.props.value).toBe("true");
590
574
  });
591
575
  });
592
576
  });
@@ -3,7 +3,7 @@ import { EvaluationError } from "./evaluation-error.js";
3
3
 
4
4
  export type ComponentDict = Record<string, Component>;
5
5
 
6
- export type CreateElement<T = any> = (type: Component, props?: PropsDict, ...children: any[]) => T;
6
+ export type CreateElement<T = unknown> = (type: Component, props?: PropsDict, ...children: Array<unknown>) => T;
7
7
 
8
8
  export type PropsDict = Record<string, unknown>;
9
9
 
@@ -12,19 +12,19 @@ export type DataDict = Record<string, unknown>;
12
12
  export type Node = {
13
13
  type: string;
14
14
  props: PropsDict;
15
- children: Node[];
15
+ children: Array<Node>;
16
16
  };
17
17
 
18
- export type H = (type: string | Function, props?: PropsDict, ...children: Node[]) => Node;
18
+ export type H = (type: string | Function, props?: PropsDict, ...children: Array<Node>) => Node;
19
19
 
20
- export type Component = (...args: any[]) => any;
20
+ export type Component = (...args: Array<never>) => unknown;
21
21
 
22
22
  /**
23
23
  * Configuration options for evaluating JSX expressions.
24
24
  *
25
25
  * @template T - The return type of createElement function
26
26
  */
27
- export interface EvaluateOptions<T = any> {
27
+ export interface EvaluateOptions<T = unknown> {
28
28
  /** Data object whose keys become top-level variables in JSX expressions */
29
29
  data?: DataDict;
30
30
  /** Map of component names to component functions used in JSX */
@@ -38,23 +38,18 @@ export interface EvaluateOptions<T = any> {
38
38
  const RESERVED_PARAMS = new Set(["h", "Math"]);
39
39
  const VALID_IDENTIFIER = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
40
40
 
41
- export function evaluate<T = any>(source: string, schema: Schema, options: EvaluateOptions<T>): T {
41
+ export function evaluate<T = unknown>(source: string, schema: Schema, options: EvaluateOptions<T>): T {
42
42
  const { data = {}, components = {}, functions = {}, createElement } = options;
43
43
 
44
44
  const dataKeys = Object.keys(data);
45
45
  const functionKeys = Object.keys(functions);
46
46
  validateParamKeys(dataKeys, functionKeys);
47
47
 
48
- const h = createH(components, createElement || defaultCreateElement, schema);
48
+ const h = createH(components, createElement ?? defaultCreateElement, schema);
49
49
  const frozen = deepFreezeData(structuredClone(data));
50
50
  try {
51
- // eslint-disable-next-line @typescript-eslint/no-implied-eval, no-new-func
52
- return new Function("h", "Math", ...dataKeys, ...functionKeys, source)(
53
- h,
54
- Math,
55
- ...Object.values(frozen),
56
- ...Object.values(functions)
57
- ) as T;
51
+ // oxlint-disable-next-line typescript/no-implied-eval, no-new-func
52
+ return new Function("h", "Math", ...dataKeys, ...functionKeys, source)(h, Math, ...Object.values(frozen), ...Object.values(functions)) as T;
58
53
  } catch (error: unknown) {
59
54
  // We may have thrown an EvaluationError from createH()
60
55
  if (error instanceof EvaluationError) {
@@ -65,7 +60,7 @@ export function evaluate<T = any>(source: string, schema: Schema, options: Evalu
65
60
  }
66
61
  }
67
62
 
68
- function validateParamKeys(dataKeys: string[], functionKeys: string[]): void {
63
+ function validateParamKeys(dataKeys: Array<string>, functionKeys: Array<string>): void {
69
64
  const seen = new Set<string>(RESERVED_PARAMS);
70
65
  for (const key of [...dataKeys, ...functionKeys]) {
71
66
  if (!VALID_IDENTIFIER.test(key)) {
@@ -81,22 +76,22 @@ function validateParamKeys(dataKeys: string[], functionKeys: string[]): void {
81
76
  function createH(components: ComponentDict, createElement: CreateElement, schema: Schema): H {
82
77
  return function h(type, props, ...children) {
83
78
  if (typeof type === "function") {
84
- return createElement(type as Component, props, ...children.flat().filter(Boolean));
79
+ return createElement(type as Component, props, ...children.flat().filter(Boolean)) as Node;
85
80
  }
86
81
 
87
82
  const Component = components[type];
88
83
 
89
84
  if (!Component) {
90
85
  if (isElementAllowed(schema, type)) {
91
- const defaultComponent = (props: PropsDict): any => (canHaveChildren(schema, type) ? props["children"] : null);
92
- return createElement(defaultComponent, props, ...children.flat().filter(Boolean));
86
+ const defaultComponent = (props: PropsDict): unknown => (canHaveChildren(schema, type) ? props["children"] : null);
87
+ return createElement(defaultComponent, props, ...children.flat().filter(Boolean)) as Node;
93
88
  }
94
89
 
95
90
  // Component not in schema - throw error
96
91
  throw new EvaluationError(`component "${type}" is not allowed`);
97
92
  }
98
93
 
99
- return createElement(Component, props, ...children.flat().filter(Boolean));
94
+ return createElement(Component, props, ...children.flat().filter(Boolean)) as Node;
100
95
  };
101
96
  }
102
97
 
@@ -110,6 +105,6 @@ function deepFreezeData(obj: Record<string, unknown>): Record<string, unknown> {
110
105
  return obj;
111
106
  }
112
107
 
113
- function defaultCreateElement(Component: Component, props: PropsDict = {}, ...children: any[]): Node {
114
- return Component({ ...props, children });
108
+ function defaultCreateElement(Component: Component, props: PropsDict = {}, ...children: Array<unknown>): Node {
109
+ return (Component as (props: PropsDict & { children: Array<unknown> }) => Node)({ ...props, children });
115
110
  }
@@ -1,3 +1,4 @@
1
+ // oxlint-disable-next-line functional/no-classes -- extends Error, which requires a class
1
2
  export class EvaluationError extends Error {
2
3
  constructor(message: string) {
3
4
  super(message);
package/src/index.ts CHANGED
@@ -1,10 +1,4 @@
1
- export {
2
- type Schema,
3
- type PropertySchema,
4
- type FunctionSchema,
5
- serializePropertySchemaToJson,
6
- deserializePropertySchemaFromJson
7
- } from "./schema.js";
1
+ export { type Schema, type PropertySchema, type FunctionSchema, serializePropertySchemaToJson, deserializePropertySchemaFromJson } from "./schema.js";
8
2
 
9
3
  export { ParseError } from "./parse/index.js";
10
4
  export { CompilationError } from "./compile/index.js";