jsxpression 0.1.41 → 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 (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 +14 -14
  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 +14 -18
  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 +76 -92
  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 +1 -1
  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
@@ -1,6 +1,6 @@
1
1
  import { describe, it, expect } from "vitest";
2
+ import type { ElementSchema, Schema } from "../schema.js";
2
3
  import { generateTypeScriptDefinitions } from "./generate-typescript-definitions.js";
3
- import type { Schema } from "../schema.js";
4
4
 
5
5
  describe("generateTypeScriptDefinitions", () => {
6
6
  describe("basic structure", () => {
@@ -230,10 +230,11 @@ describe("generateTypeScriptDefinitions", () => {
230
230
  const schema: Schema = {
231
231
  data: {},
232
232
  elements: {
233
+ // `content` isn't part of ElementSchema; this intersection type documents that it's a legacy/unmodeled field being tested here.
233
234
  Input: {
234
235
  props: {},
235
236
  content: false,
236
- } as any,
237
+ } as ElementSchema & { content: boolean },
237
238
  },
238
239
  };
239
240
 
@@ -525,9 +526,7 @@ describe("generateTypeScriptDefinitions", () => {
525
526
  };
526
527
 
527
528
  const result = generateTypeScriptDefinitions(schema);
528
- expect(result).toContain(
529
- `id: "TypeA";\n valueA: string;\n } | {\n id: "TypeB";\n valueB: number;\n };`
530
- );
529
+ expect(result).toContain(`id: "TypeA";\n valueA: string;\n } | {\n id: "TypeB";\n valueB: number;\n };`);
531
530
  });
532
531
 
533
532
  it("should generate functions", () => {
@@ -608,8 +607,9 @@ describe("generateTypeScriptDefinitions", () => {
608
607
  shape: { type: "string" },
609
608
  },
610
609
  },
610
+ // `content` isn't part of ElementSchema; this intersection type documents that it's a legacy/unmodeled field being tested here.
611
611
  content: false,
612
- } as any,
612
+ } as ElementSchema & { content: boolean },
613
613
  },
614
614
  };
615
615
 
@@ -6,35 +6,31 @@ import { declareComponentTypes, declareDataTypes, declareFunctionTypes } from ".
6
6
  * Generates TypeScript definitions from a JSXExpression schema.
7
7
  *
8
8
  * The generated definitions enable code editors to provide:
9
+ *
9
10
  * - IntelliSense autocomplete for components and data properties
10
11
  * - Type checking for JSX expressions
11
12
  * - Hover documentation from schema descriptions
12
13
  *
13
- * @param schema - Schema defining allowed data properties, JSX elements, and their types
14
- * @returns Complete TypeScript definition file as a string
15
- *
16
14
  * @example
17
- * ```typescript
18
- * const schema = {
19
- * elements: {
20
- * Button: {
21
- * props: { size: { type: "string", enum: ["sm", "md", "lg"] } }
22
- * }
23
- * },
24
- * data: {
25
- * user: { type: "object", shape: { name: { type: "string" } } }
26
- * }
27
- * };
15
+ * ```typescript
16
+ * const schema = {
17
+ * elements: {
18
+ * Button: {
19
+ * props: { size: { type: "string", enum: ["sm", "md", "lg"] } },
20
+ * },
21
+ * },
22
+ * data: {
23
+ * user: { type: "object", shape: { name: { type: "string" } } },
24
+ * },
25
+ * };
28
26
  *
29
- * const definitions = generateTypeScriptDefinitions(schema);
30
- * // Use with Monaco, VS Code, or any TypeScript-enabled editor
31
- * ```
27
+ * const definitions = generateTypeScriptDefinitions(schema);
28
+ * // Use with Monaco, VS Code, or any TypeScript-enabled editor
29
+ * ```;
30
+ *
31
+ * @param schema - Schema defining allowed data properties, JSX elements, and their types
32
+ * @returns Complete TypeScript definition file as a string
32
33
  */
33
34
  export function generateTypeScriptDefinitions(schema: Schema): string {
34
- return [
35
- declareBuiltinTypes(),
36
- declareComponentTypes(schema),
37
- declareDataTypes(schema),
38
- declareFunctionTypes(schema),
39
- ].join("\n");
35
+ return [declareBuiltinTypes(), declareComponentTypes(schema), declareDataTypes(schema), declareFunctionTypes(schema)].join("\n");
40
36
  }
@@ -1,6 +1,13 @@
1
- import type { Schema } from "../../schema.js";
1
+ import type { ElementSchema, PropertySchema, Schema } from "../../schema.js";
2
2
  import { mapSchemaTypeToTypeScript } from "./utils.js";
3
3
 
4
+ // ElementSchema fields the generator supports that aren't (yet) part of the shared schema type.
5
+ type ElementSchemaExtras = ElementSchema & {
6
+ content?: boolean;
7
+ doc?: string;
8
+ examples?: ReadonlyArray<string>;
9
+ };
10
+
4
11
  export function declareComponentTypes(schema: Schema): string {
5
12
  let output = `declare global {\n`;
6
13
 
@@ -29,10 +36,10 @@ export function declareComponentTypes(schema: Schema): string {
29
36
  return output;
30
37
  }
31
38
 
32
- function generatePropsInterface(interfaceName: string, element: any, indent: string = ""): string {
39
+ function generatePropsInterface(interfaceName: string, element: ElementSchemaExtras, indent: string = ""): string {
33
40
  let output = `${indent}interface ${interfaceName} {\n`;
34
41
 
35
- Object.entries(element.props || {}).forEach(([propName, prop]: [string, any]) => {
42
+ Object.entries(element.props ?? {}).forEach(([propName, prop]) => {
36
43
  const optional = prop.required ? "" : "?";
37
44
  const type = mapSchemaTypeToTypeScript(prop);
38
45
  const comment = generatePropComment(prop, `${indent} `);
@@ -51,8 +58,8 @@ function generatePropsInterface(interfaceName: string, element: any, indent: str
51
58
  return output;
52
59
  }
53
60
 
54
- function generateComponentComment(elementName: string, element: any, indent: string = ""): string {
55
- const comments: string[] = [];
61
+ function generateComponentComment(elementName: string, element: ElementSchemaExtras, indent: string = ""): string {
62
+ const comments: Array<string> = [];
56
63
 
57
64
  if (element.description) {
58
65
  comments.push(element.description);
@@ -66,7 +73,7 @@ function generateComponentComment(elementName: string, element: any, indent: str
66
73
  comments.push("");
67
74
  comments.push(`@param props Component props`);
68
75
 
69
- Object.entries(element.props).forEach(([propName, prop]: [string, any]) => {
76
+ Object.entries(element.props).forEach(([propName, prop]) => {
70
77
  if (prop.description) {
71
78
  comments.push(`@param props.${propName} ${prop.description}`);
72
79
  }
@@ -79,7 +86,7 @@ function generateComponentComment(elementName: string, element: any, indent: str
79
86
  if (element.examples && element.examples.length > 0) {
80
87
  comments.push("");
81
88
  comments.push("@example");
82
- element.examples.forEach((example: string) => {
89
+ element.examples.forEach((example) => {
83
90
  comments.push(example);
84
91
  });
85
92
  }
@@ -107,19 +114,22 @@ function generateComponentComment(elementName: string, element: any, indent: str
107
114
  return output;
108
115
  }
109
116
 
110
- function generatePropComment(prop: any, indent: string): string {
111
- const comments: string[] = [];
117
+ function generatePropComment(prop: PropertySchema, indent: string): string {
118
+ const comments: Array<string> = [];
112
119
 
113
120
  if (prop.description) {
114
121
  comments.push(prop.description);
115
122
  }
116
123
 
117
- if (prop.default !== undefined) {
124
+ if ((prop.type === "string" || prop.type === "number" || prop.type === "boolean") && prop.default !== undefined) {
118
125
  comments.push(`@default ${JSON.stringify(prop.default)}`);
119
126
  }
120
127
 
121
- if (prop.type === "enum" && prop.values) {
122
- comments.push(`@values ${prop.values.map((v: any) => `"${v}"`).join(", ")}`);
128
+ // oxlint-disable-next-line typescript/no-explicit-any -- "enum" isn't a PropertySchema.type variant; kept as-is rather than deleted by this type-only lint pass
129
+ const propAsAny = prop as any;
130
+ if (propAsAny.type === "enum" && propAsAny.values) {
131
+ // oxlint-disable-next-line typescript/no-explicit-any -- propAsAny.values is untyped ("enum" isn't a PropertySchema.type variant)
132
+ comments.push(`@values ${propAsAny.values.map((v: any) => `"${v}"`).join(", ")}`);
123
133
  }
124
134
 
125
135
  if (comments.length === 0) {
@@ -1,4 +1,4 @@
1
- import type { Schema } from "../../schema.js";
1
+ import type { PropertySchema, Schema } from "../../schema.js";
2
2
  import { mapSchemaTypeToTypeScript } from "./utils.js";
3
3
 
4
4
  export function declareDataTypes(schema: Schema): string {
@@ -21,8 +21,8 @@ export function declareDataTypes(schema: Schema): string {
21
21
  return output;
22
22
  }
23
23
 
24
- function generateNestedPropertyJSDoc(propertyName: string, propertySchema: any, indent: string = ""): string {
25
- const comments: string[] = [];
24
+ function generateNestedPropertyJSDoc(propertyName: string, propertySchema: PropertySchema, indent: string = ""): string {
25
+ const comments: Array<string> = [];
26
26
 
27
27
  if (propertySchema.description) {
28
28
  comments.push(propertySchema.description);
@@ -39,15 +39,15 @@ function generateNestedPropertyJSDoc(propertyName: string, propertySchema: any,
39
39
  let hasNestedProperties = false;
40
40
  if (propertySchema.type === "object" && propertySchema.shape) {
41
41
  comments.push("");
42
- Object.entries(propertySchema.shape).forEach(([key, value]: [string, any]) => {
42
+ Object.entries(propertySchema.shape).forEach(([key, value]) => {
43
43
  if (value.description) {
44
44
  comments.push(`@property ${key} ${value.description}`);
45
45
  hasNestedProperties = true;
46
46
  }
47
47
  });
48
- } else if (propertySchema.type === "array" && propertySchema.shape?.type === "object" && propertySchema.shape.shape) {
48
+ } else if (propertySchema.type === "array" && propertySchema.shape.type === "object" && propertySchema.shape.shape) {
49
49
  comments.push("");
50
- Object.entries(propertySchema.shape.shape).forEach(([key, value]: [string, any]) => {
50
+ Object.entries(propertySchema.shape.shape).forEach(([key, value]) => {
51
51
  if (value.description) {
52
52
  comments.push(`@property ${key} ${value.description}`);
53
53
  hasNestedProperties = true;
@@ -6,9 +6,7 @@ export function declareFunctionTypes(schema: Schema): string {
6
6
 
7
7
  if (schema.functions) {
8
8
  Object.entries(schema.functions).forEach(([funcName, funcSchema]) => {
9
- const args = funcSchema.args
10
- ? funcSchema.args.map((arg) => `${arg.name}: ${mapSchemaTypeToTypeScript(arg.property)}`).join(", ")
11
- : "";
9
+ const args = funcSchema.args ? funcSchema.args.map((arg) => `${arg.name}: ${mapSchemaTypeToTypeScript(arg.property)}`).join(", ") : "";
12
10
  const ret = funcSchema.ret ? mapSchemaTypeToTypeScript(funcSchema.ret) : "void";
13
11
  output += `function ${funcName}(${args}): ${ret};\n`;
14
12
  });
@@ -1,50 +1,56 @@
1
- export function mapSchemaTypeToTypeScript(prop: any, depth: number = 0): string {
1
+ import type { PropertySchema } from "../../schema.js";
2
+
3
+ export function mapSchemaTypeToTypeScript(prop: PropertySchema, depth: number = 0): string {
2
4
  switch (prop.type) {
3
5
  case "string":
4
6
  if (prop.enum && Array.isArray(prop.enum)) {
5
- return prop.enum.map((value: any) => `"${value}"`).join(" | ");
7
+ return prop.enum.map((value) => `"${value}"`).join(" | ");
6
8
  }
7
9
  return "string";
8
10
  case "number":
9
11
  if (prop.enum && Array.isArray(prop.enum)) {
10
- return prop.enum.map((value: any) => String(value)).join(" | ");
12
+ return prop.enum.map((value) => String(value)).join(" | ");
11
13
  }
12
14
  return "number";
13
15
  case "boolean":
14
16
  if (prop.enum && Array.isArray(prop.enum)) {
15
- return prop.enum.map((value: any) => String(value)).join(" | ");
17
+ return prop.enum.map((value) => String(value)).join(" | ");
16
18
  }
17
19
  return "boolean";
18
- case "array":
20
+ case "array": {
19
21
  const itemType = prop.shape ? mapSchemaTypeToTypeScript(prop.shape, depth) : "any";
20
22
  return `${itemType}[]`;
21
- case "object":
23
+ }
24
+ case "object": {
22
25
  if (prop.shape && typeof prop.shape === "object") {
23
26
  return generateObjectTypeWithJSDoc(prop.shape, depth);
24
27
  }
25
- if (prop.properties && typeof prop.properties === "object") {
26
- return generateObjectTypeWithJSDoc(prop.properties, depth);
28
+ // oxlint-disable-next-line typescript/no-explicit-any -- "properties" isn't an ObjectPropertySchema field; kept as a legacy fallback rather than removed by this type-only pass
29
+ const propAsAny = prop as any;
30
+ if (propAsAny.properties && typeof propAsAny.properties === "object") {
31
+ return generateObjectTypeWithJSDoc(propAsAny.properties, depth);
27
32
  }
28
33
  return "object";
29
- case "record":
34
+ }
35
+ case "record": {
30
36
  const valueType = prop.shape ? mapSchemaTypeToTypeScript(prop.shape) : "any";
31
37
  return `Record<string, ${valueType}>`;
38
+ }
32
39
  case "function":
33
40
  return "(...args: any[]) => any";
34
41
  case "union": {
35
- return `${prop.shape.map((p: any) => mapSchemaTypeToTypeScript(p)).join(" | ")}`;
42
+ return prop.shape.map((p) => mapSchemaTypeToTypeScript(p)).join(" | ");
36
43
  }
37
44
  default:
38
- console.warn(`Unknown schema type: ${prop.type}`);
39
45
  return "any";
40
46
  }
41
47
  }
42
48
 
43
- export function generateObjectTypeWithJSDoc(properties: any, depth: number = 0): string {
49
+ export function generateObjectTypeWithJSDoc(properties: Record<string, PropertySchema>, depth: number = 0): string {
44
50
  let result = "{\n";
45
51
 
46
52
  // Generate each property with inline JSDoc
47
- Object.entries(properties).forEach(([key, value]: [string, any]) => {
53
+ Object.entries(properties).forEach(([key, value]) => {
48
54
  // Generate comprehensive JSDoc for this property
49
55
  const propertyJSDoc = generatePropertyJSDoc(key, value, " ", depth);
50
56
  result += propertyJSDoc;
@@ -59,13 +65,8 @@ export function generateObjectTypeWithJSDoc(properties: any, depth: number = 0):
59
65
  return result;
60
66
  }
61
67
 
62
- export function generatePropertyJSDoc(
63
- _propertyName: string,
64
- propertySchema: any,
65
- indent: string = "",
66
- _depth: number = 0
67
- ): string {
68
- const comments: string[] = [];
68
+ export function generatePropertyJSDoc(_propertyName: string, propertySchema: PropertySchema, indent: string = "", _depth: number = 0): string {
69
+ const comments: Array<string> = [];
69
70
 
70
71
  // Main description
71
72
  if (propertySchema.description) {
@@ -76,16 +77,16 @@ export function generatePropertyJSDoc(
76
77
  let hasNestedProperties = false;
77
78
  if (propertySchema.type === "object" && propertySchema.shape) {
78
79
  comments.push("");
79
- Object.entries(propertySchema.shape).forEach(([key, value]: [string, any]) => {
80
+ Object.entries(propertySchema.shape).forEach(([key, value]) => {
80
81
  if (value.description) {
81
82
  comments.push(`@property ${key} ${value.description}`);
82
83
  hasNestedProperties = true;
83
84
  }
84
85
  });
85
- } else if (propertySchema.type === "array" && propertySchema.shape?.type === "object" && propertySchema.shape.shape) {
86
+ } else if (propertySchema.type === "array" && propertySchema.shape.type === "object" && propertySchema.shape.shape) {
86
87
  // For arrays of objects, document the object structure
87
88
  comments.push("");
88
- Object.entries(propertySchema.shape.shape).forEach(([key, value]: [string, any]) => {
89
+ Object.entries(propertySchema.shape.shape).forEach(([key, value]) => {
89
90
  if (value.description) {
90
91
  comments.push(`@property ${key} ${value.description}`);
91
92
  hasNestedProperties = true;
@@ -1,3 +1,5 @@
1
+ import type { Node } from "acorn";
2
+
1
3
  type Loc = {
2
4
  start: {
3
5
  line: number;
@@ -9,8 +11,10 @@ type Loc = {
9
11
  };
10
12
  };
11
13
 
14
+ // oxlint-disable-next-line functional/no-classes -- extends Error, which requires a class
12
15
  export class CompilationError extends Error {
13
- static fromNode(message: string, node: any): CompilationError {
16
+ static fromNode(message: string, nodeParam: unknown): CompilationError {
17
+ const node = nodeParam as Node;
14
18
  const loc = node.loc
15
19
  ? {
16
20
  start: {
@@ -30,9 +30,7 @@ describe("compile", () => {
30
30
  it("should compile nested ternary expressions", () => {
31
31
  const ast = parse("<div>{props.level > 2 ? 'high' : props.level > 1 ? 'medium' : 'low'}</div>");
32
32
  const result = compile(ast);
33
- expect(result).toBe(
34
- '"use strict";return h("div", null, ((props.level > 2)?"high":((props.level > 1)?"medium":"low")));'
35
- );
33
+ expect(result).toBe('"use strict";return h("div", null, ((props.level > 2)?"high":((props.level > 1)?"medium":"low")));');
36
34
  });
37
35
 
38
36
  it("should compile nested JSX elements", () => {
@@ -44,9 +42,7 @@ describe("compile", () => {
44
42
  it("should compile nested array operations", () => {
45
43
  const ast = parse("<div>{props.items.map(x => x.split(',').map(y => y.trim()).join(' ')).join(' | ')}</div>");
46
44
  const result = compile(ast);
47
- expect(result).toBe(
48
- '"use strict";return h("div", null, props.items.map((x) => x.split(",").map((y) => y.trim()).join(" ")).join(" | "));'
49
- );
45
+ expect(result).toBe('"use strict";return h("div", null, props.items.map((x) => x.split(",").map((y) => y.trim()).join(" ")).join(" | "));');
50
46
  });
51
47
 
52
48
  it("should compile bare expression containers", () => {
@@ -217,23 +213,17 @@ describe("compile", () => {
217
213
  it("should compile function with props parameter", () => {
218
214
  const ast = parse('function Badge({ label }) {\n return <span>{label}</span>\n}\nreturn <Badge label="hi" />');
219
215
  const result = compile(ast);
220
- expect(result).toBe(
221
- '"use strict";function Badge({ label }) { return h("span", null, label); }return h(Badge, { label: "hi" });'
222
- );
216
+ expect(result).toBe('"use strict";function Badge({ label }) { return h("span", null, label); }return h(Badge, { label: "hi" });');
223
217
  });
224
218
 
225
219
  it("should compile function with default parameter", () => {
226
220
  const ast = parse("function Badge({ label = 'default' }) {\n return <span>{label}</span>\n}\nreturn <Badge />");
227
221
  const result = compile(ast);
228
- expect(result).toBe(
229
- '"use strict";function Badge({ label = "default" }) { return h("span", null, label); }return h(Badge, null);'
230
- );
222
+ expect(result).toBe('"use strict";function Badge({ label = "default" }) { return h("span", null, label); }return h(Badge, null);');
231
223
  });
232
224
 
233
225
  it("should compile function with const inside body", () => {
234
- const ast = parse(
235
- "function Badge({ value }) {\n const doubled = value * 2;\n return <span>{doubled}</span>\n}\nreturn <Badge value={5} />"
236
- );
226
+ const ast = parse("function Badge({ value }) {\n const doubled = value * 2;\n return <span>{doubled}</span>\n}\nreturn <Badge value={5} />");
237
227
  const result = compile(ast);
238
228
  expect(result).toContain("const doubled = (value * 2);");
239
229
  expect(result).toContain('return h("span", null, doubled);');
@@ -248,9 +238,7 @@ describe("compile", () => {
248
238
  });
249
239
 
250
240
  it("should compile multiple function declarations", () => {
251
- const ast = parse(
252
- "function A() {\n return <span>a</span>\n}\nfunction B() {\n return <span>b</span>\n}\nreturn <div><A /><B /></div>"
253
- );
241
+ const ast = parse("function A() {\n return <span>a</span>\n}\nfunction B() {\n return <span>b</span>\n}\nreturn <div><A /><B /></div>");
254
242
  const result = compile(ast);
255
243
  expect(result).toContain("function A()");
256
244
  expect(result).toContain("function B()");
@@ -259,9 +247,7 @@ describe("compile", () => {
259
247
  });
260
248
 
261
249
  it("should compile function calling another function", () => {
262
- const ast = parse(
263
- "function Inner() {\n return <span>inner</span>\n}\nfunction Outer() {\n return <div><Inner /></div>\n}\nreturn <Outer />"
264
- );
250
+ const ast = parse("function Inner() {\n return <span>inner</span>\n}\nfunction Outer() {\n return <div><Inner /></div>\n}\nreturn <Outer />");
265
251
  const result = compile(ast);
266
252
  expect(result).toContain("function Inner()");
267
253
  expect(result).toContain("function Outer()");
@@ -11,7 +11,6 @@ import type {
11
11
  Super,
12
12
  VariableDeclaration,
13
13
  } from "acorn";
14
-
15
14
  import {
16
15
  isJsxElement,
17
16
  isJsxEmptyExpression,
@@ -40,7 +39,7 @@ export function compile(ast: Program): string {
40
39
  }
41
40
  }
42
41
 
43
- const parts: string[] = ['"use strict";'];
42
+ const parts: Array<string> = ['"use strict";'];
44
43
 
45
44
  const hasDeclarations = ast.body.some((s) => s.type === "VariableDeclaration" || s.type === "FunctionDeclaration");
46
45
 
@@ -108,13 +107,13 @@ function emitJsxName(nameNode: JSXNameNode, localFunctions: Set<string>): string
108
107
  return JSON.stringify(JSON.parse(left) + "." + JSON.parse(right));
109
108
  }
110
109
  default:
111
- throw CompilationError.fromNode(`Unsupported JSX name: ${(nameNode as any).type}`, nameNode);
110
+ throw CompilationError.fromNode(`Unsupported JSX name: ${(nameNode as { type: string }).type}`, nameNode);
112
111
  }
113
112
  }
114
113
 
115
- function emitAttributes(attributes: (JSXAttribute | JSXSpreadAttribute)[], localFunctions: Set<string>): string {
116
- const parts: string[] = [];
117
- let currentObj: string[] = [];
114
+ function emitAttributes(attributes: Array<JSXAttribute | JSXSpreadAttribute>, localFunctions: Set<string>): string {
115
+ const parts: Array<string> = [];
116
+ let currentObj: Array<string> = [];
118
117
 
119
118
  const flushCurrent = (): void => {
120
119
  if (currentObj.length) {
@@ -136,7 +135,7 @@ function emitAttributes(attributes: (JSXAttribute | JSXSpreadAttribute)[], local
136
135
 
137
136
  const key = attribute.name?.name;
138
137
 
139
- let value: string;
138
+ let value: string = "";
140
139
  if (!attribute.value) {
141
140
  value = "true";
142
141
  } else if (attribute.value.type === "Literal") {
@@ -163,8 +162,8 @@ function emitAttributes(attributes: (JSXAttribute | JSXSpreadAttribute)[], local
163
162
  return `Object.assign({}, ${parts.join(", ")})`;
164
163
  }
165
164
 
166
- function emitJsxChildren(children: JSXNode[], localFunctions: Set<string>): string[] {
167
- const result: string[] = [];
165
+ function emitJsxChildren(children: Array<JSXNode>, localFunctions: Set<string>): Array<string> {
166
+ const result: Array<string> = [];
168
167
 
169
168
  for (const child of children) {
170
169
  if (isJsxText(child)) {
@@ -195,7 +194,7 @@ function emitExpression(node: CompilableExpression, localFunctions: Set<string>)
195
194
  case "Identifier":
196
195
  return node.name;
197
196
  case "TemplateLiteral": {
198
- const bits: string[] = [];
197
+ const bits: Array<string> = [];
199
198
  node.quasis.forEach((quasi, index) => {
200
199
  bits.push(JSON.stringify(quasi.value.cooked ?? ""));
201
200
  if (node.expressions.length > index) {
@@ -210,10 +209,7 @@ function emitExpression(node: CompilableExpression, localFunctions: Set<string>)
210
209
  return `${node.operator}${emitExpression(node.argument, localFunctions)}`;
211
210
  case "BinaryExpression":
212
211
  case "LogicalExpression":
213
- return `(${emitExpression(node.left, localFunctions)} ${node.operator} ${emitExpression(
214
- node.right,
215
- localFunctions
216
- )})`;
212
+ return `(${emitExpression(node.left, localFunctions)} ${node.operator} ${emitExpression(node.right, localFunctions)})`;
217
213
  case "ConditionalExpression":
218
214
  return `(${emitExpression(node.test, localFunctions)}?${emitExpression(
219
215
  node.consequent,
@@ -245,12 +241,9 @@ function emitExpression(node: CompilableExpression, localFunctions: Set<string>)
245
241
  }
246
242
  case "MemberExpression": {
247
243
  const obj = emitExpression(node.object, localFunctions);
248
- let prop: string;
249
- if (node.computed) {
250
- prop = `[${emitExpression(node.property, localFunctions)}]`;
251
- } else {
252
- prop = `.${getAstKeyString(node.property as Identifier | Literal)}`;
253
- }
244
+ const prop: string = node.computed
245
+ ? `[${emitExpression(node.property, localFunctions)}]`
246
+ : `.${getAstKeyString(node.property as Identifier | Literal)}`;
254
247
  return `${obj}${prop}`;
255
248
  }
256
249
  case "CallExpression": {
@@ -266,9 +259,7 @@ function emitExpression(node: CompilableExpression, localFunctions: Set<string>)
266
259
  return `${callee}(${args})`;
267
260
  }
268
261
  case "ArrowFunctionExpression": {
269
- const params = node.params
270
- .map((param) => emitExpression(param as CompilableExpression, localFunctions))
271
- .join(", ");
262
+ const params = node.params.map((param) => emitExpression(param as CompilableExpression, localFunctions)).join(", ");
272
263
  const body = emitExpression(node.body as CompilableExpression, localFunctions);
273
264
  return `(${params}) => ${body}`;
274
265
  }
@@ -327,13 +318,13 @@ function emitParam(param: Pattern, localFunctions: Set<string>): string {
327
318
  case "Identifier":
328
319
  return param.name;
329
320
  case "ObjectPattern": {
330
- const props = (param as any).properties.map((p: any) => {
321
+ const props = param.properties.map((p) => {
331
322
  if (p.type === "RestElement") {
332
323
  return `...${emitParam(p.argument, localFunctions)}`;
333
324
  }
334
325
  const key = (p.key as Identifier).name;
335
326
  if (p.value.type === "AssignmentPattern") {
336
- return `${key} = ${emitExpression(p.value.right as CompilableExpression, localFunctions)}`;
327
+ return `${key} = ${emitExpression(p.value.right, localFunctions)}`;
337
328
  }
338
329
  if (p.value !== p.key && p.value.type === "Identifier" && p.value.name !== key) {
339
330
  return `${key}: ${emitParam(p.value, localFunctions)}`;
@@ -343,12 +334,9 @@ function emitParam(param: Pattern, localFunctions: Set<string>): string {
343
334
  return `{ ${props.join(", ")} }`;
344
335
  }
345
336
  case "AssignmentPattern":
346
- return `${emitParam((param as any).left, localFunctions)} = ${emitExpression(
347
- (param as any).right as CompilableExpression,
348
- localFunctions
349
- )}`;
337
+ return `${emitParam(param.left, localFunctions)} = ${emitExpression(param.right, localFunctions)}`;
350
338
  case "RestElement":
351
- return `...${emitParam((param as any).argument, localFunctions)}`;
339
+ return `...${emitParam(param.argument, localFunctions)}`;
352
340
  default:
353
341
  throw CompilationError.fromNode(`Unsupported parameter: ${param.type}`, param);
354
342
  }