@component-compass/ast-utils 0.0.2 → 0.0.4
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/dist/find-owner.d.ts +52 -0
- package/dist/find-owner.js +156 -0
- package/dist/find-owner.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/oxc-helpers.d.ts +41 -0
- package/dist/oxc-helpers.js +77 -0
- package/dist/oxc-helpers.js.map +1 -0
- package/package.json +4 -3
- package/dist/babel-interop.d.ts +0 -2
- package/dist/babel-interop.js +0 -15
- package/dist/babel-interop.js.map +0 -1
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Walk an oxc/ESTree program from `program` down to `target`, returning the
|
|
3
|
+
* nearest enclosing component binding.
|
|
4
|
+
*
|
|
5
|
+
* A "component binding" is a function or class declaration / variable
|
|
6
|
+
* declarator whose binding name is PascalCase, OR an anonymous `export default`.
|
|
7
|
+
*
|
|
8
|
+
* HOC wrappers (`memo`, `forwardRef`, `observer`, `React.memo`, `React.forwardRef`)
|
|
9
|
+
* are unwrapped: the binding name comes from the enclosing variable declarator,
|
|
10
|
+
* not the call expression.
|
|
11
|
+
*
|
|
12
|
+
* Returns `null` when no enclosing tracked component is found before reaching
|
|
13
|
+
* module scope (e.g. JSX at module top-level).
|
|
14
|
+
*
|
|
15
|
+
* Algorithm: walk top-down through `program`, maintaining two parallel stacks
|
|
16
|
+
* of currently-entered nodes: `pathStack` (every node) and `frameStack` (just
|
|
17
|
+
* the candidate owners — Function/Arrow/Class declarations or expressions).
|
|
18
|
+
* When the `target` node is entered, scan `frameStack` from innermost outward
|
|
19
|
+
* and return the first frame whose contextual binding satisfies the rules:
|
|
20
|
+
* PascalCase id, predicate (if any), default-export special case, HOC
|
|
21
|
+
* unwrapping. Pop both stacks in `leave`.
|
|
22
|
+
*
|
|
23
|
+
* `loc` is always returned as `null` — oxc-parser only emits byte offsets,
|
|
24
|
+
* and the sole current consumer (parser-react/walk-jsx.ts) reads only
|
|
25
|
+
* `binding.name`. If a future caller needs a line/column, thread the source
|
|
26
|
+
* string through and call `positionAt` from `./oxc-helpers.ts`.
|
|
27
|
+
*/
|
|
28
|
+
import type { Node as OxcNode, Program } from "@oxc-project/types";
|
|
29
|
+
export type EnclosingComponentBinding = {
|
|
30
|
+
/** Binding name; `"default"` for anonymous default exports. */
|
|
31
|
+
name: string;
|
|
32
|
+
/** True for `export default ...` cases. */
|
|
33
|
+
isDefault: boolean;
|
|
34
|
+
/** Declaration site — always null (oxc-parser emits byte offsets only). */
|
|
35
|
+
loc: {
|
|
36
|
+
line: number;
|
|
37
|
+
column: number;
|
|
38
|
+
} | null;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Optional predicate supplied by the caller. When provided, a candidate
|
|
42
|
+
* binding is only returned if `isKnownComponent(name)` returns true; otherwise
|
|
43
|
+
* the walk continues upward. When omitted, any PascalCase binding (or
|
|
44
|
+
* anonymous `export default`) is accepted.
|
|
45
|
+
*/
|
|
46
|
+
export type IsKnownComponent = (name: string) => boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Walk an oxc/ESTree program from `program` down to `target`, returning the
|
|
49
|
+
* nearest enclosing component binding. The `target` must be a node within
|
|
50
|
+
* `program`. Reference equality is used to detect arrival.
|
|
51
|
+
*/
|
|
52
|
+
export declare function findEnclosingComponentBinding(target: OxcNode, program: Program, isKnownComponent?: IsKnownComponent): EnclosingComponentBinding | null;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { walk } from "oxc-walker";
|
|
2
|
+
const HOC_NAMES = new Set(["memo", "forwardRef", "observer"]);
|
|
3
|
+
/**
|
|
4
|
+
* Walk an oxc/ESTree program from `program` down to `target`, returning the
|
|
5
|
+
* nearest enclosing component binding. The `target` must be a node within
|
|
6
|
+
* `program`. Reference equality is used to detect arrival.
|
|
7
|
+
*/
|
|
8
|
+
export function findEnclosingComponentBinding(target, program, isKnownComponent) {
|
|
9
|
+
const pathStack = [];
|
|
10
|
+
// Frames hold the candidate node plus the pathStack depth at which it was
|
|
11
|
+
// pushed, so binding-evaluation can look up parents/grandparents at scan
|
|
12
|
+
// time without re-discovering them.
|
|
13
|
+
const frameStack = [];
|
|
14
|
+
let result = null;
|
|
15
|
+
let done = false;
|
|
16
|
+
walk(program, {
|
|
17
|
+
enter(node) {
|
|
18
|
+
if (done) {
|
|
19
|
+
this.skip?.();
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
pathStack.push(node);
|
|
23
|
+
// Arrival check — must happen BEFORE pushing the target's own frame, so
|
|
24
|
+
// a candidate-shaped target (e.g. an ArrowFunctionExpression passed in
|
|
25
|
+
// by a caller) is not considered its own owner.
|
|
26
|
+
if (node === target) {
|
|
27
|
+
result = scanFrameStack(frameStack, pathStack, isKnownComponent);
|
|
28
|
+
done = true;
|
|
29
|
+
this.skip?.();
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (isOwnerCandidateNode(node)) {
|
|
33
|
+
frameStack.push({ node, depth: pathStack.length - 1 });
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
leave(node) {
|
|
37
|
+
// Pop frameStack first (it is a subset of pathStack frames).
|
|
38
|
+
const top = frameStack[frameStack.length - 1];
|
|
39
|
+
if (top && top.node === node)
|
|
40
|
+
frameStack.pop();
|
|
41
|
+
pathStack.pop();
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
function isOwnerCandidateNode(node) {
|
|
47
|
+
return (node.type === "FunctionDeclaration" ||
|
|
48
|
+
node.type === "FunctionExpression" ||
|
|
49
|
+
node.type === "ArrowFunctionExpression" ||
|
|
50
|
+
node.type === "ClassDeclaration" ||
|
|
51
|
+
node.type === "ClassExpression");
|
|
52
|
+
}
|
|
53
|
+
function scanFrameStack(frameStack, pathStack, isKnownComponent) {
|
|
54
|
+
for (let i = frameStack.length - 1; i >= 0; i--) {
|
|
55
|
+
const frame = frameStack[i];
|
|
56
|
+
if (!frame)
|
|
57
|
+
continue;
|
|
58
|
+
const parent = pathStack[frame.depth - 1] ?? null;
|
|
59
|
+
const grand = pathStack[frame.depth - 2] ?? null;
|
|
60
|
+
const binding = bindingForOxcFrame(frame.node, parent, grand, isKnownComponent);
|
|
61
|
+
if (binding)
|
|
62
|
+
return binding;
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
function bindingForOxcFrame(node, parent, grand, isKnownComponent) {
|
|
67
|
+
// class Name { … } / class Name extends Base { … }
|
|
68
|
+
if (node.type === "ClassDeclaration" || node.type === "ClassExpression") {
|
|
69
|
+
const cls = node;
|
|
70
|
+
const id = cls.id;
|
|
71
|
+
if (id && isPascalCase(id.name)) {
|
|
72
|
+
if (!isKnownComponent || isKnownComponent(id.name)) {
|
|
73
|
+
return { name: id.name, isDefault: false, loc: null };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (parent?.type === "ExportDefaultDeclaration") {
|
|
77
|
+
if (!isKnownComponent || isKnownComponent("default")) {
|
|
78
|
+
return { name: "default", isDefault: true, loc: null };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
// function Name() { … }
|
|
84
|
+
if (node.type === "FunctionDeclaration") {
|
|
85
|
+
const fn = node;
|
|
86
|
+
const id = fn.id;
|
|
87
|
+
if (parent?.type === "ExportDefaultDeclaration") {
|
|
88
|
+
const name = id && isPascalCase(id.name) ? id.name : "default";
|
|
89
|
+
if (!isKnownComponent || isKnownComponent(name)) {
|
|
90
|
+
return { name, isDefault: true, loc: null };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (id && isPascalCase(id.name)) {
|
|
94
|
+
if (!isKnownComponent || isKnownComponent(id.name)) {
|
|
95
|
+
return { name: id.name, isDefault: false, loc: null };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
// (...) => … / function () { … } (anonymous), examined by its context.
|
|
101
|
+
if (node.type === "ArrowFunctionExpression" || node.type === "FunctionExpression") {
|
|
102
|
+
return bindingFromAnonymousFunctionParent(parent, grand, isKnownComponent);
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
function bindingFromAnonymousFunctionParent(parent, grand, isKnownComponent) {
|
|
107
|
+
if (!parent)
|
|
108
|
+
return null;
|
|
109
|
+
if (parent.type === "VariableDeclarator" && parent.id.type === "Identifier") {
|
|
110
|
+
return bindingFromVariableId(parent.id.name, isKnownComponent);
|
|
111
|
+
}
|
|
112
|
+
if (parent.type === "CallExpression" && isHocCall(parent)) {
|
|
113
|
+
if (!grand)
|
|
114
|
+
return null;
|
|
115
|
+
if (grand.type === "VariableDeclarator" && grand.id.type === "Identifier") {
|
|
116
|
+
return bindingFromVariableId(grand.id.name, isKnownComponent);
|
|
117
|
+
}
|
|
118
|
+
if (grand.type === "ExportDefaultDeclaration") {
|
|
119
|
+
if (!isKnownComponent || isKnownComponent("default")) {
|
|
120
|
+
return { name: "default", isDefault: true, loc: null };
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
if (parent.type === "ExportDefaultDeclaration") {
|
|
126
|
+
if (!isKnownComponent || isKnownComponent("default")) {
|
|
127
|
+
return { name: "default", isDefault: true, loc: null };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
function bindingFromVariableId(name, isKnownComponent) {
|
|
133
|
+
if (!isPascalCase(name))
|
|
134
|
+
return null;
|
|
135
|
+
if (isKnownComponent && !isKnownComponent(name))
|
|
136
|
+
return null;
|
|
137
|
+
return { name, isDefault: false, loc: null };
|
|
138
|
+
}
|
|
139
|
+
function isHocCall(call) {
|
|
140
|
+
if (call.type !== "CallExpression")
|
|
141
|
+
return false;
|
|
142
|
+
const callee = call.callee;
|
|
143
|
+
if (callee.type === "Identifier")
|
|
144
|
+
return HOC_NAMES.has(callee.name);
|
|
145
|
+
if (callee.type === "MemberExpression" &&
|
|
146
|
+
callee.object.type === "Identifier" &&
|
|
147
|
+
callee.object.name === "React" &&
|
|
148
|
+
callee.property.type === "Identifier") {
|
|
149
|
+
return HOC_NAMES.has(callee.property.name);
|
|
150
|
+
}
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
function isPascalCase(name) {
|
|
154
|
+
return /^[A-Z]/.test(name);
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=find-owner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-owner.js","sourceRoot":"","sources":["../src/find-owner.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export { isElement, hasChildren } from "./parse5-guards.js";
|
|
2
|
-
export { traverse } from "./babel-interop.js";
|
|
3
2
|
export { posixPath } from "./posix.js";
|
|
4
3
|
export { errorMessage, errorStack } from "./errors.js";
|
|
5
4
|
export { classifyImportOrigin } from "./classify-import.js";
|
|
6
5
|
export type { ImportOrigin, ClassifyOptions } from "./classify-import.js";
|
|
6
|
+
export { findEnclosingComponentBinding } from "./find-owner.js";
|
|
7
|
+
export type { EnclosingComponentBinding } from "./find-owner.js";
|
|
8
|
+
export { positionAt, getJSXName, isJSXElement, isJSXFragment, isJSXAttribute, isJSXSpreadAttribute, isCallExpression, isImportDeclaration, } from "./oxc-helpers.js";
|
|
9
|
+
export type { Position } from "./oxc-helpers.js";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { isElement, hasChildren } from "./parse5-guards.js";
|
|
2
|
-
export { traverse } from "./babel-interop.js";
|
|
3
2
|
export { posixPath } from "./posix.js";
|
|
4
3
|
export { errorMessage, errorStack } from "./errors.js";
|
|
5
4
|
export { classifyImportOrigin } from "./classify-import.js";
|
|
5
|
+
export { findEnclosingComponentBinding } from "./find-owner.js";
|
|
6
|
+
export { positionAt, getJSXName, isJSXElement, isJSXFragment, isJSXAttribute, isJSXSpreadAttribute, isCallExpression, isImportDeclaration, } from "./oxc-helpers.js";
|
|
6
7
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE5D,OAAO,EAAE,6BAA6B,EAAE,MAAM,iBAAiB,CAAC;AAEhE,OAAO,EACL,UAAU,EACV,UAAU,EACV,YAAY,EACZ,aAAa,EACb,cAAc,EACd,oBAAoB,EACpB,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for working with oxc-parser's ESTree-shaped AST. Used by every
|
|
3
|
+
* default-path plugin/detector after the Phase C migration.
|
|
4
|
+
*
|
|
5
|
+
* - `positionAt` — UTF-16 offset → { line, column } conversion (as emitted by oxc-parser)
|
|
6
|
+
* - `getJSXName` — JSXIdentifier | JSXMemberExpression | JSXNamespacedName → string
|
|
7
|
+
* - `is*` predicates — type-narrow ESTree nodes by `type` field
|
|
8
|
+
*
|
|
9
|
+
* Keep this module dependency-free except for @oxc-project/types (type-only
|
|
10
|
+
* at runtime). All helpers work against plain ESTree-shape objects.
|
|
11
|
+
*/
|
|
12
|
+
import type { CallExpression, ImportDeclaration, JSXElement, JSXFragment, JSXIdentifier, JSXMemberExpression, JSXNamespacedName, JSXAttribute, JSXSpreadAttribute } from "@oxc-project/types";
|
|
13
|
+
export type Position = {
|
|
14
|
+
line: number;
|
|
15
|
+
column: number;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Convert a UTF-16 code unit offset (as emitted by oxc-parser) into a
|
|
19
|
+
* 1-indexed line + 0-indexed column position. O(offset) — fine for emit-time
|
|
20
|
+
* use (called once per occurrence), avoid in tight walk loops. Cache by source
|
|
21
|
+
* if profile shows it matters.
|
|
22
|
+
*/
|
|
23
|
+
export declare function positionAt(source: string, offset: number): Position;
|
|
24
|
+
export declare function isJSXElement(node: unknown): node is JSXElement;
|
|
25
|
+
export declare function isJSXFragment(node: unknown): node is JSXFragment;
|
|
26
|
+
export declare function isJSXAttribute(node: unknown): node is JSXAttribute;
|
|
27
|
+
export declare function isJSXSpreadAttribute(node: unknown): node is JSXSpreadAttribute;
|
|
28
|
+
export declare function isCallExpression(node: unknown): node is CallExpression;
|
|
29
|
+
export declare function isImportDeclaration(node: unknown): node is ImportDeclaration;
|
|
30
|
+
type JSXName = JSXIdentifier | JSXMemberExpression | JSXNamespacedName;
|
|
31
|
+
/**
|
|
32
|
+
* Stringify a JSX element/attribute name node:
|
|
33
|
+
* <Foo /> → "Foo" (JSXIdentifier)
|
|
34
|
+
* <Foo.Bar /> → "Foo.Bar" (JSXMemberExpression)
|
|
35
|
+
* <svg:rect /> → "svg:rect" (JSXNamespacedName)
|
|
36
|
+
* <a.b.c /> → "a.b.c" (nested JSXMemberExpression)
|
|
37
|
+
*/
|
|
38
|
+
export declare function getJSXName(el: JSXElement | {
|
|
39
|
+
openingElement: JSXElement["openingElement"];
|
|
40
|
+
} | JSXName): string;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for working with oxc-parser's ESTree-shaped AST. Used by every
|
|
3
|
+
* default-path plugin/detector after the Phase C migration.
|
|
4
|
+
*
|
|
5
|
+
* - `positionAt` — UTF-16 offset → { line, column } conversion (as emitted by oxc-parser)
|
|
6
|
+
* - `getJSXName` — JSXIdentifier | JSXMemberExpression | JSXNamespacedName → string
|
|
7
|
+
* - `is*` predicates — type-narrow ESTree nodes by `type` field
|
|
8
|
+
*
|
|
9
|
+
* Keep this module dependency-free except for @oxc-project/types (type-only
|
|
10
|
+
* at runtime). All helpers work against plain ESTree-shape objects.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Convert a UTF-16 code unit offset (as emitted by oxc-parser) into a
|
|
14
|
+
* 1-indexed line + 0-indexed column position. O(offset) — fine for emit-time
|
|
15
|
+
* use (called once per occurrence), avoid in tight walk loops. Cache by source
|
|
16
|
+
* if profile shows it matters.
|
|
17
|
+
*/
|
|
18
|
+
export function positionAt(source, offset) {
|
|
19
|
+
let line = 1;
|
|
20
|
+
let column = 0;
|
|
21
|
+
for (let i = 0; i < offset && i < source.length; i++) {
|
|
22
|
+
if (source[i] === "\n") {
|
|
23
|
+
line++;
|
|
24
|
+
column = 0;
|
|
25
|
+
}
|
|
26
|
+
else if (source[i] === "\r") {
|
|
27
|
+
// \r\n counted via the next \n; lone \r increments line.
|
|
28
|
+
if (source[i + 1] !== "\n") {
|
|
29
|
+
line++;
|
|
30
|
+
column = 0;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
column++;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return { line, column };
|
|
38
|
+
}
|
|
39
|
+
export function isJSXElement(node) {
|
|
40
|
+
return node?.type === "JSXElement";
|
|
41
|
+
}
|
|
42
|
+
export function isJSXFragment(node) {
|
|
43
|
+
return node?.type === "JSXFragment";
|
|
44
|
+
}
|
|
45
|
+
export function isJSXAttribute(node) {
|
|
46
|
+
return node?.type === "JSXAttribute";
|
|
47
|
+
}
|
|
48
|
+
export function isJSXSpreadAttribute(node) {
|
|
49
|
+
return node?.type === "JSXSpreadAttribute";
|
|
50
|
+
}
|
|
51
|
+
export function isCallExpression(node) {
|
|
52
|
+
return node?.type === "CallExpression";
|
|
53
|
+
}
|
|
54
|
+
export function isImportDeclaration(node) {
|
|
55
|
+
return node?.type === "ImportDeclaration";
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Stringify a JSX element/attribute name node:
|
|
59
|
+
* <Foo /> → "Foo" (JSXIdentifier)
|
|
60
|
+
* <Foo.Bar /> → "Foo.Bar" (JSXMemberExpression)
|
|
61
|
+
* <svg:rect /> → "svg:rect" (JSXNamespacedName)
|
|
62
|
+
* <a.b.c /> → "a.b.c" (nested JSXMemberExpression)
|
|
63
|
+
*/
|
|
64
|
+
export function getJSXName(el) {
|
|
65
|
+
const name = "openingElement" in el ? el.openingElement.name : el;
|
|
66
|
+
return stringifyJSXName(name);
|
|
67
|
+
}
|
|
68
|
+
function stringifyJSXName(name) {
|
|
69
|
+
if (name.type === "JSXIdentifier")
|
|
70
|
+
return name.name;
|
|
71
|
+
if (name.type === "JSXNamespacedName") {
|
|
72
|
+
return `${name.namespace.name}:${name.name.name}`;
|
|
73
|
+
}
|
|
74
|
+
// JSXMemberExpression — may be nested
|
|
75
|
+
return `${stringifyJSXName(name.object)}.${name.property.name}`;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=oxc-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oxc-helpers.js","sourceRoot":"","sources":["../src/oxc-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAiBH;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,MAAc,EAAE,MAAc;IACvD,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrD,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACvB,IAAI,EAAE,CAAC;YACP,MAAM,GAAG,CAAC,CAAC;QACb,CAAC;aAAM,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC9B,yDAAyD;YACzD,IAAI,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC3B,IAAI,EAAE,CAAC;gBACP,MAAM,GAAG,CAAC,CAAC;YACb,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,EAAE,CAAC;QACX,CAAC;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAa;IACxC,OAAQ,IAAa,EAAE,IAAI,KAAK,YAAY,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAa;IACzC,OAAQ,IAAa,EAAE,IAAI,KAAK,aAAa,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAa;IAC1C,OAAQ,IAAa,EAAE,IAAI,KAAK,cAAc,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAa;IAChD,OAAQ,IAAa,EAAE,IAAI,KAAK,oBAAoB,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAa;IAC5C,OAAQ,IAAa,EAAE,IAAI,KAAK,gBAAgB,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,IAAa;IAC/C,OAAQ,IAAa,EAAE,IAAI,KAAK,mBAAmB,CAAC;AACtD,CAAC;AAID;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CACxB,EAA2E;IAE3E,MAAM,IAAI,GAAG,gBAAgB,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAE,EAAc,CAAC;IAC/E,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAa;IACrC,IAAI,IAAI,CAAC,IAAI,KAAK,eAAe;QAAE,OAAO,IAAI,CAAC,IAAI,CAAC;IACpD,IAAI,IAAI,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;QACtC,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACpD,CAAC;IACD,sCAAsC;IACtC,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAC,MAAiB,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;AAC7E,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@component-compass/ast-utils",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Shared AST utilities for component-compass parsers and manifest plugins. Internal infrastructure.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -24,12 +24,13 @@
|
|
|
24
24
|
"clean": "rm -rf dist .turbo"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@
|
|
27
|
+
"@oxc-project/types": "^0.130.0",
|
|
28
|
+
"oxc-walker": "^1.0.0",
|
|
28
29
|
"parse5": "^8.0.0"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
|
31
|
-
"@types/babel__traverse": "^7.28.0",
|
|
32
32
|
"@types/node": "^24.0.0",
|
|
33
|
+
"oxc-parser": "^0.130.0",
|
|
33
34
|
"typescript": "^5.9.0",
|
|
34
35
|
"vitest": "^4.0.0"
|
|
35
36
|
},
|
package/dist/babel-interop.d.ts
DELETED
package/dist/babel-interop.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { createRequire } from "node:module";
|
|
2
|
-
/**
|
|
3
|
-
* @babel/traverse is a CJS-only package ("type": "commonjs"). Under our
|
|
4
|
-
* module: NodeNext setup, Node's CJS-from-ESM default-import interop puts
|
|
5
|
-
* module.exports itself on the default binding (not module.exports.default),
|
|
6
|
-
* so the bare `import traverse from "@babel/traverse"` shape used in the
|
|
7
|
-
* Babel docs fails at call time. Babel docs assume bundler/esModuleInterop
|
|
8
|
-
* context, which auto-unwraps default — Node-native ESM does not.
|
|
9
|
-
*
|
|
10
|
-
* createRequire is Node's official escape hatch for loading CJS from ESM.
|
|
11
|
-
* Vitest also implements it. No runtime branching needed.
|
|
12
|
-
*/
|
|
13
|
-
const require = createRequire(import.meta.url);
|
|
14
|
-
export const traverse = require("@babel/traverse").default;
|
|
15
|
-
//# sourceMappingURL=babel-interop.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"babel-interop.js","sourceRoot":"","sources":["../src/babel-interop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C;;;;;;;;;;GAUG;AACH,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,CAAC,MAAM,QAAQ,GAAgC,OAAO,CAAC,iBAAiB,CAAC,CAAC,OAAO,CAAC"}
|