jsxpression 0.1.41 → 0.2.1

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 (183) 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 +3 -3
  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.d.ts.map +1 -1
  94. package/lib/codegen/schema/function-types.js +1 -3
  95. package/lib/codegen/schema/function-types.js.map +1 -1
  96. package/lib/codegen/schema/utils.d.ts +4 -3
  97. package/lib/codegen/schema/utils.d.ts.map +1 -1
  98. package/lib/codegen/schema/utils.js +12 -8
  99. package/lib/codegen/schema/utils.js.map +1 -1
  100. package/lib/compile/compilation-error.d.ts +1 -1
  101. package/lib/compile/compilation-error.d.ts.map +1 -1
  102. package/lib/compile/compilation-error.js +3 -1
  103. package/lib/compile/compilation-error.js.map +1 -1
  104. package/lib/compile/compile.d.ts.map +1 -1
  105. package/lib/compile/compile.js +5 -11
  106. package/lib/compile/compile.js.map +1 -1
  107. package/lib/evaluate/evaluate.d.ts +6 -6
  108. package/lib/evaluate/evaluate.d.ts.map +1 -1
  109. package/lib/evaluate/evaluate.js +1 -1
  110. package/lib/evaluate/evaluate.js.map +1 -1
  111. package/lib/evaluate/evaluation-error.d.ts.map +1 -1
  112. package/lib/evaluate/evaluation-error.js +1 -0
  113. package/lib/evaluate/evaluation-error.js.map +1 -1
  114. package/lib/index.d.ts +1 -1
  115. package/lib/index.d.ts.map +1 -1
  116. package/lib/index.js +1 -1
  117. package/lib/index.js.map +1 -1
  118. package/lib/jsx.d.ts +3 -3
  119. package/lib/jsx.d.ts.map +1 -1
  120. package/lib/jsx.js.map +1 -1
  121. package/lib/parse/parse-error.d.ts.map +1 -1
  122. package/lib/parse/parse-error.js +1 -0
  123. package/lib/parse/parse-error.js.map +1 -1
  124. package/lib/render.d.ts +25 -33
  125. package/lib/render.d.ts.map +1 -1
  126. package/lib/render.js +21 -26
  127. package/lib/render.js.map +1 -1
  128. package/lib/schema.d.ts +9 -9
  129. package/lib/schema.d.ts.map +1 -1
  130. package/lib/schema.js +1 -1
  131. package/lib/schema.js.map +1 -1
  132. package/lib/traverse.d.ts.map +1 -1
  133. package/lib/traverse.js.map +1 -1
  134. package/lib/validate.d.ts +14 -17
  135. package/lib/validate.d.ts.map +1 -1
  136. package/lib/validate.js +13 -14
  137. package/lib/validate.js.map +1 -1
  138. package/package.json +12 -12
  139. package/src/analyze/analysis-error.ts +2 -6
  140. package/src/analyze/analysis-report.ts +73 -62
  141. package/src/analyze/analyze.test.ts +60 -60
  142. package/src/analyze/analyze.ts +4 -4
  143. package/src/analyze/data/analyze.ts +5 -8
  144. package/src/analyze/data/data-access.ts +49 -46
  145. package/src/analyze/data/method-calls.ts +9 -18
  146. package/src/analyze/data/utils.ts +15 -19
  147. package/src/analyze/index.ts +1 -1
  148. package/src/analyze/jsx/analyze.ts +4 -4
  149. package/src/analyze/jsx/element-attributes.ts +5 -18
  150. package/src/analyze/jsx/element-children.ts +4 -8
  151. package/src/analyze/jsx/element-tags.ts +2 -2
  152. package/src/analyze/security/analyze.ts +4 -4
  153. package/src/analyze/security/call-expressions.ts +5 -18
  154. package/src/analyze/security/declarations.ts +14 -43
  155. package/src/analyze/security/expressions.ts +12 -49
  156. package/src/analyze/security/identifiers.ts +37 -39
  157. package/src/analyze/utils.ts +25 -19
  158. package/src/analyze/validation-context.ts +32 -23
  159. package/src/builtins.ts +27 -38
  160. package/src/codegen/builtins/builtin-types.ts +13 -20
  161. package/src/codegen/generate-typescript-definitions.test.ts +6 -6
  162. package/src/codegen/generate-typescript-definitions.ts +19 -23
  163. package/src/codegen/schema/component-types.ts +22 -12
  164. package/src/codegen/schema/data-types.ts +6 -6
  165. package/src/codegen/schema/function-types.ts +1 -3
  166. package/src/codegen/schema/utils.ts +24 -23
  167. package/src/compile/compilation-error.ts +5 -1
  168. package/src/compile/compile.test.ts +7 -21
  169. package/src/compile/compile.ts +18 -30
  170. package/src/evaluate/evaluate.test.ts +78 -94
  171. package/src/evaluate/evaluate.ts +15 -20
  172. package/src/evaluate/evaluation-error.ts +1 -0
  173. package/src/index.ts +1 -7
  174. package/src/jsx.ts +4 -6
  175. package/src/parse/parse-error.ts +1 -0
  176. package/src/parse/parse.test.ts +16 -18
  177. package/src/render.test.ts +4 -4
  178. package/src/render.ts +26 -38
  179. package/src/schema.ts +11 -11
  180. package/src/traverse.test.ts +6 -6
  181. package/src/traverse.ts +3 -3
  182. package/src/validate.ts +14 -17
  183. package/CHANGELOG.md +0 -8
@@ -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
51
  // oxlint-disable-next-line typescript/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;
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";
package/src/jsx.ts CHANGED
@@ -19,9 +19,7 @@ export type JSXLiteral = {
19
19
 
20
20
  export type JSXAttributeValue = JSXLiteral | JSXExpressionContainer;
21
21
 
22
- export type JSXNameNode =
23
- | { type: "JSXIdentifier"; name: string }
24
- | { type: "JSXMemberExpression"; object: JSXNameNode; property: JSXNameNode };
22
+ export type JSXNameNode = { type: "JSXIdentifier"; name: string } | { type: "JSXMemberExpression"; object: JSXNameNode; property: JSXNameNode };
25
23
 
26
24
  export type JSXAttribute = {
27
25
  type: "JSXAttribute";
@@ -41,7 +39,7 @@ export type JSXOpeningElement = {
41
39
  name: {
42
40
  name: string;
43
41
  };
44
- attributes: (JSXAttribute | JSXSpreadAttribute)[];
42
+ attributes: Array<JSXAttribute | JSXSpreadAttribute>;
45
43
  };
46
44
 
47
45
  export type JSXClosingElement = {
@@ -53,12 +51,12 @@ export type JSXElement = {
53
51
  type: "JSXElement";
54
52
  openingElement: JSXOpeningElement;
55
53
  closingElement?: JSXClosingElement;
56
- children: JSXNode[];
54
+ children: Array<JSXNode>;
57
55
  };
58
56
 
59
57
  export type JSXFragment = {
60
58
  type: "JSXFragment";
61
- children: JSXNode[];
59
+ children: Array<JSXNode>;
62
60
  };
63
61
 
64
62
  export type JSXText = {
@@ -3,6 +3,7 @@ type Loc = {
3
3
  column: number;
4
4
  };
5
5
 
6
+ // oxlint-disable-next-line functional/no-classes -- extends Error, which requires a class
6
7
  export class ParseError extends Error {
7
8
  readonly loc?: Loc;
8
9
 
@@ -1,6 +1,15 @@
1
1
  import { describe, it, expect } from "vitest";
2
- import { parse } from "./parse.js";
3
2
  import { ParseError } from "./parse-error.js";
3
+ import { parse } from "./parse.js";
4
+
5
+ function getThrownError(fn: () => unknown): unknown {
6
+ try {
7
+ fn();
8
+ } catch (error) {
9
+ return error;
10
+ }
11
+ throw new Error("Expected function to throw");
12
+ }
4
13
 
5
14
  describe("parse", () => {
6
15
  it("should parse valid JSX element", () => {
@@ -20,12 +29,6 @@ describe("parse", () => {
20
29
 
21
30
  it("should throw ParseError with position for syntax error", () => {
22
31
  expect(() => parse("<Text>Unclosed")).toThrow(ParseError);
23
-
24
- try {
25
- parse("<Text>Unclosed");
26
- } catch (error) {
27
- expect(error).toBeInstanceOf(ParseError);
28
- }
29
32
  });
30
33
 
31
34
  it("should parse nested JSX", () => {
@@ -78,17 +81,12 @@ describe("parse", () => {
78
81
  });
79
82
 
80
83
  it("should preserve location information in errors", () => {
81
- try {
82
- parse("<Text>Unclosed");
83
- throw new Error("Should have thrown ParseError");
84
- } catch (error) {
85
- expect(error).toBeInstanceOf(ParseError);
86
- if (error instanceof ParseError && error.loc) {
87
- expect(error.loc).toBeDefined();
88
- expect(error.loc.line).toBe(1);
89
- expect(error.loc.column).toBe(6);
90
- }
91
- }
84
+ const error = getThrownError(() => parse("<Text>Unclosed"));
85
+
86
+ expect(error).toBeInstanceOf(ParseError);
87
+ expect((error as ParseError).loc).toBeDefined();
88
+ expect((error as ParseError).loc?.line).toBe(1);
89
+ expect((error as ParseError).loc?.column).toBe(6);
92
90
  });
93
91
 
94
92
  it("should handle invalid JSX syntax", () => {
@@ -7,12 +7,12 @@ import { render } from "./render.js";
7
7
  type TestNode = {
8
8
  type: string;
9
9
  props: Record<string, unknown>;
10
- children: unknown[];
10
+ children: Array<unknown>;
11
11
  };
12
12
 
13
13
  describe("render", () => {
14
14
  it("should render complete JSX pipeline successfully", () => {
15
- const TestComponent = ({ children, ...props }: { x: number; y: number; children?: any[] }): TestNode => ({
15
+ const TestComponent = ({ children, ...props }: { x: number; y: number; children?: Array<unknown> }): TestNode => ({
16
16
  type: "TestComponent",
17
17
  props,
18
18
  children: children ?? [],
@@ -76,13 +76,13 @@ describe("render", () => {
76
76
  });
77
77
 
78
78
  it("should render nested JSX elements", () => {
79
- const OuterComponent = ({ children, ...props }: { x: number; children?: any[] }): TestNode => ({
79
+ const OuterComponent = ({ children, ...props }: { x: number; children?: Array<unknown> }): TestNode => ({
80
80
  type: "OuterComponent",
81
81
  props,
82
82
  children: children ?? [],
83
83
  });
84
84
 
85
- const InnerComponent = ({ children, ...props }: { y: number; children?: any[] }): TestNode => ({
85
+ const InnerComponent = ({ children, ...props }: { y: number; children?: Array<unknown> }): TestNode => ({
86
86
  type: "InnerComponent",
87
87
  props,
88
88
  children: children ?? [],
package/src/render.ts CHANGED
@@ -1,30 +1,45 @@
1
+ import { analyze, AnalysisError } from "./analyze/index.js";
1
2
  import { compile as compileInternal } from "./compile/index.js";
2
3
  import type { EvaluateOptions } from "./evaluate/evaluate.js";
3
4
  import { evaluate } from "./evaluate/evaluate.js";
4
5
  import { parse } from "./parse/index.js";
5
6
  import type { Schema } from "./schema.js";
6
- import { analyze, AnalysisError } from "./analyze/index.js";
7
7
 
8
8
  /**
9
9
  * Configuration options for rendering JSX expressions.
10
10
  *
11
- * Extends EvaluateOptions with render-specific functionality, including control over
12
- * the minimum severity threshold that stops rendering.
11
+ * Extends EvaluateOptions with render-specific functionality, including control over the minimum severity threshold that stops rendering.
13
12
  *
14
13
  * @template T - The return type of createElement function
15
14
  */
16
- export interface RenderOptions<T = any> extends EvaluateOptions<T> {
17
- /**
18
- * Minimum severity level that counts as a failure: 1=info, 2=warning, 3=error.
19
- */
15
+ export interface RenderOptions<T = unknown> extends EvaluateOptions<T> {
16
+ /** Minimum severity level that counts as a failure: 1=info, 2=warning, 3=error. */
20
17
  minSeverity?: 1 | 2 | 3;
21
18
  }
22
19
 
23
20
  /**
24
21
  * Renders a JSX expression with data validation and security constraints.
25
22
  *
26
- * Parses JSX source code, validates it against a schema for security and type safety,
27
- * compiles it to executable code, and evaluates it with the provided data and components.
23
+ * Parses JSX source code, validates it against a schema for security and type safety, compiles it to executable code, and evaluates it with the
24
+ * provided data and components.
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const schema: Schema = {
29
+ * data: {
30
+ * user: { type: "object", shape: { name: { type: "string" } } },
31
+ * },
32
+ * elements: {
33
+ * Text: { props: { children: { type: "string" } } },
34
+ * },
35
+ * };
36
+ *
37
+ * const result = render("<Text>Hello {user.name}!</Text>", schema, {
38
+ * data: { user: { name: "World" } },
39
+ * components: { Text: ({ children }) => children },
40
+ * createElement: (type, props, ...children) => ({ type, props, children }),
41
+ * });
42
+ * ```;
28
43
  *
29
44
  * @template T - The return type of the rendered JSX (e.g., ReactElement, VNode, string)
30
45
  * @param source - JSX expression source code to render (e.g., `"<Text x={user.name}>Hello</Text>"`)
@@ -35,36 +50,9 @@ export interface RenderOptions<T = any> extends EvaluateOptions<T> {
35
50
  * @param options.createElement - Function to create elements (e.g., React.createElement)
36
51
  * @param options.minSeverity - Minimum severity (1=info, 2=warning, 3=error) required to abort rendering; defaults to `3`
37
52
  * @returns The rendered JSX element of type T
38
- *
39
53
  * @throws {AnalysisError} When JSX contains security violations, invalid data access, or schema mismatches
40
- *
41
- * @example
42
- * ```typescript
43
- * const schema: Schema = {
44
- * data: {
45
- * user: { type: "object", shape: { name: { type: "string" } } }
46
- * },
47
- * elements: {
48
- * Text: { props: { children: { type: "string" } } }
49
- * }
50
- * };
51
- *
52
- * const result = render(
53
- * "<Text>Hello {user.name}!</Text>",
54
- * schema,
55
- * {
56
- * data: { user: { name: "World" } },
57
- * components: { Text: ({ children }) => children },
58
- * createElement: (type, props, ...children) => ({ type, props, children })
59
- * }
60
- * );
61
- * ```
62
54
  */
63
- export function render<T = any>(
64
- source: string,
65
- schema: Schema,
66
- { minSeverity = 3, ...options }: RenderOptions<T> = {}
67
- ): T {
55
+ export function render<T = unknown>(source: string, schema: Schema, { minSeverity = 3, ...options }: RenderOptions<T> = {}): T {
68
56
  const ast = parse(source);
69
57
  const report = analyze(ast, schema);
70
58
 
@@ -75,7 +63,7 @@ export function render<T = any>(
75
63
  return evaluate(compileInternal(ast), schema, options);
76
64
  }
77
65
 
78
- export function compile<T = any>(source: string, schema: Schema, { minSeverity = 3 }: RenderOptions<T> = {}): string {
66
+ export function compile<T = unknown>(source: string, schema: Schema, { minSeverity = 3 }: RenderOptions<T> = {}): string {
79
67
  const ast = parse(source);
80
68
  const report = analyze(ast, schema);
81
69
  if (report.hasIssues(minSeverity)) {
package/src/schema.ts CHANGED
@@ -6,7 +6,7 @@ export type StringPropertySchema = {
6
6
  description?: string;
7
7
  required?: boolean;
8
8
  default?: string;
9
- enum?: readonly string[];
9
+ enum?: ReadonlyArray<string>;
10
10
  };
11
11
 
12
12
  export type NumberPropertySchema = {
@@ -14,7 +14,7 @@ export type NumberPropertySchema = {
14
14
  description?: string;
15
15
  required?: boolean;
16
16
  default?: number;
17
- enum?: readonly number[];
17
+ enum?: ReadonlyArray<number>;
18
18
  };
19
19
 
20
20
  export type BooleanPropertySchema = {
@@ -22,7 +22,7 @@ export type BooleanPropertySchema = {
22
22
  description?: string;
23
23
  required?: boolean;
24
24
  default?: boolean;
25
- enum?: readonly boolean[];
25
+ enum?: ReadonlyArray<boolean>;
26
26
  };
27
27
 
28
28
  export type FunctionPropertySchema = {
@@ -72,7 +72,7 @@ export type PropertySchema =
72
72
  export type ElementSchema = {
73
73
  description?: string;
74
74
  props?: Record<string, PropertySchema>;
75
- allowedChildren?: string[];
75
+ allowedChildren?: Array<string>;
76
76
  };
77
77
 
78
78
  export type ArgumentSchema = {
@@ -175,7 +175,7 @@ export function getElementSchema(schema: Schema, tagName: string): ElementSchema
175
175
  return schema.elements?.[tagName];
176
176
  }
177
177
 
178
- export function getAllowedAttributes(schema: Schema, tagName: string): string[] {
178
+ export function getAllowedAttributes(schema: Schema, tagName: string): Array<string> {
179
179
  const elementConfig = getElementSchema(schema, tagName);
180
180
  return elementConfig?.props ? Object.keys(elementConfig.props) : [];
181
181
  }
@@ -185,7 +185,7 @@ export function isAttributeAllowed(schema: Schema, tagName: string, attributeNam
185
185
  return allowedAttributes.includes(attributeName);
186
186
  }
187
187
 
188
- export function getAllowedChildren(schema: Schema, tagName: string): string[] | undefined {
188
+ export function getAllowedChildren(schema: Schema, tagName: string): Array<string> | undefined {
189
189
  const elementConfig = getElementSchema(schema, tagName);
190
190
  return elementConfig?.allowedChildren;
191
191
  }
@@ -197,7 +197,7 @@ export function canHaveChildren(schema: Schema, tagName: string): boolean {
197
197
 
198
198
  export function isSelfClosing(schema: Schema, tagName: string): boolean {
199
199
  const allowedChildren = getAllowedChildren(schema, tagName);
200
- return allowedChildren !== undefined && allowedChildren.length === 0;
200
+ return allowedChildren?.length === 0;
201
201
  }
202
202
 
203
203
  export function isChildAllowed(schema: Schema, parentTag: string, childTag: string): boolean {
@@ -206,7 +206,7 @@ export function isChildAllowed(schema: Schema, parentTag: string, childTag: stri
206
206
  }
207
207
 
208
208
  // New schema utilities for enhanced validation
209
- export function getAllElements(schema: Schema): string[] {
209
+ export function getAllElements(schema: Schema): Array<string> {
210
210
  return schema.elements ? Object.keys(schema.elements) : [];
211
211
  }
212
212
 
@@ -215,13 +215,13 @@ export function getAttributeSchema(schema: Schema, tagName: string, attributeNam
215
215
  return elementSchema?.props?.[attributeName];
216
216
  }
217
217
 
218
- export function getRequiredAttributes(schema: Schema, tagName: string): string[] {
218
+ export function getRequiredAttributes(schema: Schema, tagName: string): Array<string> {
219
219
  const elementSchema = getElementSchema(schema, tagName);
220
220
  if (!elementSchema?.props) {
221
221
  return [];
222
222
  }
223
223
 
224
- const required: string[] = [];
224
+ const required: Array<string> = [];
225
225
  for (const [attrName, attrSchema] of Object.entries(elementSchema.props)) {
226
226
  if (attrSchema.required === true) {
227
227
  required.push(attrName);
@@ -233,7 +233,7 @@ export function getRequiredAttributes(schema: Schema, tagName: string): string[]
233
233
 
234
234
  type PropertyEnumValue = string | number | boolean;
235
235
 
236
- export function getEnumValues(property: PropertySchema): readonly PropertyEnumValue[] | undefined {
236
+ export function getEnumValues(property: PropertySchema): ReadonlyArray<PropertyEnumValue> | undefined {
237
237
  switch (property.type) {
238
238
  case "string":
239
239
  return property.enum;
@@ -1,11 +1,11 @@
1
1
  import { describe, it, expect } from "vitest";
2
- import { traverse } from "./traverse.js";
3
2
  import { parse } from "./parse/index.js";
3
+ import { traverse } from "./traverse.js";
4
4
 
5
5
  describe("traverse", () => {
6
6
  it("should call JSXElement visitor", () => {
7
7
  const ast = parse("<Text>Hello</Text>");
8
- const visits: string[] = [];
8
+ const visits: Array<string> = [];
9
9
 
10
10
  traverse(ast, {
11
11
  JSXElement() {
@@ -18,7 +18,7 @@ describe("traverse", () => {
18
18
 
19
19
  it("should call JSXFragment visitor", () => {
20
20
  const ast = parse("<>Fragment</>");
21
- const visits: string[] = [];
21
+ const visits: Array<string> = [];
22
22
 
23
23
  traverse(ast, {
24
24
  JSXFragment() {
@@ -31,7 +31,7 @@ describe("traverse", () => {
31
31
 
32
32
  it("should call Identifier visitor for expressions", () => {
33
33
  const ast = parse("<Text>{props.value}</Text>");
34
- const identifiers: string[] = [];
34
+ const identifiers: Array<string> = [];
35
35
 
36
36
  traverse(ast, {
37
37
  Identifier(node) {
@@ -57,7 +57,7 @@ describe("traverse", () => {
57
57
 
58
58
  it("should call JSXExpressionContainer visitor", () => {
59
59
  const ast = parse("<Text>{props.value}</Text>");
60
- const visits: string[] = [];
60
+ const visits: Array<string> = [];
61
61
 
62
62
  traverse(ast, {
63
63
  JSXExpressionContainer() {
@@ -83,7 +83,7 @@ describe("traverse", () => {
83
83
 
84
84
  it("should handle multiple visitor types simultaneously", () => {
85
85
  const ast = parse("<Text x={props.value}>Hello</Text>");
86
- const visits: string[] = [];
86
+ const visits: Array<string> = [];
87
87
 
88
88
  traverse(ast, {
89
89
  JSXElement() {
package/src/traverse.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { Program } from "acorn";
2
- import { base, type RecursiveVisitors, type SimpleVisitors, simple } from "acorn-walk";
1
+ import type { Node, Program } from "acorn";
2
+ import { base, type RecursiveVisitors, type SimpleVisitors, simple, type WalkerCallback } from "acorn-walk";
3
3
  import {
4
4
  isJsxEmptyExpression,
5
5
  isJsxText,
@@ -101,7 +101,7 @@ const tsNodeTypes = [
101
101
  "TSThisType",
102
102
  ] as const;
103
103
 
104
- const tsWalkers: Record<string, (node: any, state: any, c: any) => void> = {};
104
+ const tsWalkers: Record<string, (node: Node, state: unknown, callback: WalkerCallback<unknown>) => void> = {};
105
105
  for (const nodeType of tsNodeTypes) {
106
106
  tsWalkers[nodeType] = () => {};
107
107
  }
package/src/validate.ts CHANGED
@@ -5,34 +5,31 @@ import type { Schema } from "./schema.js";
5
5
  export type ValidateResult = { ok: true } | { ok: false; error: AnalysisError | ParseError };
6
6
 
7
7
  export interface ValidateOptions {
8
- /**
9
- * Minimum severity level that counts as a failure: 1=info, 2=warning, 3=error.
10
- */
8
+ /** Minimum severity level that counts as a failure: 1=info, 2=warning, 3=error. */
11
9
  minSeverity?: 1 | 2 | 3;
12
10
  }
13
11
  /**
14
12
  * Validates JSX expression syntax and schema compliance without execution.
15
13
  *
16
- * Performs static analysis to check if JSX source code is valid according to the schema.
17
- * This includes syntax validation, security constraints, JSX element/attribute validation,
18
- * and data access pattern validation - all without needing actual data or components.
14
+ * Performs static analysis to check if JSX source code is valid according to the schema. This includes syntax validation, security constraints, JSX
15
+ * element/attribute validation, and data access pattern validation - all without needing actual data or components.
19
16
  *
20
17
  * This function parses the source code and returns a simple ok/error result.
21
18
  *
19
+ * @example
20
+ * ```typescript
21
+ * const result = validate("<Text>{user.name}</Text>", schema);
22
+ * if (result.ok) {
23
+ * console.log("JSX is valid!");
24
+ * } else {
25
+ * console.error("Validation failed with", result.report.errors.length, "errors");
26
+ * result.report.errors.forEach((err) => console.error(err.message));
27
+ * }
28
+ * ```;
29
+ *
22
30
  * @param source - JSX expression source code to validate
23
31
  * @param schema - Schema defining allowed data properties, JSX elements, and hierarchy rules
24
32
  * @returns Validation result indicating success or failure with parse or analysis error
25
- *
26
- * @example
27
- * ```typescript
28
- * const result = validate("<Text>{user.name}</Text>", schema);
29
- * if (result.ok) {
30
- * console.log("JSX is valid!");
31
- * } else {
32
- * console.error("Validation failed with", result.report.errors.length, "errors");
33
- * result.report.errors.forEach(err => console.error(err.message));
34
- * }
35
- * ```
36
33
  */
37
34
  export function validate(
38
35
  source: string,
package/CHANGELOG.md DELETED
@@ -1,8 +0,0 @@
1
- # Change Log
2
-
3
- All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).
4
-
5
- ## [0.1.39] - 2026-09-05
6
-
7
- - Wired the package's test suite into the shared workspace test runner.
8
- - Internal: adopt `verbatimModuleSyntax` and stricter compiler/lint settings. No other functional changes.