@component-compass/ast-utils 0.0.0-pr-3-8916f3c-20260507145532

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/README.md ADDED
@@ -0,0 +1,8 @@
1
+ # @component-compass/ast-utils
2
+
3
+ Shared AST utility functions used by component-compass parsers and manifest plugins.
4
+
5
+ - `parse5-guards` — type guards for parse5 element/text/document nodes.
6
+ - `babel-interop` — ESM/CJS shim that exposes `@babel/traverse`'s default export under our `verbatimModuleSyntax` + Node ESM resolution settings.
7
+
8
+ This is internal infrastructure for the component-compass packages. The API may evolve as parsers and manifest plugins evolve.
@@ -0,0 +1,2 @@
1
+ import type traverseType from "@babel/traverse";
2
+ export declare const traverse: typeof traverseType.default;
@@ -0,0 +1,15 @@
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
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,16 @@
1
+ export type ImportOrigin = {
2
+ type: "external";
3
+ package: string;
4
+ } | {
5
+ type: "local";
6
+ filePath: string;
7
+ } | {
8
+ type: "unresolved";
9
+ };
10
+ export type ClassifyOptions = {
11
+ /** Absolute path to the repo root. Used to compute repo-relative filePath. */
12
+ repoRoot: string;
13
+ /** Absolute path of the source file containing the import. */
14
+ fromFile: string;
15
+ };
16
+ export declare function classifyImportOrigin(specifier: string, opts: ClassifyOptions): ImportOrigin;
@@ -0,0 +1,79 @@
1
+ import { createRequire } from "node:module";
2
+ import { dirname, isAbsolute, relative, sep } from "node:path";
3
+ import { readFileSync, existsSync, realpathSync } from "node:fs";
4
+ import { posixPath } from "./posix.js";
5
+ export function classifyImportOrigin(specifier, opts) {
6
+ const resolved = tryResolve(specifier, opts.fromFile);
7
+ if (!resolved)
8
+ return { type: "unresolved" };
9
+ const nodeModulesIdx = resolved.lastIndexOf(`${sep}node_modules${sep}`);
10
+ if (nodeModulesIdx >= 0) {
11
+ const pkg = packageOf(resolved);
12
+ if (!pkg)
13
+ return { type: "unresolved" };
14
+ return { type: "external", package: pkg };
15
+ }
16
+ if (!isAbsolute(resolved))
17
+ return { type: "unresolved" };
18
+ // Normalise both sides to real paths so that symlinks (e.g. /var → /private/var
19
+ // on macOS) don't cause false "outside repo" negatives.
20
+ let repoRoot;
21
+ try {
22
+ repoRoot = realpathSync(opts.repoRoot);
23
+ }
24
+ catch {
25
+ repoRoot = opts.repoRoot;
26
+ }
27
+ let realResolved;
28
+ try {
29
+ realResolved = realpathSync(resolved);
30
+ }
31
+ catch {
32
+ realResolved = resolved;
33
+ }
34
+ const rel = relative(repoRoot, realResolved);
35
+ if (rel.startsWith("..") || isAbsolute(rel)) {
36
+ return { type: "unresolved" };
37
+ }
38
+ return { type: "local", filePath: posixPath(rel) };
39
+ }
40
+ const SOURCE_EXTENSIONS = [".tsx", ".ts", ".jsx", ".js", ".mjs", ".cjs"];
41
+ function tryResolve(specifier, fromFile) {
42
+ const require = createRequire(fromFile);
43
+ // First attempt: plain resolution (works for node_modules and files with known extensions).
44
+ try {
45
+ return require.resolve(specifier);
46
+ }
47
+ catch {
48
+ // Fall through to extension-probing for extensionless relative imports.
49
+ }
50
+ // Second attempt: probe TypeScript/JSX extensions that Node's require doesn't try by default.
51
+ for (const ext of SOURCE_EXTENSIONS) {
52
+ try {
53
+ return require.resolve(`${specifier}${ext}`);
54
+ }
55
+ catch {
56
+ // continue
57
+ }
58
+ }
59
+ return null;
60
+ }
61
+ function packageOf(absolute) {
62
+ let cursor = dirname(absolute);
63
+ while (cursor && cursor !== dirname(cursor)) {
64
+ const pkgJson = `${cursor}${sep}package.json`;
65
+ if (existsSync(pkgJson)) {
66
+ try {
67
+ const parsed = JSON.parse(readFileSync(pkgJson, "utf8"));
68
+ if (typeof parsed.name === "string" && parsed.name.length > 0)
69
+ return parsed.name;
70
+ }
71
+ catch {
72
+ return null;
73
+ }
74
+ }
75
+ cursor = dirname(cursor);
76
+ }
77
+ return null;
78
+ }
79
+ //# sourceMappingURL=classify-import.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classify-import.js","sourceRoot":"","sources":["../src/classify-import.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Narrow an unknown thrown value to a string for inclusion in a user-facing
3
+ * message. Prefer this over (e as Error).message — the value at a catch site
4
+ * is typed unknown precisely because thrown values aren't guaranteed Errors.
5
+ */
6
+ export declare function errorMessage(e: unknown): string;
7
+ /**
8
+ * Same idea for stack traces. Returns the stack if the value is an Error with
9
+ * one, otherwise falls back to errorMessage.
10
+ */
11
+ export declare function errorStack(e: unknown): string;
package/dist/errors.js ADDED
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Narrow an unknown thrown value to a string for inclusion in a user-facing
3
+ * message. Prefer this over (e as Error).message — the value at a catch site
4
+ * is typed unknown precisely because thrown values aren't guaranteed Errors.
5
+ */
6
+ export function errorMessage(e) {
7
+ if (e instanceof Error)
8
+ return e.message;
9
+ if (typeof e === "string")
10
+ return e;
11
+ try {
12
+ return JSON.stringify(e);
13
+ }
14
+ catch {
15
+ return String(e);
16
+ }
17
+ }
18
+ /**
19
+ * Same idea for stack traces. Returns the stack if the value is an Error with
20
+ * one, otherwise falls back to errorMessage.
21
+ */
22
+ export function errorStack(e) {
23
+ if (e instanceof Error && e.stack)
24
+ return e.stack;
25
+ return errorMessage(e);
26
+ }
27
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,CAAU;IACrC,IAAI,CAAC,YAAY,KAAK;QAAE,OAAO,CAAC,CAAC,OAAO,CAAC;IACzC,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC;IACpC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,CAAU;IACnC,IAAI,CAAC,YAAY,KAAK,IAAI,CAAC,CAAC,KAAK;QAAE,OAAO,CAAC,CAAC,KAAK,CAAC;IAClD,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC;AACzB,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { isElement, hasChildren } from "./parse5-guards.js";
2
+ export { traverse } from "./babel-interop.js";
3
+ export { posixPath } from "./posix.js";
4
+ export { errorMessage, errorStack } from "./errors.js";
5
+ export { classifyImportOrigin } from "./classify-import.js";
6
+ export type { ImportOrigin, ClassifyOptions } from "./classify-import.js";
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { isElement, hasChildren } from "./parse5-guards.js";
2
+ export { traverse } from "./babel-interop.js";
3
+ export { posixPath } from "./posix.js";
4
+ export { errorMessage, errorStack } from "./errors.js";
5
+ export { classifyImportOrigin } from "./classify-import.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,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"}
@@ -0,0 +1,10 @@
1
+ import type { DefaultTreeAdapterMap } from "parse5";
2
+ type Node = DefaultTreeAdapterMap["node"];
3
+ type Element = DefaultTreeAdapterMap["element"];
4
+ /** parse5 element nodes carry a `tagName`; text/document/doctype nodes don't. */
5
+ export declare function isElement(n: Node): n is Element;
6
+ /** parse5 element/document/document-fragment nodes carry `childNodes`. */
7
+ export declare function hasChildren(n: Node): n is Node & {
8
+ childNodes: Node[];
9
+ };
10
+ export {};
@@ -0,0 +1,11 @@
1
+ /** parse5 element nodes carry a `tagName`; text/document/doctype nodes don't. */
2
+ export function isElement(n) {
3
+ return "tagName" in n;
4
+ }
5
+ /** parse5 element/document/document-fragment nodes carry `childNodes`. */
6
+ export function hasChildren(n) {
7
+ if (!("childNodes" in n))
8
+ return false;
9
+ return Array.isArray(n.childNodes);
10
+ }
11
+ //# sourceMappingURL=parse5-guards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse5-guards.js","sourceRoot":"","sources":["../src/parse5-guards.ts"],"names":[],"mappings":"AAQA,iFAAiF;AACjF,MAAM,UAAU,SAAS,CAAC,CAAO;IAC/B,OAAO,SAAS,IAAI,CAAC,CAAC;AACxB,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,WAAW,CAAC,CAAO;IACjC,IAAI,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACvC,OAAO,KAAK,CAAC,OAAO,CAAE,CAA6B,CAAC,UAAU,CAAC,CAAC;AAClE,CAAC"}
@@ -0,0 +1,2 @@
1
+ /** Normalises backslashes to forward slashes for cross-platform path output. */
2
+ export declare function posixPath(p: string): string;
package/dist/posix.js ADDED
@@ -0,0 +1,5 @@
1
+ /** Normalises backslashes to forward slashes for cross-platform path output. */
2
+ export function posixPath(p) {
3
+ return p.replaceAll("\\", "/");
4
+ }
5
+ //# sourceMappingURL=posix.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"posix.js","sourceRoot":"","sources":["../src/posix.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,MAAM,UAAU,SAAS,CAAC,CAAS;IACjC,OAAO,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AACjC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@component-compass/ast-utils",
3
+ "version": "0.0.0-pr-3-8916f3c-20260507145532",
4
+ "description": "Shared AST utilities for component-compass parsers and manifest plugins. Internal infrastructure.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "files": [
10
+ "dist",
11
+ "README.md"
12
+ ],
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.js"
17
+ }
18
+ },
19
+ "scripts": {
20
+ "build": "tsc -p tsconfig.json",
21
+ "test": "vitest run --passWithNoTests",
22
+ "typecheck": "tsc --noEmit",
23
+ "lint": "biome lint src",
24
+ "clean": "rm -rf dist .turbo"
25
+ },
26
+ "dependencies": {
27
+ "@babel/traverse": "^7.29.0",
28
+ "parse5": "^8.0.0"
29
+ },
30
+ "devDependencies": {
31
+ "@types/babel__traverse": "^7.28.0",
32
+ "@types/node": "^24.0.0",
33
+ "typescript": "^5.9.0",
34
+ "vitest": "^4.0.0"
35
+ },
36
+ "engines": {
37
+ "node": ">=24"
38
+ },
39
+ "publishConfig": {
40
+ "access": "public"
41
+ }
42
+ }