jsxpression 0.1.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/LICENSE +21 -0
- package/README.md +368 -0
- package/lib/analyze/analysis-error.d.ts.map +1 -0
- package/lib/analyze/analysis-report.d.ts +33 -0
- package/lib/analyze/analysis-report.d.ts.map +1 -0
- package/lib/analyze/analysis-report.js +194 -0
- package/lib/analyze/analysis-report.js.map +1 -0
- package/lib/analyze/analyze.d.ts.map +1 -0
- package/lib/analyze/analyze.test.d.ts.map +1 -0
- package/lib/analyze/analyze.test.js +765 -0
- package/lib/analyze/analyze.test.js.map +1 -0
- package/lib/analyze/data/analyze.d.ts.map +1 -0
- package/lib/analyze/data/data-access.d.ts.map +1 -0
- package/lib/analyze/data/index.d.ts.map +1 -0
- package/lib/analyze/data/method-calls.d.ts.map +1 -0
- package/lib/analyze/data/utils.d.ts.map +1 -0
- package/lib/analyze/index.d.ts.map +1 -0
- package/lib/analyze/jsx/analyze.d.ts.map +1 -0
- package/lib/analyze/jsx/element-attributes.d.ts.map +1 -0
- package/lib/analyze/jsx/element-attributes.js +89 -0
- package/lib/analyze/jsx/element-attributes.js.map +1 -0
- package/lib/analyze/jsx/element-children.d.ts.map +1 -0
- package/lib/analyze/jsx/element-tags.d.ts.map +1 -0
- package/lib/analyze/jsx/index.d.ts.map +1 -0
- package/lib/analyze/security/analyze.d.ts.map +1 -0
- package/lib/analyze/security/call-expressions.d.ts.map +1 -0
- package/lib/analyze/security/declarations.d.ts.map +1 -0
- package/lib/analyze/security/expressions.d.ts.map +1 -0
- package/lib/analyze/security/identifiers.d.ts.map +1 -0
- package/lib/analyze/security/index.d.ts.map +1 -0
- package/lib/analyze/security/member-access.d.ts.map +1 -0
- package/lib/builtins.d.ts +50 -0
- package/lib/builtins.d.ts.map +1 -0
- package/lib/builtins.js +1065 -0
- package/lib/builtins.js.map +1 -0
- package/lib/codegen/builtin-types.d.ts +11 -0
- package/lib/codegen/builtin-types.d.ts.map +1 -0
- package/lib/codegen/builtin-types.js +151 -0
- package/lib/codegen/builtin-types.js.map +1 -0
- package/lib/codegen/builtins/builtin-types.d.ts +2 -0
- package/lib/codegen/builtins/builtin-types.d.ts.map +1 -0
- package/lib/codegen/builtins/builtin-types.js +143 -0
- package/lib/codegen/builtins/builtin-types.js.map +1 -0
- package/lib/codegen/builtins/index.d.ts +2 -0
- package/lib/codegen/builtins/index.d.ts.map +1 -0
- package/lib/codegen/builtins/index.js +6 -0
- package/lib/codegen/builtins/index.js.map +1 -0
- package/lib/codegen/declare-types.d.ts +20 -0
- package/lib/codegen/declare-types.d.ts.map +1 -0
- package/lib/codegen/declare-types.js +299 -0
- package/lib/codegen/declare-types.js.map +1 -0
- package/lib/codegen/generate-typescript-definitions.d.ts +31 -0
- package/lib/codegen/generate-typescript-definitions.d.ts.map +1 -0
- package/lib/codegen/generate-typescript-definitions.js +37 -0
- package/lib/codegen/generate-typescript-definitions.js.map +1 -0
- package/lib/codegen/generate-typescript-definitions.test.d.ts +2 -0
- package/lib/codegen/generate-typescript-definitions.test.d.ts.map +1 -0
- package/lib/codegen/generate-typescript-definitions.test.js +587 -0
- package/lib/codegen/generate-typescript-definitions.test.js.map +1 -0
- package/lib/codegen/index.d.ts +2 -0
- package/lib/codegen/index.d.ts.map +1 -0
- package/lib/codegen/index.js +6 -0
- package/lib/codegen/index.js.map +1 -0
- package/lib/codegen/schema/component-types.d.ts +3 -0
- package/lib/codegen/schema/component-types.d.ts.map +1 -0
- package/lib/codegen/schema/component-types.js +118 -0
- package/lib/codegen/schema/component-types.js.map +1 -0
- package/lib/codegen/schema/data-types.d.ts +3 -0
- package/lib/codegen/schema/data-types.d.ts.map +1 -0
- package/lib/codegen/schema/data-types.js +98 -0
- package/lib/codegen/schema/data-types.js.map +1 -0
- package/lib/codegen/schema/index.d.ts +3 -0
- package/lib/codegen/schema/index.d.ts.map +1 -0
- package/lib/codegen/schema/index.js +8 -0
- package/lib/codegen/schema/index.js.map +1 -0
- package/lib/codegen/schema/utils.d.ts +4 -0
- package/lib/codegen/schema/utils.d.ts.map +1 -0
- package/lib/codegen/schema/utils.js +103 -0
- package/lib/codegen/schema/utils.js.map +1 -0
- package/lib/codegen/schema-to-types.d.ts +14 -0
- package/lib/codegen/schema-to-types.d.ts.map +1 -0
- package/lib/codegen/schema-to-types.js +203 -0
- package/lib/codegen/schema-to-types.js.map +1 -0
- package/lib/compile/compile.d.ts.map +1 -0
- package/lib/compile/compile.js +245 -0
- package/lib/compile/compile.js.map +1 -0
- package/lib/compile/compile.test.d.ts.map +1 -0
- package/lib/compile/compile.test.js +148 -0
- package/lib/compile/compile.test.js.map +1 -0
- package/lib/evaluate/evaluate.d.ts +26 -0
- package/lib/evaluate/evaluate.d.ts.map +1 -0
- package/lib/evaluate/evaluate.js +40 -0
- package/lib/evaluate/evaluation-error.d.ts +4 -0
- package/lib/evaluate/evaluation-error.d.ts.map +1 -0
- package/lib/evaluate/evaluation-error.js +6 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +16 -0
- package/lib/index.js.map +1 -0
- package/lib/render.d.ts +58 -0
- package/lib/render.d.ts.map +1 -0
- package/lib/render.js +52 -0
- package/lib/render.test.d.ts.map +1 -0
- package/lib/schema.d.ts +68 -0
- package/lib/schema.d.ts.map +1 -0
- package/lib/schema.js +106 -0
- package/lib/validate.d.ts +41 -0
- package/lib/validate.d.ts.map +1 -0
- package/lib/validate.js +42 -0
- package/package.json +27 -0
- package/src/analyze/analysis-error.ts +26 -0
- package/src/analyze/analysis-report.ts +228 -0
- package/src/analyze/analyze.test.ts +829 -0
- package/src/analyze/analyze.ts +10 -0
- package/src/analyze/data/analyze.ts +15 -0
- package/src/analyze/data/data-access.ts +349 -0
- package/src/analyze/data/index.ts +1 -0
- package/src/analyze/data/method-calls.ts +96 -0
- package/src/analyze/data/utils.ts +329 -0
- package/src/analyze/index.ts +3 -0
- package/src/analyze/jsx/analyze.ts +17 -0
- package/src/analyze/jsx/element-attributes.ts +143 -0
- package/src/analyze/jsx/element-children.ts +97 -0
- package/src/analyze/jsx/element-tags.ts +55 -0
- package/src/analyze/jsx/index.ts +1 -0
- package/src/analyze/security/analyze.ts +21 -0
- package/src/analyze/security/call-expressions.ts +41 -0
- package/src/analyze/security/declarations.ts +67 -0
- package/src/analyze/security/expressions.ts +100 -0
- package/src/analyze/security/identifiers.ts +113 -0
- package/src/analyze/security/index.ts +1 -0
- package/src/analyze/security/member-access.ts +35 -0
- package/src/analyze/utils.ts +118 -0
- package/src/analyze/validation-context.ts +32 -0
- package/src/builtins.ts +1149 -0
- package/src/codegen/builtins/builtin-types.ts +174 -0
- package/src/codegen/builtins/index.ts +1 -0
- package/src/codegen/generate-typescript-definitions.test.ts +676 -0
- package/src/codegen/generate-typescript-definitions.ts +35 -0
- package/src/codegen/index.ts +1 -0
- package/src/codegen/schema/component-types.ts +140 -0
- package/src/codegen/schema/data-types.ts +109 -0
- package/src/codegen/schema/index.ts +2 -0
- package/src/codegen/schema/utils.ts +111 -0
- package/src/compile/compilation-error.ts +37 -0
- package/src/compile/compile.test.ts +180 -0
- package/src/compile/compile.ts +282 -0
- package/src/compile/index.ts +2 -0
- package/src/evaluate/evaluate.test.ts +316 -0
- package/src/evaluate/evaluate.ts +81 -0
- package/src/evaluate/evaluation-error.ts +6 -0
- package/src/evaluate/index.ts +2 -0
- package/src/index.ts +10 -0
- package/src/jsx.ts +161 -0
- package/src/parse/index.ts +2 -0
- package/src/parse/parse-error.ts +14 -0
- package/src/parse/parse.test.ts +99 -0
- package/src/parse/parse.ts +40 -0
- package/src/render.test.ts +425 -0
- package/src/render.ts +75 -0
- package/src/schema.ts +195 -0
- package/src/traverse.test.ts +104 -0
- package/src/traverse.ts +78 -0
- package/src/types.ts +17 -0
- package/src/validate.ts +59 -0
package/src/jsx.ts
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ArrayExpression,
|
|
3
|
+
ArrowFunctionExpression,
|
|
4
|
+
BinaryExpression,
|
|
5
|
+
CallExpression,
|
|
6
|
+
ConditionalExpression,
|
|
7
|
+
Identifier,
|
|
8
|
+
Literal,
|
|
9
|
+
LogicalExpression,
|
|
10
|
+
MemberExpression,
|
|
11
|
+
ObjectExpression,
|
|
12
|
+
UnaryExpression,
|
|
13
|
+
} from "acorn";
|
|
14
|
+
|
|
15
|
+
export type JSXStringLiteral = {
|
|
16
|
+
type: "Literal";
|
|
17
|
+
value: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type JSXNumberLiteral = {
|
|
21
|
+
type: "Literal";
|
|
22
|
+
value: number;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type JSXBooleanLiteral = {
|
|
26
|
+
type: "Literal";
|
|
27
|
+
value: boolean;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type JSXNullLiteral = {
|
|
31
|
+
type: "Literal";
|
|
32
|
+
value: null;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type JSXLiteral = JSXStringLiteral | JSXNumberLiteral | JSXBooleanLiteral | JSXNullLiteral;
|
|
36
|
+
|
|
37
|
+
export type JSXAttributeValue = JSXLiteral | JSXExpressionContainer;
|
|
38
|
+
|
|
39
|
+
export type JSXNameNode =
|
|
40
|
+
| { type: "JSXIdentifier"; name: string }
|
|
41
|
+
| { type: "JSXMemberExpression"; object: JSXNameNode; property: JSXNameNode };
|
|
42
|
+
|
|
43
|
+
export type JSXAttribute = {
|
|
44
|
+
type: "JSXAttribute";
|
|
45
|
+
name: {
|
|
46
|
+
name: string;
|
|
47
|
+
};
|
|
48
|
+
value?: JSXAttributeValue;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export type JSXSpreadAttribute = {
|
|
52
|
+
type: "JSXSpreadAttribute";
|
|
53
|
+
argument: JSXNode;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export type JSXOpeningElement = {
|
|
57
|
+
type: "JSXOpeningElement";
|
|
58
|
+
name: {
|
|
59
|
+
name: string;
|
|
60
|
+
};
|
|
61
|
+
attributes: (JSXAttribute | JSXSpreadAttribute)[];
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export type JSXClosingElement = {
|
|
65
|
+
type: "JSXClosingElement";
|
|
66
|
+
name: { name: string };
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export type JSXElement = {
|
|
70
|
+
type: "JSXElement";
|
|
71
|
+
openingElement: JSXOpeningElement;
|
|
72
|
+
closingElement?: JSXClosingElement;
|
|
73
|
+
children: JSXNode[];
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export type JSXFragment = {
|
|
77
|
+
type: "JSXFragment";
|
|
78
|
+
children: JSXNode[];
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export type JSXText = {
|
|
82
|
+
type: "JSXText";
|
|
83
|
+
value: string;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export type JSXEmptyExpression = {
|
|
87
|
+
type: "JSXEmptyExpression";
|
|
88
|
+
start: number;
|
|
89
|
+
end: number;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export type JSXExpression =
|
|
93
|
+
| ArrayExpression
|
|
94
|
+
| ArrowFunctionExpression
|
|
95
|
+
| BinaryExpression
|
|
96
|
+
| CallExpression
|
|
97
|
+
| ConditionalExpression
|
|
98
|
+
| Identifier
|
|
99
|
+
| JSXElement
|
|
100
|
+
| JSXFragment
|
|
101
|
+
| Literal
|
|
102
|
+
| LogicalExpression
|
|
103
|
+
| MemberExpression
|
|
104
|
+
| ObjectExpression
|
|
105
|
+
| UnaryExpression;
|
|
106
|
+
|
|
107
|
+
export type JSXExpressionContainer = {
|
|
108
|
+
type: "JSXExpressionContainer";
|
|
109
|
+
expression: JSXExpression | JSXEmptyExpression;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export type JSXNode = JSXElement | JSXFragment | JSXText | JSXEmptyExpression | JSXExpressionContainer;
|
|
113
|
+
|
|
114
|
+
export type JSXRoot = JSXElement | JSXFragment | JSXExpressionContainer;
|
|
115
|
+
|
|
116
|
+
export type JSXNodeWithChildren = JSXElement | JSXFragment;
|
|
117
|
+
export type JSXLeafNode = JSXText | JSXEmptyExpression;
|
|
118
|
+
|
|
119
|
+
export type JSXExpressionHost = JSXExpressionContainer;
|
|
120
|
+
|
|
121
|
+
export type GetAttributeValue<T extends JSXAttribute> = T["value"];
|
|
122
|
+
|
|
123
|
+
export function isJsxElement(value: unknown): value is JSXElement {
|
|
124
|
+
return (value as JSXElement)?.type === "JSXElement";
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function isJsxFragment(value: unknown): value is JSXFragment {
|
|
128
|
+
return (value as JSXFragment)?.type === "JSXFragment";
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function isJsxRoot(value: unknown): value is JSXRoot {
|
|
132
|
+
return isJsxElement(value) || isJsxFragment(value) || isJsxExpressionContainer(value);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function isJsxAttribute(value: unknown): value is JSXAttribute {
|
|
136
|
+
return (value as JSXAttribute)?.type === "JSXAttribute";
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function isJsxLiteral(value: unknown): value is JSXLiteral {
|
|
140
|
+
return (value as JSXLiteral)?.type === "Literal";
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function isJsxExpressionContainer(value: unknown): value is JSXExpressionContainer {
|
|
144
|
+
return (value as JSXExpressionContainer)?.type === "JSXExpressionContainer";
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function isJsxEmptyExpression(value: unknown): value is JSXEmptyExpression {
|
|
148
|
+
return (value as JSXEmptyExpression)?.type === "JSXEmptyExpression";
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function isJsxText(value: unknown): value is JSXText {
|
|
152
|
+
return (value as JSXText)?.type === "JSXText";
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function isJsxNodeWithChildren(value: JSXNode): value is JSXNodeWithChildren {
|
|
156
|
+
return isJsxElement(value) || isJsxFragment(value);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function isJsxLeafNode(value: JSXNode): value is JSXLeafNode {
|
|
160
|
+
return (value as JSXText)?.type === "JSXText" || isJsxEmptyExpression(value);
|
|
161
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { parse } from "./parse";
|
|
3
|
+
import { ParseError } from "./parse-error";
|
|
4
|
+
|
|
5
|
+
describe("parse", () => {
|
|
6
|
+
it("should parse valid JSX element", () => {
|
|
7
|
+
const result = parse("<Text x={10}>Hello</Text>");
|
|
8
|
+
|
|
9
|
+
expect(result.type).toBe("Program");
|
|
10
|
+
expect(result.body).toHaveLength(1);
|
|
11
|
+
expect(result.body[0].type).toBe("ExpressionStatement");
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should parse JSX fragment", () => {
|
|
15
|
+
const result = parse("<><Text>A</Text><Text>B</Text></>");
|
|
16
|
+
|
|
17
|
+
expect(result.type).toBe("Program");
|
|
18
|
+
expect(result.body[0].type).toBe("ExpressionStatement");
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("should throw ParseError with position for syntax error", () => {
|
|
22
|
+
expect(() => parse("<Text>Unclosed")).toThrow(ParseError);
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
parse("<Text>Unclosed");
|
|
26
|
+
} catch (error) {
|
|
27
|
+
expect(error).toBeInstanceOf(ParseError);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("should parse nested JSX", () => {
|
|
32
|
+
const result = parse("<Outer><Inner><Deep>Text</Deep></Inner></Outer>");
|
|
33
|
+
|
|
34
|
+
expect(result.type).toBe("Program");
|
|
35
|
+
expect(result.body[0].type).toBe("ExpressionStatement");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("should parse JSX with expressions", () => {
|
|
39
|
+
const result = parse("<Text>{props.value}</Text>");
|
|
40
|
+
|
|
41
|
+
expect(result.type).toBe("Program");
|
|
42
|
+
expect(result.body[0].type).toBe("ExpressionStatement");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("should parse JSX with complex expressions", () => {
|
|
46
|
+
const result = parse("<Text>{data.items.map(x => x * 2).join(', ')}</Text>");
|
|
47
|
+
|
|
48
|
+
expect(result.type).toBe("Program");
|
|
49
|
+
expect(result.body[0].type).toBe("ExpressionStatement");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("should parse JSX with attributes", () => {
|
|
53
|
+
const result = parse('<Text x={10} y="hello" z={data.value}>Content</Text>');
|
|
54
|
+
|
|
55
|
+
expect(result.type).toBe("Program");
|
|
56
|
+
expect(result.body[0].type).toBe("ExpressionStatement");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("should parse self-closing JSX elements", () => {
|
|
60
|
+
const result = parse("<Input value={data.name} />");
|
|
61
|
+
|
|
62
|
+
expect(result.type).toBe("Program");
|
|
63
|
+
expect(result.body[0].type).toBe("ExpressionStatement");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should parse JSX with conditional expressions", () => {
|
|
67
|
+
const result = parse("<Text>{data.show ? 'visible' : 'hidden'}</Text>");
|
|
68
|
+
|
|
69
|
+
expect(result.type).toBe("Program");
|
|
70
|
+
expect(result.body[0].type).toBe("ExpressionStatement");
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("should parse empty JSX expressions", () => {
|
|
74
|
+
const result = parse("<Text>{}</Text>");
|
|
75
|
+
|
|
76
|
+
expect(result.type).toBe("Program");
|
|
77
|
+
expect(result.body[0].type).toBe("ExpressionStatement");
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
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
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("should handle invalid JSX syntax", () => {
|
|
95
|
+
expect(() => parse("<>")).toThrow(ParseError);
|
|
96
|
+
expect(() => parse("<Text><")).toThrow(ParseError);
|
|
97
|
+
expect(() => parse("<Text attr>")).toThrow(ParseError);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Parser, type Program } from "acorn";
|
|
2
|
+
import jsx from "acorn-jsx";
|
|
3
|
+
import { ParseError } from "./parse-error";
|
|
4
|
+
|
|
5
|
+
const JSXParser = Parser.extend(jsx());
|
|
6
|
+
|
|
7
|
+
export function parse(source: string): Program {
|
|
8
|
+
try {
|
|
9
|
+
return JSXParser.parse(source, {
|
|
10
|
+
ecmaVersion: "latest",
|
|
11
|
+
sourceType: "module",
|
|
12
|
+
locations: true,
|
|
13
|
+
allowReturnOutsideFunction: true,
|
|
14
|
+
});
|
|
15
|
+
} catch (error: unknown) {
|
|
16
|
+
// Acorn throws syntax errors with location info when parsing fails.
|
|
17
|
+
// We steal this info and pass it to our own ParseError.
|
|
18
|
+
if (isAcornError(error)) {
|
|
19
|
+
// Remove location (the line:column part) from message if present
|
|
20
|
+
const message = error.message.replace(ACORN_LOCATION_SUFFIX_RX, "");
|
|
21
|
+
|
|
22
|
+
throw new ParseError(message, error.loc);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
throw new ParseError(error instanceof Error ? error.message : "Parsing failed");
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const ACORN_LOCATION_SUFFIX_RX = /\s+\(\d+:\d+\)$/;
|
|
30
|
+
|
|
31
|
+
function isAcornError(error: unknown): error is AcornError {
|
|
32
|
+
return error instanceof Error && (error as AcornError).loc !== undefined;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
type AcornError = Error & {
|
|
36
|
+
loc: {
|
|
37
|
+
line: number;
|
|
38
|
+
column: number;
|
|
39
|
+
};
|
|
40
|
+
};
|