jsxpression 0.1.5 → 0.1.8
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/evaluate/evaluate.d.ts +2 -1
- package/lib/evaluate/evaluate.d.ts.map +1 -1
- package/lib/evaluate/evaluate.js +10 -8
- package/lib/evaluate/evaluate.js.map +1 -1
- package/lib/evaluate/evaluate.test.js +35 -25
- package/lib/evaluate/evaluate.test.js.map +1 -1
- package/lib/render.js +1 -1
- package/lib/render.js.map +1 -1
- package/package.json +2 -2
- package/src/evaluate/evaluate.test.ts +39 -25
- package/src/evaluate/evaluate.ts +11 -8
- package/src/render.ts +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Schema } from "../schema.js";
|
|
1
2
|
export type ComponentDict = Record<string, Component>;
|
|
2
3
|
export type CreateElement<T = any> = (type: Component, props?: PropsDict, ...children: any[]) => T;
|
|
3
4
|
export type PropsDict = Record<string, unknown>;
|
|
@@ -22,5 +23,5 @@ export interface EvaluateOptions<T = any> {
|
|
|
22
23
|
/** Function to create JSX elements (e.g., React.createElement, h) */
|
|
23
24
|
createElement?: CreateElement<T>;
|
|
24
25
|
}
|
|
25
|
-
export declare function evaluate<T = any>(source: string, options: EvaluateOptions<T>): T;
|
|
26
|
+
export declare function evaluate<T = any>(source: string, schema: Schema, options: EvaluateOptions<T>): T;
|
|
26
27
|
//# sourceMappingURL=evaluate.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evaluate.d.ts","sourceRoot":"","sources":["../../src/evaluate/evaluate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"evaluate.d.ts","sourceRoot":"","sources":["../../src/evaluate/evaluate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAqC,MAAM,cAAc,CAAC;AAEzE,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAEtD,MAAM,MAAM,aAAa,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,SAAS,EAAE,GAAG,QAAQ,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AAEnG,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhD,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE/C,MAAM,MAAM,IAAI,GAAG;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,IAAI,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,SAAS,EAAE,GAAG,QAAQ,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;AAE/E,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC;AAEhD;;;;GAIG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,GAAG;IACtC,2DAA2D;IAC3D,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,gEAAgE;IAChE,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,qEAAqE;IACrE,aAAa,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;CAClC;AAED,wBAAgB,QAAQ,CAAC,CAAC,GAAG,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,CAAC,CAgBhG"}
|
package/lib/evaluate/evaluate.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { EvaluationError } from "./evaluation-error.js";
|
|
2
|
-
|
|
2
|
+
import { isElementAllowed, canHaveChildren } from "../schema.js";
|
|
3
|
+
export function evaluate(source, schema, options) {
|
|
3
4
|
const { data = {}, components = {}, createElement } = options;
|
|
4
|
-
const h = createH(components, createElement || defaultCreateElement);
|
|
5
|
+
const h = createH(components, createElement || defaultCreateElement, schema);
|
|
5
6
|
try {
|
|
6
7
|
// eslint-disable-next-line @typescript-eslint/no-implied-eval, no-new-func
|
|
7
8
|
return new Function("h", "data", "Math", source)(h, deepFreezeData(data), Math);
|
|
@@ -14,10 +15,15 @@ export function evaluate(source, options) {
|
|
|
14
15
|
throw new EvaluationError(error instanceof Error ? error.message : "Evaluation failed");
|
|
15
16
|
}
|
|
16
17
|
}
|
|
17
|
-
function createH(components, createElement) {
|
|
18
|
+
function createH(components, createElement, schema) {
|
|
18
19
|
return function h(type, props, ...children) {
|
|
19
20
|
const Component = components[type];
|
|
20
21
|
if (!Component) {
|
|
22
|
+
if (isElementAllowed(schema, type)) {
|
|
23
|
+
const defaultComponent = (props) => (canHaveChildren(schema, type) ? props.children : null);
|
|
24
|
+
return createElement(defaultComponent, props, ...children.flat().filter(Boolean));
|
|
25
|
+
}
|
|
26
|
+
// Component not in schema - throw error
|
|
21
27
|
throw new EvaluationError(`component "${type}" is not allowed`);
|
|
22
28
|
}
|
|
23
29
|
return createElement(Component, props, ...children.flat().filter(Boolean));
|
|
@@ -32,10 +38,6 @@ function isDataDict(value) {
|
|
|
32
38
|
return typeof value === "object" && value !== null;
|
|
33
39
|
}
|
|
34
40
|
function defaultCreateElement(Component, props = {}, ...children) {
|
|
35
|
-
return {
|
|
36
|
-
type: Component.name,
|
|
37
|
-
props,
|
|
38
|
-
children,
|
|
39
|
-
};
|
|
41
|
+
return Component({ ...props, children });
|
|
40
42
|
}
|
|
41
43
|
//# sourceMappingURL=evaluate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evaluate.js","sourceRoot":"","sources":["../../src/evaluate/evaluate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"evaluate.js","sourceRoot":"","sources":["../../src/evaluate/evaluate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAU,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAkCzE,MAAM,UAAU,QAAQ,CAAU,MAAc,EAAE,MAAc,EAAE,OAA2B;IAC3F,MAAM,EAAE,IAAI,GAAG,EAAE,EAAE,UAAU,GAAG,EAAE,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC;IAE9D,MAAM,CAAC,GAAG,OAAO,CAAC,UAAU,EAAE,aAAa,IAAI,oBAAoB,EAAE,MAAM,CAAC,CAAC;IAE7E,IAAI,CAAC;QACH,2EAA2E;QAC3E,OAAO,IAAI,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,IAAI,CAAC,EAAE,IAAI,CAAM,CAAC;IACvF,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,uDAAuD;QACvD,IAAI,KAAK,YAAY,eAAe,EAAE,CAAC;YACrC,MAAM,KAAK,CAAC;QACd,CAAC;QAED,MAAM,IAAI,eAAe,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC;IAC1F,CAAC;AACH,CAAC;AAED,SAAS,OAAO,CAAC,UAAyB,EAAE,aAA4B,EAAE,MAAc;IACtF,OAAO,SAAS,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,QAAQ;QACxC,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QAEnC,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,IAAI,gBAAgB,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC;gBACnC,MAAM,gBAAgB,GAAG,CAAC,KAAgB,EAAO,EAAE,CAAC,CAAC,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBAC5G,OAAO,aAAa,CAAC,gBAAgB,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;YACpF,CAAC;YAED,wCAAwC;YACxC,MAAM,IAAI,eAAe,CAAC,cAAc,IAAI,kBAAkB,CAAC,CAAC;QAClE,CAAC;QAED,OAAO,aAAa,CAAC,SAAS,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7E,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,GAAa;IACnC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACnB,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IAC9D,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,UAAU,CAAC,KAAU;IAC5B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;AACrD,CAAC;AAED,SAAS,oBAAoB,CAAC,SAAoB,EAAE,QAAmB,EAAE,EAAE,GAAG,QAAe;IAC3F,OAAO,SAAS,CAAC,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -3,15 +3,22 @@ import { evaluate } from "./evaluate.js";
|
|
|
3
3
|
import { compile } from "../compile/index.js";
|
|
4
4
|
import { parse } from "../parse/index.js";
|
|
5
5
|
import { EvaluationError } from "./evaluation-error.js";
|
|
6
|
+
function createPermissiveSchema(componentNames) {
|
|
7
|
+
return {
|
|
8
|
+
elements: Object.fromEntries(componentNames.map((name) => [name, {}])),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
6
11
|
describe("evaluate", () => {
|
|
7
12
|
const compileAndEvaluate = (source, options = {}) => {
|
|
8
|
-
|
|
13
|
+
const componentNames = Object.keys(options.components || {});
|
|
14
|
+
const schema = createPermissiveSchema(componentNames);
|
|
15
|
+
return evaluate(compile(parse(source)), schema, options);
|
|
9
16
|
};
|
|
10
17
|
it("should evaluate JSX with props", () => {
|
|
11
|
-
const TestComponent = (props
|
|
18
|
+
const TestComponent = (props) => ({
|
|
12
19
|
type: "TestComponent",
|
|
13
|
-
props,
|
|
14
|
-
children,
|
|
20
|
+
props: { x: props.x, y: props.y },
|
|
21
|
+
children: props.children,
|
|
15
22
|
});
|
|
16
23
|
const result = compileAndEvaluate("<Test x={data.x} y={data.y}>Hello</Test>", {
|
|
17
24
|
data: { x: 10, y: 20 },
|
|
@@ -41,8 +48,9 @@ describe("evaluate", () => {
|
|
|
41
48
|
});
|
|
42
49
|
it("should throw EvaluationError for unknown component", () => {
|
|
43
50
|
const compiled = compile(parse("<UnknownComponent>Hello</UnknownComponent>"));
|
|
44
|
-
|
|
45
|
-
expect(() => evaluate(compiled, { components: {} })).toThrow(
|
|
51
|
+
const emptySchema = createPermissiveSchema([]);
|
|
52
|
+
expect(() => evaluate(compiled, emptySchema, { components: {} })).toThrow(EvaluationError);
|
|
53
|
+
expect(() => evaluate(compiled, emptySchema, { components: {} })).toThrow('component "UnknownComponent" is not allowed');
|
|
46
54
|
});
|
|
47
55
|
it("should deep-freeze props to prevent mutations", () => {
|
|
48
56
|
const TestComponent = (props) => {
|
|
@@ -52,7 +60,8 @@ describe("evaluate", () => {
|
|
|
52
60
|
return { type: "Test", props, children: [] };
|
|
53
61
|
};
|
|
54
62
|
const compiled = compile(parse("<Test>Hello</Test>"));
|
|
55
|
-
|
|
63
|
+
const schema = createPermissiveSchema(["Test"]);
|
|
64
|
+
evaluate(compiled, schema, {
|
|
56
65
|
data: { nested: { value: 42 } },
|
|
57
66
|
components: {
|
|
58
67
|
Test: TestComponent,
|
|
@@ -60,15 +69,15 @@ describe("evaluate", () => {
|
|
|
60
69
|
});
|
|
61
70
|
});
|
|
62
71
|
it("should evaluate nested elements", () => {
|
|
63
|
-
const OuterComponent = (props
|
|
72
|
+
const OuterComponent = (props) => ({
|
|
64
73
|
type: "Outer",
|
|
65
|
-
props,
|
|
66
|
-
children,
|
|
74
|
+
props: { x: props.x },
|
|
75
|
+
children: props.children,
|
|
67
76
|
});
|
|
68
|
-
const InnerComponent = (props
|
|
77
|
+
const InnerComponent = (props) => ({
|
|
69
78
|
type: "Inner",
|
|
70
|
-
props,
|
|
71
|
-
children,
|
|
79
|
+
props: { y: props.y },
|
|
80
|
+
children: props.children,
|
|
72
81
|
});
|
|
73
82
|
const result = compileAndEvaluate("<Outer x={data.x}><Inner y={data.y}>Text</Inner></Outer>", {
|
|
74
83
|
data: { x: 10, y: 20 },
|
|
@@ -77,11 +86,11 @@ describe("evaluate", () => {
|
|
|
77
86
|
Inner: InnerComponent,
|
|
78
87
|
},
|
|
79
88
|
});
|
|
80
|
-
expect(result.type).toBe("
|
|
89
|
+
expect(result.type).toBe("Outer");
|
|
81
90
|
expect(result.props).toEqual({ x: 10 });
|
|
82
91
|
expect(result.children).toHaveLength(1);
|
|
83
92
|
const innerNode = result.children[0];
|
|
84
|
-
expect(innerNode.type).toBe("
|
|
93
|
+
expect(innerNode.type).toBe("Inner");
|
|
85
94
|
expect(innerNode.props).toEqual({ y: 20 });
|
|
86
95
|
expect(innerNode.children).toEqual(["Text"]);
|
|
87
96
|
});
|
|
@@ -135,7 +144,8 @@ describe("evaluate", () => {
|
|
|
135
144
|
it("should handle runtime errors gracefully", () => {
|
|
136
145
|
const compiled = compile(parse("<Test value={data.missing.nested}>Text</Test>"));
|
|
137
146
|
const TestComponent = () => ({ type: "Test", props: {}, children: [] });
|
|
138
|
-
|
|
147
|
+
const schema = createPermissiveSchema(["Test"]);
|
|
148
|
+
expect(() => evaluate(compiled, schema, {
|
|
139
149
|
data: {},
|
|
140
150
|
components: {
|
|
141
151
|
Test: TestComponent,
|
|
@@ -157,10 +167,10 @@ describe("evaluate", () => {
|
|
|
157
167
|
expect(result.props.msg).toBe("Anonymous");
|
|
158
168
|
});
|
|
159
169
|
it("should flatten and filter children correctly", () => {
|
|
160
|
-
const TestComponent = (props
|
|
170
|
+
const TestComponent = (props) => ({
|
|
161
171
|
type: "Test",
|
|
162
|
-
props,
|
|
163
|
-
children,
|
|
172
|
+
props: {},
|
|
173
|
+
children: props.children,
|
|
164
174
|
});
|
|
165
175
|
const result = compileAndEvaluate("<Test>{data.show && 'Visible'}{false}{'Always'}</Test>", {
|
|
166
176
|
data: { show: true },
|
|
@@ -179,10 +189,10 @@ describe("evaluate", () => {
|
|
|
179
189
|
expect(result).toHaveLength(2);
|
|
180
190
|
});
|
|
181
191
|
it("should handle empty JSX expressions", () => {
|
|
182
|
-
const TestComponent = (props
|
|
192
|
+
const TestComponent = (props) => ({
|
|
183
193
|
type: "Test",
|
|
184
|
-
props,
|
|
185
|
-
children,
|
|
194
|
+
props: {},
|
|
195
|
+
children: props.children,
|
|
186
196
|
});
|
|
187
197
|
const result = compileAndEvaluate("<Test>{}{data.value}{}</Test>", {
|
|
188
198
|
data: { value: "hello" },
|
|
@@ -235,10 +245,10 @@ describe("evaluate", () => {
|
|
|
235
245
|
expect(result.props.value).toBe(11); // 5 + (3 * 2)
|
|
236
246
|
});
|
|
237
247
|
it("should handle data access in children", () => {
|
|
238
|
-
const TestComponent = (props
|
|
248
|
+
const TestComponent = (props) => ({
|
|
239
249
|
type: "Test",
|
|
240
|
-
props,
|
|
241
|
-
children,
|
|
250
|
+
props: {},
|
|
251
|
+
children: props.children,
|
|
242
252
|
});
|
|
243
253
|
const result = compileAndEvaluate("<Test>Hello {data.name}!</Test>", {
|
|
244
254
|
data: { name: "World" },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evaluate.test.js","sourceRoot":"","sources":["../../src/evaluate/evaluate.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAwB,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"evaluate.test.js","sourceRoot":"","sources":["../../src/evaluate/evaluate.test.ts"],"names":[],"mappings":"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"}
|
package/lib/render.js
CHANGED
|
@@ -48,6 +48,6 @@ export function render(source, schema, { minSeverity = 3, ...options } = {}) {
|
|
|
48
48
|
if (report.hasIssues(minSeverity)) {
|
|
49
49
|
throw AnalysisError.fromReport(report);
|
|
50
50
|
}
|
|
51
|
-
return evaluate(compile(ast), options);
|
|
51
|
+
return evaluate(compile(ast), schema, options);
|
|
52
52
|
}
|
|
53
53
|
//# sourceMappingURL=render.js.map
|
package/lib/render.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAmB,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAiB5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,UAAU,MAAM,CACpB,MAAc,EACd,MAAc,EACd,EAAE,WAAW,GAAG,CAAC,EAAE,GAAG,OAAO,KAAuB,EAAE;IAEtD,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAEpC,IAAI,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC;QAClC,MAAM,aAAa,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC;IAED,OAAO,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,OAAO,CAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAmB,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAiB5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,UAAU,MAAM,CACpB,MAAc,EACd,MAAc,EACd,EAAE,WAAW,GAAG,CAAC,EAAE,GAAG,OAAO,KAAuB,EAAE;IAEtD,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAEpC,IAAI,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC;QAClC,MAAM,aAAa,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC;IAED,OAAO,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,OAAO,CAAM,CAAC;AACtD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jsxpression",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Validate and safely render JSX expressions",
|
|
5
5
|
"author": "Divid AB <info@divid.se>",
|
|
6
6
|
"repository": "https://github.com/dividab/abstract-visuals/tree/master/packages/jsxpression",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"acorn-jsx": "5.3.2",
|
|
23
23
|
"acorn-walk": "8.3.4"
|
|
24
24
|
},
|
|
25
|
-
"gitHead": "
|
|
25
|
+
"gitHead": "4c1cdfd1bde58b9cc64d88f4bc01b2e32fcd75e1",
|
|
26
26
|
"scripts": {
|
|
27
27
|
"test": "vitest run src/**/*.test.ts"
|
|
28
28
|
}
|
|
@@ -2,6 +2,7 @@ import { describe, it, expect, vi } from "vitest";
|
|
|
2
2
|
import { evaluate, type EvaluateOptions } from "./evaluate.js";
|
|
3
3
|
import { compile } from "../compile/index.js";
|
|
4
4
|
import { parse } from "../parse/index.js";
|
|
5
|
+
import { Schema } from "../schema.js";
|
|
5
6
|
|
|
6
7
|
import { EvaluationError } from "./evaluation-error.js";
|
|
7
8
|
|
|
@@ -11,16 +12,24 @@ type Node = {
|
|
|
11
12
|
children: Node[];
|
|
12
13
|
};
|
|
13
14
|
|
|
15
|
+
function createPermissiveSchema(componentNames: string[]): Schema {
|
|
16
|
+
return {
|
|
17
|
+
elements: Object.fromEntries(componentNames.map((name) => [name, {}])),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
14
21
|
describe("evaluate", () => {
|
|
15
22
|
const compileAndEvaluate = (source: string, options: EvaluateOptions = {}): Node => {
|
|
16
|
-
|
|
23
|
+
const componentNames = Object.keys(options.components || {});
|
|
24
|
+
const schema = createPermissiveSchema(componentNames);
|
|
25
|
+
return evaluate(compile(parse(source)), schema, options);
|
|
17
26
|
};
|
|
18
27
|
|
|
19
28
|
it("should evaluate JSX with props", () => {
|
|
20
|
-
const TestComponent = (props: any
|
|
29
|
+
const TestComponent = (props: any): Node => ({
|
|
21
30
|
type: "TestComponent",
|
|
22
|
-
props,
|
|
23
|
-
children,
|
|
31
|
+
props: { x: props.x, y: props.y },
|
|
32
|
+
children: props.children,
|
|
24
33
|
});
|
|
25
34
|
|
|
26
35
|
const result = compileAndEvaluate("<Test x={data.x} y={data.y}>Hello</Test>", {
|
|
@@ -56,9 +65,12 @@ describe("evaluate", () => {
|
|
|
56
65
|
|
|
57
66
|
it("should throw EvaluationError for unknown component", () => {
|
|
58
67
|
const compiled = compile(parse("<UnknownComponent>Hello</UnknownComponent>"));
|
|
68
|
+
const emptySchema = createPermissiveSchema([]);
|
|
59
69
|
|
|
60
|
-
expect(() => evaluate(compiled, { components: {} })).toThrow(EvaluationError);
|
|
61
|
-
expect(() => evaluate(compiled, { components: {} })).toThrow(
|
|
70
|
+
expect(() => evaluate(compiled, emptySchema, { components: {} })).toThrow(EvaluationError);
|
|
71
|
+
expect(() => evaluate(compiled, emptySchema, { components: {} })).toThrow(
|
|
72
|
+
'component "UnknownComponent" is not allowed'
|
|
73
|
+
);
|
|
62
74
|
});
|
|
63
75
|
|
|
64
76
|
it("should deep-freeze props to prevent mutations", () => {
|
|
@@ -70,8 +82,9 @@ describe("evaluate", () => {
|
|
|
70
82
|
};
|
|
71
83
|
|
|
72
84
|
const compiled = compile(parse("<Test>Hello</Test>"));
|
|
85
|
+
const schema = createPermissiveSchema(["Test"]);
|
|
73
86
|
|
|
74
|
-
evaluate(compiled, {
|
|
87
|
+
evaluate(compiled, schema, {
|
|
75
88
|
data: { nested: { value: 42 } },
|
|
76
89
|
components: {
|
|
77
90
|
Test: TestComponent,
|
|
@@ -80,16 +93,16 @@ describe("evaluate", () => {
|
|
|
80
93
|
});
|
|
81
94
|
|
|
82
95
|
it("should evaluate nested elements", () => {
|
|
83
|
-
const OuterComponent = (props: any
|
|
96
|
+
const OuterComponent = (props: any): Node => ({
|
|
84
97
|
type: "Outer",
|
|
85
|
-
props,
|
|
86
|
-
children,
|
|
98
|
+
props: { x: props.x },
|
|
99
|
+
children: props.children,
|
|
87
100
|
});
|
|
88
101
|
|
|
89
|
-
const InnerComponent = (props: any
|
|
102
|
+
const InnerComponent = (props: any): Node => ({
|
|
90
103
|
type: "Inner",
|
|
91
|
-
props,
|
|
92
|
-
children,
|
|
104
|
+
props: { y: props.y },
|
|
105
|
+
children: props.children,
|
|
93
106
|
});
|
|
94
107
|
|
|
95
108
|
const result = compileAndEvaluate("<Outer x={data.x}><Inner y={data.y}>Text</Inner></Outer>", {
|
|
@@ -100,11 +113,11 @@ describe("evaluate", () => {
|
|
|
100
113
|
},
|
|
101
114
|
});
|
|
102
115
|
|
|
103
|
-
expect(result.type).toBe("
|
|
116
|
+
expect(result.type).toBe("Outer");
|
|
104
117
|
expect(result.props).toEqual({ x: 10 });
|
|
105
118
|
expect(result.children).toHaveLength(1);
|
|
106
119
|
const innerNode = result.children[0] as Node;
|
|
107
|
-
expect(innerNode.type).toBe("
|
|
120
|
+
expect(innerNode.type).toBe("Inner");
|
|
108
121
|
expect(innerNode.props).toEqual({ y: 20 });
|
|
109
122
|
expect(innerNode.children).toEqual(["Text"]);
|
|
110
123
|
});
|
|
@@ -169,9 +182,10 @@ describe("evaluate", () => {
|
|
|
169
182
|
it("should handle runtime errors gracefully", () => {
|
|
170
183
|
const compiled = compile(parse("<Test value={data.missing.nested}>Text</Test>"));
|
|
171
184
|
const TestComponent = (): Node => ({ type: "Test", props: {}, children: [] });
|
|
185
|
+
const schema = createPermissiveSchema(["Test"]);
|
|
172
186
|
|
|
173
187
|
expect(() =>
|
|
174
|
-
evaluate(compiled, {
|
|
188
|
+
evaluate(compiled, schema, {
|
|
175
189
|
data: {},
|
|
176
190
|
components: {
|
|
177
191
|
Test: TestComponent,
|
|
@@ -198,10 +212,10 @@ describe("evaluate", () => {
|
|
|
198
212
|
});
|
|
199
213
|
|
|
200
214
|
it("should flatten and filter children correctly", () => {
|
|
201
|
-
const TestComponent = (props: any
|
|
215
|
+
const TestComponent = (props: any): Node => ({
|
|
202
216
|
type: "Test",
|
|
203
|
-
props,
|
|
204
|
-
children,
|
|
217
|
+
props: {},
|
|
218
|
+
children: props.children,
|
|
205
219
|
});
|
|
206
220
|
|
|
207
221
|
const result = compileAndEvaluate("<Test>{data.show && 'Visible'}{false}{'Always'}</Test>", {
|
|
@@ -226,10 +240,10 @@ describe("evaluate", () => {
|
|
|
226
240
|
});
|
|
227
241
|
|
|
228
242
|
it("should handle empty JSX expressions", () => {
|
|
229
|
-
const TestComponent = (props: any
|
|
243
|
+
const TestComponent = (props: any): Node => ({
|
|
230
244
|
type: "Test",
|
|
231
|
-
props,
|
|
232
|
-
children,
|
|
245
|
+
props: {},
|
|
246
|
+
children: props.children,
|
|
233
247
|
});
|
|
234
248
|
|
|
235
249
|
const result = compileAndEvaluate("<Test>{}{data.value}{}</Test>", {
|
|
@@ -300,10 +314,10 @@ describe("evaluate", () => {
|
|
|
300
314
|
});
|
|
301
315
|
|
|
302
316
|
it("should handle data access in children", () => {
|
|
303
|
-
const TestComponent = (props: any
|
|
317
|
+
const TestComponent = (props: any): Node => ({
|
|
304
318
|
type: "Test",
|
|
305
|
-
props,
|
|
306
|
-
children,
|
|
319
|
+
props: {},
|
|
320
|
+
children: props.children,
|
|
307
321
|
});
|
|
308
322
|
|
|
309
323
|
const result = compileAndEvaluate("<Test>Hello {data.name}!</Test>", {
|
package/src/evaluate/evaluate.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { EvaluationError } from "./evaluation-error.js";
|
|
2
|
+
import { Schema, isElementAllowed, canHaveChildren } from "../schema.js";
|
|
2
3
|
|
|
3
4
|
export type ComponentDict = Record<string, Component>;
|
|
4
5
|
|
|
@@ -32,10 +33,10 @@ export interface EvaluateOptions<T = any> {
|
|
|
32
33
|
createElement?: CreateElement<T>;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
export function evaluate<T = any>(source: string, options: EvaluateOptions<T>): T {
|
|
36
|
+
export function evaluate<T = any>(source: string, schema: Schema, options: EvaluateOptions<T>): T {
|
|
36
37
|
const { data = {}, components = {}, createElement } = options;
|
|
37
38
|
|
|
38
|
-
const h = createH(components, createElement || defaultCreateElement);
|
|
39
|
+
const h = createH(components, createElement || defaultCreateElement, schema);
|
|
39
40
|
|
|
40
41
|
try {
|
|
41
42
|
// eslint-disable-next-line @typescript-eslint/no-implied-eval, no-new-func
|
|
@@ -50,11 +51,17 @@ export function evaluate<T = any>(source: string, options: EvaluateOptions<T>):
|
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
function createH(components: ComponentDict, createElement: CreateElement): H {
|
|
54
|
+
function createH(components: ComponentDict, createElement: CreateElement, schema: Schema): H {
|
|
54
55
|
return function h(type, props, ...children) {
|
|
55
56
|
const Component = components[type];
|
|
56
57
|
|
|
57
58
|
if (!Component) {
|
|
59
|
+
if (isElementAllowed(schema, type)) {
|
|
60
|
+
const defaultComponent = (props: PropsDict): any => (canHaveChildren(schema, type) ? props.children : null);
|
|
61
|
+
return createElement(defaultComponent, props, ...children.flat().filter(Boolean));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Component not in schema - throw error
|
|
58
65
|
throw new EvaluationError(`component "${type}" is not allowed`);
|
|
59
66
|
}
|
|
60
67
|
|
|
@@ -73,9 +80,5 @@ function isDataDict(value: any): value is DataDict {
|
|
|
73
80
|
}
|
|
74
81
|
|
|
75
82
|
function defaultCreateElement(Component: Component, props: PropsDict = {}, ...children: any[]): Node {
|
|
76
|
-
return {
|
|
77
|
-
type: Component.name,
|
|
78
|
-
props,
|
|
79
|
-
children,
|
|
80
|
-
};
|
|
83
|
+
return Component({ ...props, children });
|
|
81
84
|
}
|
package/src/render.ts
CHANGED