@component-compass/ast-utils 0.0.4 → 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.
@@ -1,3 +1,4 @@
1
+ import type { ResolveImport } from "@component-compass/plugin-core";
1
2
  export type ImportOrigin = {
2
3
  type: "external";
3
4
  package: string;
@@ -8,9 +9,25 @@ export type ImportOrigin = {
8
9
  type: "unresolved";
9
10
  };
10
11
  export type ClassifyOptions = {
11
- /** Absolute path to the repo root. Used to compute repo-relative filePath. */
12
12
  repoRoot: string;
13
- /** Absolute path of the source file containing the import. */
14
13
  fromFile: string;
14
+ /**
15
+ * The shared `ResolveImport` from `cli/walker/resolve-import.ts`. Handles
16
+ * config aliases, tsconfig `paths`, and Node resolution in one layered
17
+ * pass. Required — there is no internal fallback.
18
+ */
19
+ resolveImport: ResolveImport;
20
+ /**
21
+ * Names of packages known to belong to the scan's repo — workspace
22
+ * siblings (`workspaceGraph.packages[*].name`) plus declared deps from the
23
+ * root and workspace `package.json` files. When the resolver returns null,
24
+ * the specifier's package portion is matched against this set; a hit
25
+ * recovers external-package identity instead of marking the import
26
+ * unresolved. Necessary for yarn/pnpm workspaces where siblings live under
27
+ * `packages/*` but aren't symlinked into the root `node_modules`. Specs
28
+ * that don't parse to a known package name (e.g. `~/foo`, `@/x`) stay
29
+ * unresolved.
30
+ */
31
+ knownPackageNames?: ReadonlySet<string>;
15
32
  };
16
33
  export declare function classifyImportOrigin(specifier: string, opts: ClassifyOptions): ImportOrigin;
@@ -1,11 +1,15 @@
1
- import { createRequire } from "node:module";
2
- import { dirname, isAbsolute, relative, sep } from "node:path";
1
+ import { isAbsolute, relative, sep, dirname } from "node:path";
3
2
  import { readFileSync, existsSync, realpathSync } from "node:fs";
4
3
  import { posixPath } from "./posix.js";
5
4
  export function classifyImportOrigin(specifier, opts) {
6
- const resolved = tryResolve(specifier, opts.fromFile);
7
- if (!resolved)
5
+ const resolved = opts.resolveImport(opts.fromFile, specifier);
6
+ if (!resolved) {
7
+ const pkg = packageNameFromSpecifier(specifier);
8
+ if (pkg && opts.knownPackageNames?.has(pkg)) {
9
+ return { type: "external", package: pkg };
10
+ }
8
11
  return { type: "unresolved" };
12
+ }
9
13
  const nodeModulesIdx = resolved.lastIndexOf(`${sep}node_modules${sep}`);
10
14
  if (nodeModulesIdx >= 0) {
11
15
  const pkg = packageOf(resolved);
@@ -15,8 +19,6 @@ export function classifyImportOrigin(specifier, opts) {
15
19
  }
16
20
  if (!isAbsolute(resolved))
17
21
  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
22
  let repoRoot;
21
23
  try {
22
24
  repoRoot = realpathSync(opts.repoRoot);
@@ -37,26 +39,29 @@ export function classifyImportOrigin(specifier, opts) {
37
39
  }
38
40
  return { type: "local", filePath: posixPath(rel) };
39
41
  }
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.
42
+ /**
43
+ * Parse a module specifier into its package-name portion. Returns null for
44
+ * specifiers that aren't shaped like a package import (relative paths,
45
+ * tsconfig/alias prefixes like `~/x`, `@/x`, `#x`, absolute paths).
46
+ * - `@scope/name` → `@scope/name`
47
+ * - `@scope/name/sub/path` → `@scope/name`
48
+ * - `lodash` → `lodash`
49
+ * - `lodash/fp/flow` → `lodash`
50
+ * - `./x`, `../x`, `/x` → null
51
+ * - `~/x`, `@/x`, `#alias` → null (scoped form requires `@scope/name`)
52
+ */
53
+ function packageNameFromSpecifier(specifier) {
54
+ if (specifier.startsWith("@")) {
55
+ const slash1 = specifier.indexOf("/");
56
+ if (slash1 < 0)
57
+ return null;
58
+ const slash2 = specifier.indexOf("/", slash1 + 1);
59
+ return slash2 < 0 ? specifier : specifier.slice(0, slash2);
49
60
  }
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;
61
+ if (!/^[a-zA-Z]/.test(specifier))
62
+ return null;
63
+ const slash = specifier.indexOf("/");
64
+ return slash < 0 ? specifier : specifier.slice(0, slash);
60
65
  }
61
66
  function packageOf(absolute) {
62
67
  let cursor = dirname(absolute);
@@ -1 +1 @@
1
- {"version":3,"file":"classify-import.js","sourceRoot":"","sources":["../src/classify-import.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"classify-import.js","sourceRoot":"","sources":["../src/classify-import.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Helpers for working with oxc-parser's ESTree-shaped AST. Used by every
3
- * default-path plugin/detector after the Phase C migration.
3
+ * default-path plugin/detector.
4
4
  *
5
5
  * - `positionAt` — UTF-16 offset → { line, column } conversion (as emitted by oxc-parser)
6
6
  * - `getJSXName` — JSXIdentifier | JSXMemberExpression | JSXNamespacedName → string
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Helpers for working with oxc-parser's ESTree-shaped AST. Used by every
3
- * default-path plugin/detector after the Phase C migration.
3
+ * default-path plugin/detector.
4
4
  *
5
5
  * - `positionAt` — UTF-16 offset → { line, column } conversion (as emitted by oxc-parser)
6
6
  * - `getJSXName` — JSXIdentifier | JSXMemberExpression | JSXNamespacedName → string
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@component-compass/ast-utils",
3
- "version": "0.0.4",
3
+ "version": "0.1.0",
4
4
  "description": "Shared AST utilities for component-compass parsers and manifest plugins. Internal infrastructure.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -24,15 +24,16 @@
24
24
  "clean": "rm -rf dist .turbo"
25
25
  },
26
26
  "dependencies": {
27
- "@oxc-project/types": "^0.130.0",
28
- "oxc-walker": "^1.0.0",
29
- "parse5": "^8.0.0"
27
+ "@component-compass/plugin-core": "0.1.0",
28
+ "@oxc-project/types": "0.130.0",
29
+ "oxc-walker": "1.0.0",
30
+ "parse5": "8.0.1"
30
31
  },
31
32
  "devDependencies": {
32
- "@types/node": "^24.0.0",
33
- "oxc-parser": "^0.130.0",
34
- "typescript": "^5.9.0",
35
- "vitest": "^4.0.0"
33
+ "@types/node": "24.12.2",
34
+ "oxc-parser": "0.130.0",
35
+ "typescript": "5.9.3",
36
+ "vitest": "4.1.5"
36
37
  },
37
38
  "engines": {
38
39
  "node": ">=24"