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.
- package/lib/analyze/analysis-error.d.ts.map +1 -1
- package/lib/analyze/analysis-error.js +3 -1
- package/lib/analyze/analysis-error.js.map +1 -1
- package/lib/analyze/analysis-report.d.ts +146 -5
- package/lib/analyze/analysis-report.d.ts.map +1 -1
- package/lib/analyze/analysis-report.js.map +1 -1
- package/lib/analyze/data/data-access.d.ts.map +1 -1
- package/lib/analyze/data/data-access.js +22 -15
- package/lib/analyze/data/data-access.js.map +1 -1
- package/lib/analyze/data/method-calls.js +1 -1
- package/lib/analyze/data/method-calls.js.map +1 -1
- package/lib/analyze/data/utils.d.ts.map +1 -1
- package/lib/analyze/data/utils.js +27 -22
- package/lib/analyze/data/utils.js.map +1 -1
- package/lib/analyze/jsx/element-attributes.js +2 -2
- package/lib/analyze/jsx/element-attributes.js.map +1 -1
- package/lib/analyze/jsx/element-children.js +1 -1
- package/lib/analyze/jsx/element-children.js.map +1 -1
- package/lib/analyze/jsx/element-tags.js +1 -1
- package/lib/analyze/jsx/element-tags.js.map +1 -1
- package/lib/analyze/security/call-expressions.js +1 -1
- package/lib/analyze/security/call-expressions.js.map +1 -1
- package/lib/analyze/security/identifiers.js +6 -8
- package/lib/analyze/security/identifiers.js.map +1 -1
- package/lib/analyze/utils.d.ts.map +1 -1
- package/lib/analyze/utils.js +3 -2
- package/lib/analyze/utils.js.map +1 -1
- package/lib/builtins.js +1 -1
- package/lib/builtins.js.map +1 -1
- package/lib/codegen/schema/data-types.js +3 -6
- package/lib/codegen/schema/data-types.js.map +1 -1
- package/lib/codegen/schema/function-types.js +1 -1
- package/lib/codegen/schema/function-types.js.map +1 -1
- package/lib/codegen/schema/utils.d.ts.map +1 -1
- package/lib/codegen/schema/utils.js +6 -5
- package/lib/codegen/schema/utils.js.map +1 -1
- package/lib/compile/compile.js +11 -7
- package/lib/compile/compile.js.map +1 -1
- package/lib/jsx.js +1 -1
- package/lib/jsx.js.map +1 -1
- package/lib/parse/parse.js.map +1 -1
- package/package.json +2 -2
- package/src/analyze/analysis-error.ts +3 -1
- package/src/analyze/analysis-report.ts +2 -2
- package/src/analyze/analyze.test.ts +9 -0
- package/src/analyze/data/data-access.ts +22 -15
- package/src/analyze/data/method-calls.ts +1 -1
- package/src/analyze/data/utils.ts +29 -32
- package/src/analyze/jsx/element-attributes.ts +2 -2
- package/src/analyze/jsx/element-children.ts +1 -1
- package/src/analyze/jsx/element-tags.ts +1 -1
- package/src/analyze/security/call-expressions.ts +1 -1
- package/src/analyze/security/identifiers.ts +6 -8
- package/src/analyze/utils.ts +8 -7
- package/src/builtins.ts +1 -1
- package/src/codegen/schema/data-types.ts +3 -6
- package/src/codegen/schema/function-types.ts +1 -1
- package/src/codegen/schema/utils.ts +6 -5
- package/src/compile/compile.ts +11 -7
- package/src/jsx.ts +7 -7
- 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 =
|
|
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
|
-
|
|
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
|
|
104
|
+
if (comments.length === 1) {
|
|
104
105
|
return `${indent}/** ${comments[0]} */\n`;
|
|
105
106
|
}
|
|
106
107
|
|
package/src/compile/compile.ts
CHANGED
|
@@ -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"
|
|
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
|
|
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
|
|
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
|
-
|
|
201
|
-
|
|
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
|
|
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
|
|
129
|
+
return value.type === "JSXText" || isJsxEmptyExpression(value);
|
|
130
130
|
}
|
package/src/parse/parse.ts
CHANGED
|
@@ -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 & {
|