jsxpression 0.2.4 → 0.3.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 (61) hide show
  1. package/lib/analyze/analysis-error.d.ts.map +1 -1
  2. package/lib/analyze/analysis-error.js +3 -1
  3. package/lib/analyze/analysis-error.js.map +1 -1
  4. package/lib/analyze/analysis-report.d.ts +146 -5
  5. package/lib/analyze/analysis-report.d.ts.map +1 -1
  6. package/lib/analyze/analysis-report.js.map +1 -1
  7. package/lib/analyze/data/data-access.d.ts.map +1 -1
  8. package/lib/analyze/data/data-access.js +22 -15
  9. package/lib/analyze/data/data-access.js.map +1 -1
  10. package/lib/analyze/data/method-calls.js +1 -1
  11. package/lib/analyze/data/method-calls.js.map +1 -1
  12. package/lib/analyze/data/utils.d.ts.map +1 -1
  13. package/lib/analyze/data/utils.js +27 -22
  14. package/lib/analyze/data/utils.js.map +1 -1
  15. package/lib/analyze/jsx/element-attributes.js +2 -2
  16. package/lib/analyze/jsx/element-attributes.js.map +1 -1
  17. package/lib/analyze/jsx/element-children.js +1 -1
  18. package/lib/analyze/jsx/element-children.js.map +1 -1
  19. package/lib/analyze/jsx/element-tags.js +1 -1
  20. package/lib/analyze/jsx/element-tags.js.map +1 -1
  21. package/lib/analyze/security/call-expressions.js +1 -1
  22. package/lib/analyze/security/call-expressions.js.map +1 -1
  23. package/lib/analyze/security/identifiers.js +6 -8
  24. package/lib/analyze/security/identifiers.js.map +1 -1
  25. package/lib/analyze/utils.d.ts.map +1 -1
  26. package/lib/analyze/utils.js +3 -2
  27. package/lib/analyze/utils.js.map +1 -1
  28. package/lib/builtins.js +1 -1
  29. package/lib/builtins.js.map +1 -1
  30. package/lib/codegen/schema/data-types.js +3 -6
  31. package/lib/codegen/schema/data-types.js.map +1 -1
  32. package/lib/codegen/schema/function-types.js +1 -1
  33. package/lib/codegen/schema/function-types.js.map +1 -1
  34. package/lib/codegen/schema/utils.d.ts.map +1 -1
  35. package/lib/codegen/schema/utils.js +6 -5
  36. package/lib/codegen/schema/utils.js.map +1 -1
  37. package/lib/compile/compile.js +11 -7
  38. package/lib/compile/compile.js.map +1 -1
  39. package/lib/jsx.js +1 -1
  40. package/lib/jsx.js.map +1 -1
  41. package/lib/parse/parse.js.map +1 -1
  42. package/package.json +2 -2
  43. package/src/analyze/analysis-error.ts +3 -1
  44. package/src/analyze/analysis-report.ts +2 -2
  45. package/src/analyze/analyze.test.ts +9 -0
  46. package/src/analyze/data/data-access.ts +22 -15
  47. package/src/analyze/data/method-calls.ts +1 -1
  48. package/src/analyze/data/utils.ts +29 -32
  49. package/src/analyze/jsx/element-attributes.ts +2 -2
  50. package/src/analyze/jsx/element-children.ts +1 -1
  51. package/src/analyze/jsx/element-tags.ts +1 -1
  52. package/src/analyze/security/call-expressions.ts +1 -1
  53. package/src/analyze/security/identifiers.ts +6 -8
  54. package/src/analyze/utils.ts +8 -7
  55. package/src/builtins.ts +1 -1
  56. package/src/codegen/schema/data-types.ts +3 -6
  57. package/src/codegen/schema/function-types.ts +1 -1
  58. package/src/codegen/schema/utils.ts +6 -5
  59. package/src/compile/compile.ts +11 -7
  60. package/src/jsx.ts +7 -7
  61. package/src/parse/parse.ts +1 -1
@@ -18,10 +18,12 @@ export function mapSchemaTypeToTypeScript(prop: PropertySchema, depth: number =
18
18
  }
19
19
  return "boolean";
20
20
  case "array": {
21
+ // oxlint-disable-next-line typescript/no-unnecessary-condition -- defensive check kept for Schema values that bypass zod deserialization (e.g. hand-constructed by consumers of this package) and so may not actually carry `shape`
21
22
  const itemType = prop.shape ? mapSchemaTypeToTypeScript(prop.shape, depth) : "any";
22
23
  return `${itemType}[]`;
23
24
  }
24
25
  case "object": {
26
+ // oxlint-disable-next-line typescript/no-unnecessary-condition -- defensive check kept for Schema values that bypass zod deserialization (e.g. hand-constructed by consumers of this package) and so may not actually carry `shape`
25
27
  if (prop.shape && typeof prop.shape === "object") {
26
28
  return generateObjectTypeWithJSDoc(prop.shape, depth);
27
29
  }
@@ -33,7 +35,7 @@ export function mapSchemaTypeToTypeScript(prop: PropertySchema, depth: number =
33
35
  return "object";
34
36
  }
35
37
  case "record": {
36
- const valueType = prop.shape ? mapSchemaTypeToTypeScript(prop.shape) : "any";
38
+ const valueType = mapSchemaTypeToTypeScript(prop.shape);
37
39
  return `Record<string, ${valueType}>`;
38
40
  }
39
41
  case "function":
@@ -74,22 +76,21 @@ export function generatePropertyJSDoc(_propertyName: string, propertySchema: Pro
74
76
  }
75
77
 
76
78
  // Add @property tags for nested object properties (recursive!)
77
- let hasNestedProperties = false;
79
+ // oxlint-disable-next-line typescript/no-unnecessary-condition -- defensive check kept for Schema values that bypass zod deserialization and so may not actually carry `shape`
78
80
  if (propertySchema.type === "object" && propertySchema.shape) {
79
81
  comments.push("");
80
82
  Object.entries(propertySchema.shape).forEach(([key, value]) => {
81
83
  if (value.description) {
82
84
  comments.push(`@property ${key} ${value.description}`);
83
- hasNestedProperties = true;
84
85
  }
85
86
  });
87
+ // oxlint-disable-next-line typescript/no-unnecessary-condition -- defensive check kept for Schema values that bypass zod deserialization and so may not actually carry `shape`
86
88
  } else if (propertySchema.type === "array" && propertySchema.shape.type === "object" && propertySchema.shape.shape) {
87
89
  // For arrays of objects, document the object structure
88
90
  comments.push("");
89
91
  Object.entries(propertySchema.shape.shape).forEach(([key, value]) => {
90
92
  if (value.description) {
91
93
  comments.push(`@property ${key} ${value.description}`);
92
- hasNestedProperties = true;
93
94
  }
94
95
  });
95
96
  }
@@ -100,7 +101,7 @@ export function generatePropertyJSDoc(_propertyName: string, propertySchema: Pro
100
101
  }
101
102
 
102
103
  // Single-line JSDoc
103
- if (comments.length === 1 && !hasNestedProperties) {
104
+ if (comments.length === 1) {
104
105
  return `${indent}/** ${comments[0]} */\n`;
105
106
  }
106
107
 
@@ -34,7 +34,7 @@ type CompilableExpression = Expression | PrivateIdentifier | Super | JSXElement
34
34
  export function compile(ast: Program): string {
35
35
  const localFunctions = new Set<string>();
36
36
  for (const stmt of ast.body) {
37
- if (stmt.type === "FunctionDeclaration" && stmt.id) {
37
+ if (stmt.type === "FunctionDeclaration") {
38
38
  localFunctions.add(stmt.id.name);
39
39
  }
40
40
  }
@@ -54,7 +54,7 @@ export function compile(ast: Program): string {
54
54
  parts.push(`return ${emitJsxRoot(statement.expression, localFunctions)};`);
55
55
  } else if (!hasDeclarations && statement.type === "BlockStatement" && statement.body.length === 1) {
56
56
  const innerStatement = statement.body[0];
57
- if (innerStatement.type === "ExpressionStatement") {
57
+ if (innerStatement?.type === "ExpressionStatement") {
58
58
  const syntheticContainer = {
59
59
  type: "JSXExpressionContainer" as const,
60
60
  expression: innerStatement.expression as CompilableExpression,
@@ -129,17 +129,19 @@ function emitAttributes(attributes: Array<JSXAttribute | JSXSpreadAttribute>, lo
129
129
  continue;
130
130
  }
131
131
 
132
+ // oxlint-disable-next-line typescript/no-unnecessary-condition -- attribute is only asserted (not runtime-validated) as JSXAttribute; acorn-typescript's real JSX grammar can still produce other AST shapes here
132
133
  if (attribute.type !== "JSXAttribute") {
133
134
  throw CompilationError.fromNode("Only simple JSX attributes allowed", attribute);
134
135
  }
135
136
 
136
- const key = attribute.name?.name;
137
+ const key = attribute.name.name;
137
138
 
138
139
  let value: string = "";
139
140
  if (!attribute.value) {
140
141
  value = "true";
141
142
  } else if (attribute.value.type === "Literal") {
142
143
  value = JSON.stringify(attribute.value.value);
144
+ // oxlint-disable-next-line typescript/no-unnecessary-condition -- attribute.value is only asserted (not runtime-validated) as JSXAttributeValue; the real grammar can still produce other expression container contents here
143
145
  } else if (attribute.value.type === "JSXExpressionContainer") {
144
146
  value = emitExpression(attribute.value.expression, localFunctions);
145
147
  } else {
@@ -156,7 +158,7 @@ function emitAttributes(attributes: Array<JSXAttribute | JSXSpreadAttribute>, lo
156
158
  }
157
159
 
158
160
  if (parts.length === 1) {
159
- return parts[0];
161
+ return parts[0] ?? "null";
160
162
  }
161
163
 
162
164
  return `Object.assign({}, ${parts.join(", ")})`;
@@ -197,8 +199,9 @@ function emitExpression(node: CompilableExpression, localFunctions: Set<string>)
197
199
  const bits: Array<string> = [];
198
200
  node.quasis.forEach((quasi, index) => {
199
201
  bits.push(JSON.stringify(quasi.value.cooked ?? ""));
200
- if (node.expressions.length > index) {
201
- bits.push(`+(${emitExpression(node.expressions[index], localFunctions)})+`);
202
+ const expression = node.expressions[index];
203
+ if (expression !== undefined) {
204
+ bits.push(`+(${emitExpression(expression, localFunctions)})+`);
202
205
  }
203
206
  });
204
207
  return bits.join("").replace(TRAILING_PLUS_RX, "") || '""';
@@ -272,7 +275,7 @@ function emitExpression(node: CompilableExpression, localFunctions: Set<string>)
272
275
  case "JSXEmptyExpression":
273
276
  return "null";
274
277
  default:
275
- throw CompilationError.fromNode(`Unsupported expression: ${node?.type}`, node);
278
+ throw CompilationError.fromNode(`Unsupported expression: ${node.type}`, node);
276
279
  }
277
280
  }
278
281
 
@@ -347,6 +350,7 @@ function emitParam(param: Pattern, localFunctions: Set<string>): string {
347
350
  function getAstKeyString(node: Identifier | Literal): string {
348
351
  if (node.type === "Identifier") {
349
352
  return node.name;
353
+ // oxlint-disable-next-line typescript/no-unnecessary-condition -- node is only asserted (not runtime-validated) as Identifier | Literal at the call sites; the real ESTree key/property type is broader
350
354
  } else if (node.type === "Literal") {
351
355
  return JSON.stringify(node.value);
352
356
  } else {
package/src/jsx.ts CHANGED
@@ -98,11 +98,11 @@ export type JSXNodeWithChildren = JSXElement | JSXFragment;
98
98
  export type JSXLeafNode = JSXText | JSXEmptyExpression;
99
99
 
100
100
  export function isJsxElement(value: unknown): value is JSXElement {
101
- return (value as JSXElement)?.type === "JSXElement";
101
+ return (value as JSXElement | null | undefined)?.type === "JSXElement";
102
102
  }
103
103
 
104
104
  export function isJsxFragment(value: unknown): value is JSXFragment {
105
- return (value as JSXFragment)?.type === "JSXFragment";
105
+ return (value as JSXFragment | null | undefined)?.type === "JSXFragment";
106
106
  }
107
107
 
108
108
  export function isJsxRoot(value: unknown): value is JSXRoot {
@@ -110,21 +110,21 @@ export function isJsxRoot(value: unknown): value is JSXRoot {
110
110
  }
111
111
 
112
112
  export function isJsxAttribute(value: unknown): value is JSXAttribute {
113
- return (value as JSXAttribute)?.type === "JSXAttribute";
113
+ return (value as JSXAttribute | null | undefined)?.type === "JSXAttribute";
114
114
  }
115
115
 
116
116
  export function isJsxExpressionContainer(value: unknown): value is JSXExpressionContainer {
117
- return (value as JSXExpressionContainer)?.type === "JSXExpressionContainer";
117
+ return (value as JSXExpressionContainer | null | undefined)?.type === "JSXExpressionContainer";
118
118
  }
119
119
 
120
120
  export function isJsxEmptyExpression(value: unknown): value is JSXEmptyExpression {
121
- return (value as JSXEmptyExpression)?.type === "JSXEmptyExpression";
121
+ return (value as JSXEmptyExpression | null | undefined)?.type === "JSXEmptyExpression";
122
122
  }
123
123
 
124
124
  export function isJsxText(value: unknown): value is JSXText {
125
- return (value as JSXText)?.type === "JSXText";
125
+ return (value as JSXText | null | undefined)?.type === "JSXText";
126
126
  }
127
127
 
128
128
  export function isJsxLeafNode(value: JSXNode): value is JSXLeafNode {
129
- return (value as JSXText)?.type === "JSXText" || isJsxEmptyExpression(value);
129
+ return value.type === "JSXText" || isJsxEmptyExpression(value);
130
130
  }
@@ -30,7 +30,7 @@ export function parse(source: string): Program {
30
30
  const ACORN_LOCATION_SUFFIX_RX = /\s+\(\d+:\d+\)$/;
31
31
 
32
32
  function isAcornError(error: unknown): error is AcornError {
33
- return error instanceof Error && (error as AcornError).loc !== undefined;
33
+ return error instanceof Error && (error as Partial<AcornError>).loc !== undefined;
34
34
  }
35
35
 
36
36
  type AcornError = Error & {