@component-compass/cli 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.
Files changed (112) hide show
  1. package/dist/cli.js +5 -1
  2. package/dist/cli.js.map +1 -1
  3. package/dist/commands/init.js +1 -3
  4. package/dist/commands/init.js.map +1 -1
  5. package/dist/commands/scan.d.ts +13 -1
  6. package/dist/commands/scan.js +192 -72
  7. package/dist/commands/scan.js.map +1 -1
  8. package/dist/composition-rollup.d.ts +16 -14
  9. package/dist/composition-rollup.js +33 -43
  10. package/dist/composition-rollup.js.map +1 -1
  11. package/dist/config/loader.js +5 -9
  12. package/dist/config/loader.js.map +1 -1
  13. package/dist/config/schema.d.ts +2 -15
  14. package/dist/config/schema.js.map +1 -1
  15. package/dist/envelope/index.d.ts +0 -9
  16. package/dist/envelope/index.js +1 -46
  17. package/dist/envelope/index.js.map +1 -1
  18. package/dist/identity.d.ts +19 -17
  19. package/dist/identity.js +42 -21
  20. package/dist/identity.js.map +1 -1
  21. package/dist/index.d.ts +2 -0
  22. package/dist/index.js +1 -0
  23. package/dist/index.js.map +1 -1
  24. package/dist/local-index/detect-react.d.ts +2 -1
  25. package/dist/local-index/detect-react.js +269 -72
  26. package/dist/local-index/detect-react.js.map +1 -1
  27. package/dist/local-index/detect-vue.d.ts +15 -1
  28. package/dist/local-index/detect-vue.js +130 -107
  29. package/dist/local-index/detect-vue.js.map +1 -1
  30. package/dist/local-index/detect-wc.d.ts +7 -1
  31. package/dist/local-index/detect-wc.js +56 -60
  32. package/dist/local-index/detect-wc.js.map +1 -1
  33. package/dist/local-index/index.d.ts +12 -4
  34. package/dist/local-index/index.js +40 -25
  35. package/dist/local-index/index.js.map +1 -1
  36. package/dist/manifest/barrel-parser.d.ts +10 -0
  37. package/dist/manifest/barrel-parser.js +11 -0
  38. package/dist/manifest/barrel-parser.js.map +1 -1
  39. package/dist/manifest/derived-manifest-stub.d.ts +16 -7
  40. package/dist/manifest/derived-manifest-stub.js +43 -7
  41. package/dist/manifest/derived-manifest-stub.js.map +1 -1
  42. package/dist/manifest/lazy-resolver.d.ts +52 -34
  43. package/dist/manifest/lazy-resolver.js +269 -69
  44. package/dist/manifest/lazy-resolver.js.map +1 -1
  45. package/dist/occurrences.d.ts +4 -4
  46. package/dist/occurrences.js +49 -9
  47. package/dist/occurrences.js.map +1 -1
  48. package/dist/parse-by-ext.d.ts +21 -0
  49. package/dist/parse-by-ext.js +53 -0
  50. package/dist/parse-by-ext.js.map +1 -0
  51. package/dist/reporter/index.d.ts +27 -28
  52. package/dist/reporter/index.js +99 -58
  53. package/dist/reporter/index.js.map +1 -1
  54. package/dist/reporter/stdout.js +4 -4
  55. package/dist/reporter/stdout.js.map +1 -1
  56. package/dist/rollup.d.ts +13 -6
  57. package/dist/rollup.js +9 -6
  58. package/dist/rollup.js.map +1 -1
  59. package/dist/scan/cem-index.d.ts +38 -0
  60. package/dist/scan/cem-index.js +139 -0
  61. package/dist/scan/cem-index.js.map +1 -0
  62. package/dist/scan/git-mtime.d.ts +2 -0
  63. package/dist/scan/git-mtime.js +22 -0
  64. package/dist/scan/git-mtime.js.map +1 -0
  65. package/dist/scan/meta.d.ts +5 -0
  66. package/dist/scan/meta.js +58 -0
  67. package/dist/scan/meta.js.map +1 -0
  68. package/dist/scan/stamp-deprecated.d.ts +16 -0
  69. package/dist/scan/stamp-deprecated.js +33 -0
  70. package/dist/scan/stamp-deprecated.js.map +1 -0
  71. package/dist/scan/stamp-version.d.ts +18 -0
  72. package/dist/scan/stamp-version.js +94 -0
  73. package/dist/scan/stamp-version.js.map +1 -0
  74. package/dist/seeds.d.ts +20 -19
  75. package/dist/seeds.js +136 -68
  76. package/dist/seeds.js.map +1 -1
  77. package/dist/types.d.ts +2 -5
  78. package/dist/util/git.d.ts +8 -0
  79. package/dist/util/git.js +73 -0
  80. package/dist/util/git.js.map +1 -1
  81. package/dist/util/progress.d.ts +21 -0
  82. package/dist/util/progress.js +54 -0
  83. package/dist/util/progress.js.map +1 -0
  84. package/dist/walker/files.d.ts +1 -0
  85. package/dist/walker/files.js +11 -5
  86. package/dist/walker/files.js.map +1 -1
  87. package/dist/workspace/build-graph.d.ts +2 -0
  88. package/dist/workspace/build-graph.js +117 -0
  89. package/dist/workspace/build-graph.js.map +1 -0
  90. package/dist/workspace/declared-deps.d.ts +5 -0
  91. package/dist/workspace/declared-deps.js +42 -0
  92. package/dist/workspace/declared-deps.js.map +1 -0
  93. package/dist/workspace/find-owning-package.d.ts +8 -0
  94. package/dist/workspace/find-owning-package.js +69 -0
  95. package/dist/workspace/find-owning-package.js.map +1 -0
  96. package/dist/workspace/index.d.ts +4 -0
  97. package/dist/workspace/index.js +4 -0
  98. package/dist/workspace/index.js.map +1 -0
  99. package/dist/workspace/types.d.ts +46 -0
  100. package/dist/workspace/types.js +13 -0
  101. package/dist/workspace/types.js.map +1 -0
  102. package/package.json +15 -7
  103. package/schema/config.schema.json +2 -24
  104. package/dist/config/tag-rules.d.ts +0 -2
  105. package/dist/config/tag-rules.js +0 -34
  106. package/dist/config/tag-rules.js.map +0 -1
  107. package/dist/local-index/walker.d.ts +0 -11
  108. package/dist/local-index/walker.js +0 -47
  109. package/dist/local-index/walker.js.map +0 -1
  110. package/dist/manifest/diagnostic-filter.d.ts +0 -12
  111. package/dist/manifest/diagnostic-filter.js +0 -23
  112. package/dist/manifest/diagnostic-filter.js.map +0 -1
package/dist/seeds.js CHANGED
@@ -1,13 +1,12 @@
1
1
  /**
2
- * Builds per-component seeds from a resolver-emitted snapshot,
3
- * parser-emitted occurrences, and the workspace tag rules. Seeds are the
4
- * per-component input to `rollupOccurrencesToComponents`: they carry
5
- * identity, derivedTags, and manifest enrichment but no occurrence data
6
- * (that is merged separately during rollup).
2
+ * Builds per-component seeds from a resolver-emitted snapshot and
3
+ * parser-emitted occurrences. Seeds are the per-component input to
4
+ * `rollupOccurrencesToComponents`: they carry identity and manifest enrichment
5
+ * but no occurrence data (that is merged separately during rollup).
7
6
  *
8
7
  * Pure function; no I/O.
9
8
  */
10
- import { evaluateTagRules } from "./config/tag-rules.js";
9
+ import { relative, isAbsolute } from "node:path";
11
10
  import { manifestComponentToOutput } from "./reporter/index.js";
12
11
  import { computeOutputIdentity, computeStableId, computeStableIdFromComponentId, } from "./identity.js";
13
12
  /**
@@ -15,61 +14,152 @@ import { computeOutputIdentity, computeStableId, computeStableIdFromComponentId,
15
14
  * ComponentSeeds.
16
15
  *
17
16
  * Two sources contribute:
18
- * 1. Snapshotted componentsfull enrichment via `manifestComponentToOutput`,
19
- * labelled with the snapshot entry's `enrichmentSource`.
20
- * 2. Components observed in parser walks but absent from the snapshot —
21
- * emitted with `manifest: null` so they surface in `components[]` per
22
- * the realignment principle ("manifest is enrichment, not gate").
17
+ * 1. Components observed in parser walks carry `modulePath` from the
18
+ * resolver and surface with `manifest: null` initially.
19
+ * 2. Snapshotted components full enrichment via `manifestComponentToOutput`,
20
+ * labelled with the snapshot entry's `enrichmentSource`. Snapshot entries
21
+ * have NO `modulePath` (manifests don't carry that info), so their stable
22
+ * id differs from the parser-emitted seed for the same logical component.
23
+ * To avoid emitting a ghost component, we attach the snapshot's manifest
24
+ * enrichment to a matching parser-emitted seed when the match is
25
+ * unambiguous (exactly one parser seed with `{kind, packageName,
26
+ * exportName-or-tagName}`). Ambiguous matches fall through to a
27
+ * snapshot-only seed.
23
28
  *
24
- * Dedupe by stable id; snapshotted seeds win.
25
- *
26
- * Scope derivation follows the three-lane model in identity.ts:
27
- * - local → source.type === "local"
28
- * - ds → external + derivedTags.length > 0
29
- * - external → external + no matching tag rules
29
+ * Scope derivation: "local" for source.type === "local"; "external" otherwise.
30
+ * DS-grouping is the web app's responsibility — CC emits two scopes only.
30
31
  */
31
- export function buildComponentSeeds(snapshot, parseResults, tagRules) {
32
+ export function buildComponentSeeds(snapshot, parseResults, localIndex, repoRoot, workspaceGraph) {
32
33
  const seedsById = new Map();
33
- // 1. Resolver-snapshotted components first (so they win on dedupe).
34
+ // 1. Parser-emitted components first. These carry `modulePath` for
35
+ // resolver-driven externals and are the ones occurrences hash against.
36
+ for (const result of parseResults) {
37
+ for (const occ of result.occurrences) {
38
+ // Normalise local filePaths: parsers emit absolute paths; the local index
39
+ // uses repo-root-relative POSIX paths. Relativise here so the stable id
40
+ // matches the one produced for seeds built from the local index.
41
+ const componentId = repoRoot && occ.componentId.source.type === "local" && isAbsolute(occ.componentId.source.filePath)
42
+ ? {
43
+ ...occ.componentId,
44
+ source: {
45
+ type: "local",
46
+ filePath: relative(repoRoot, occ.componentId.source.filePath).replace(/\\/g, "/"),
47
+ },
48
+ }
49
+ : occ.componentId;
50
+ const id = computeStableIdFromComponentId(componentId);
51
+ if (seedsById.has(id))
52
+ continue;
53
+ const isLocal = componentId.source.type === "local";
54
+ let definitionLoc;
55
+ if (isLocal && localIndex) {
56
+ let match;
57
+ if (componentId.kind === "custom-element") {
58
+ match = localIndex.byTag.get(componentId.tagName);
59
+ }
60
+ else {
61
+ const path = componentId.source.type === "local" ? componentId.source.filePath : "";
62
+ const defs = localIndex.byPath.get(path) ?? [];
63
+ const exportName = componentId.export;
64
+ match = defs.find((d) => d.exportName === exportName);
65
+ }
66
+ if (match?.loc) {
67
+ definitionLoc = { line: match.loc.line, column: match.loc.column };
68
+ }
69
+ }
70
+ const identity = computeOutputIdentity({
71
+ componentId,
72
+ repoId: "",
73
+ ...(workspaceGraph !== undefined ? { workspaceGraph } : {}),
74
+ ...(definitionLoc !== undefined ? { definitionLoc } : {}),
75
+ });
76
+ seedsById.set(id, { id, identity, manifest: null, deprecated: false });
77
+ }
78
+ }
79
+ // 2. Snapshotted components. Snapshot entries lack `modulePath`, so their
80
+ // stable id won't collide with the parser-emitted seed even when they
81
+ // describe the same logical component. Instead of hashing, look up by
82
+ // `{kind, packageName, exportName-or-tagName}` and attach the manifest
83
+ // enrichment to that parser seed. Only merge when exactly one parser
84
+ // seed matches — multiple matches (e.g. two subpaths both exporting
85
+ // `default`) are ambiguous, so fall through to a snapshot-only seed.
34
86
  for (const entry of snapshot) {
35
87
  const componentId = indexedToComponentId(entry.component);
36
- const packageName = entry.component.source.type === "external"
37
- ? entry.component.source.package
38
- : null;
39
- const derivedTags = evaluateTagRules(packageName, tagRules);
40
- const via = defaultVia(entry.component);
88
+ const manifest = manifestComponentToOutput(entry.component, entry.enrichmentSource);
89
+ const mergeTarget = findUnambiguousMergeTarget(seedsById, componentId);
90
+ if (mergeTarget !== null) {
91
+ mergeTarget.manifest = manifest;
92
+ mergeTarget.deprecated = false;
93
+ continue;
94
+ }
41
95
  const identity = computeOutputIdentity({
42
96
  componentId,
43
- via,
44
- derivedTags,
45
97
  repoId: "",
98
+ ...(workspaceGraph !== undefined ? { workspaceGraph } : {}),
46
99
  });
47
100
  const id = computeStableId(identity);
48
- const manifest = manifestComponentToOutput(entry.component, entry.enrichmentSource);
49
- seedsById.set(id, { id, identity, derivedTags, manifest });
101
+ if (seedsById.has(id))
102
+ continue;
103
+ seedsById.set(id, { id, identity, manifest, deprecated: false });
50
104
  }
51
- // 2. Components observed in parser walks but not yet seeded.
52
- // Emitted with manifest: null per the realignment principle.
53
- for (const result of parseResults) {
54
- for (const occ of result.occurrences) {
55
- const id = computeStableIdFromComponentId(occ.componentId);
56
- if (seedsById.has(id))
57
- continue;
58
- const packageName = occ.componentId.source.type === "external"
59
- ? occ.componentId.source.package
60
- : null;
61
- const derivedTags = evaluateTagRules(packageName, tagRules);
62
- const identity = computeOutputIdentity({
63
- componentId: occ.componentId,
64
- via: defaultViaForKind(occ.componentId),
65
- derivedTags,
66
- repoId: "",
67
- });
68
- seedsById.set(id, { id, identity, derivedTags, manifest: null });
105
+ // 3. Local definitions that were never referenced in any occurrence.
106
+ // These must still appear in components[] so they can serve as
107
+ // owner-edge targets in the composition graph.
108
+ if (localIndex) {
109
+ for (const [, defs] of localIndex.byPath) {
110
+ for (const def of defs) {
111
+ const id = computeStableIdFromComponentId(def.componentId);
112
+ if (seedsById.has(id))
113
+ continue;
114
+ const definitionLoc = def.loc !== undefined
115
+ ? { line: def.loc.line, column: def.loc.column }
116
+ : undefined;
117
+ const identity = computeOutputIdentity({
118
+ componentId: def.componentId,
119
+ repoId: "",
120
+ ...(workspaceGraph !== undefined ? { workspaceGraph } : {}),
121
+ ...(definitionLoc !== undefined ? { definitionLoc } : {}),
122
+ });
123
+ seedsById.set(id, { id, identity, manifest: null, deprecated: false });
124
+ }
69
125
  }
70
126
  }
71
127
  return [...seedsById.values()];
72
128
  }
129
+ /**
130
+ * Find a parser-emitted seed whose logical identity matches the snapshot's
131
+ * `ComponentId`, ignoring `modulePath` (snapshot entries don't carry it).
132
+ *
133
+ * The match is intentionally narrowed to **unambiguous** cases: if two or more
134
+ * parser seeds share the same `{kind, packageName, exportName/tagName}` (e.g.
135
+ * two subpaths of one package both exporting `default`), we cannot safely pick
136
+ * one to enrich, so we return null and let the caller fall through to a
137
+ * snapshot-only seed.
138
+ */
139
+ function findUnambiguousMergeTarget(seeds, candidate) {
140
+ if (candidate.source.type !== "external")
141
+ return null;
142
+ const candidatePackage = candidate.source.package;
143
+ let match = null;
144
+ for (const seed of seeds.values()) {
145
+ if (seed.identity.kind !== candidate.kind)
146
+ continue;
147
+ if (seed.identity.packageName !== candidatePackage)
148
+ continue;
149
+ if (candidate.kind === "custom-element") {
150
+ if (seed.identity.tagName !== candidate.tagName)
151
+ continue;
152
+ }
153
+ else {
154
+ if (seed.identity.exportName !== candidate.export)
155
+ continue;
156
+ }
157
+ if (match !== null)
158
+ return null; // ambiguous — bail out
159
+ match = seed;
160
+ }
161
+ return match;
162
+ }
73
163
  /**
74
164
  * Convert an `IndexedComponent` to a `ComponentId` for use with
75
165
  * `computeOutputIdentity`. `IndexedComponent` extends `ManifestComponent`
@@ -89,26 +179,4 @@ function indexedToComponentId(c) {
89
179
  source: c.source,
90
180
  };
91
181
  }
92
- /**
93
- * Infer a default `via` for a snapshotted seed based on component kind.
94
- * Only `via.kind` is consumed by `computeOutputIdentity`; the required
95
- * `specifier`/`import` fields on `direct-import` are not meaningful for
96
- * zero-occurrence seeds and are left as empty strings.
97
- */
98
- function defaultVia(c) {
99
- if (c.kind === "custom-element") {
100
- return { kind: "html-tag" };
101
- }
102
- return { kind: "direct-import", specifier: "", import: "" };
103
- }
104
- /**
105
- * Infer a default `via` for an occurrence-observed seed based on the
106
- * component's kind. Used when seeding a component that has no snapshot entry.
107
- */
108
- function defaultViaForKind(c) {
109
- if (c.kind === "custom-element") {
110
- return { kind: "html-tag" };
111
- }
112
- return { kind: "direct-import", specifier: "", import: "" };
113
- }
114
182
  //# sourceMappingURL=seeds.js.map
package/dist/seeds.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"seeds.js","sourceRoot":"","sources":["../src/seeds.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"seeds.js","sourceRoot":"","sources":["../src/seeds.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -1,16 +1,13 @@
1
1
  export type { Loc, WarningCode, Warning } from "@component-compass/plugin-core";
2
- export type { TagRule } from "./config/schema.js";
3
- import type { TagRule } from "./config/schema.js";
4
2
  export type ResolvedConfig = {
5
3
  configPath: string;
6
4
  configDir: string;
7
- repoId: string;
8
- packageScopes: string[];
5
+ repoId?: string;
9
6
  include: string[];
10
7
  exclude: string[];
11
8
  captureValues: boolean;
12
9
  output: string;
10
+ gitignore: boolean;
13
11
  tsconfigPath?: string;
14
12
  aliases?: Record<string, string[]>;
15
- tagRules?: TagRule[];
16
13
  };
@@ -1 +1,9 @@
1
+ export type MTimeRange = {
2
+ firstCommitAt: string;
3
+ lastCommitAt: string;
4
+ };
5
+ export declare function readFileMTimes(root: string, paths: string[]): Promise<Map<string, MTimeRange>>;
1
6
  export declare function readGitCommit(root: string): Promise<string | undefined>;
7
+ export declare function readInitialCommit(root: string): Promise<string | undefined>;
8
+ export declare function readGitRemote(root: string): Promise<string | null>;
9
+ export declare function readGitBranch(root: string): Promise<string | null>;
package/dist/util/git.js CHANGED
@@ -1,6 +1,50 @@
1
1
  import { execFile } from "node:child_process";
2
2
  import { promisify } from "node:util";
3
3
  const exec = promisify(execFile);
4
+ export async function readFileMTimes(root, paths) {
5
+ if (paths.length === 0)
6
+ return new Map();
7
+ const out = new Map();
8
+ // git log --reverse interleaves commits oldest-first. Marker line precedes
9
+ // each commit's file list. Walk linearly: track currentDate, then bucket
10
+ // each named path into first (set once) / last (overwrite each commit).
11
+ // Known fidelity gaps: shallow clones cap firstCommitAt at the depth boundary;
12
+ // renames without --follow stop at the rename. Both documented in the spec.
13
+ try {
14
+ const args = [
15
+ "-c",
16
+ "core.quotePath=false",
17
+ "log",
18
+ "--reverse",
19
+ "--name-only",
20
+ "--format=__CC_COMMIT__ %aI",
21
+ "--",
22
+ ...paths,
23
+ ];
24
+ const { stdout } = await exec("git", args, {
25
+ cwd: root,
26
+ maxBuffer: 64 * 1024 * 1024,
27
+ });
28
+ let currentDate = null;
29
+ for (const line of stdout.split("\n")) {
30
+ if (line.startsWith("__CC_COMMIT__ ")) {
31
+ currentDate = line.slice("__CC_COMMIT__ ".length).trim();
32
+ }
33
+ else if (line.trim() && currentDate) {
34
+ const p = line.trim();
35
+ const existing = out.get(p);
36
+ if (existing)
37
+ existing.lastCommitAt = currentDate;
38
+ else
39
+ out.set(p, { firstCommitAt: currentDate, lastCommitAt: currentDate });
40
+ }
41
+ }
42
+ }
43
+ catch {
44
+ // git failure or buffer overflow — return whatever's accumulated (or empty).
45
+ }
46
+ return out;
47
+ }
4
48
  export async function readGitCommit(root) {
5
49
  try {
6
50
  const { stdout } = await exec("git", ["rev-parse", "HEAD"], { cwd: root });
@@ -10,4 +54,33 @@ export async function readGitCommit(root) {
10
54
  return undefined;
11
55
  }
12
56
  }
57
+ export async function readInitialCommit(root) {
58
+ try {
59
+ const { stdout } = await exec("git", ["rev-list", "--max-parents=0", "HEAD"], { cwd: root });
60
+ return stdout.trim().split("\n")[0];
61
+ }
62
+ catch {
63
+ return undefined;
64
+ }
65
+ }
66
+ export async function readGitRemote(root) {
67
+ try {
68
+ const { stdout } = await exec("git", ["config", "--get", "remote.origin.url"], { cwd: root });
69
+ return stdout.trim() || null;
70
+ }
71
+ catch {
72
+ return null;
73
+ }
74
+ }
75
+ export async function readGitBranch(root) {
76
+ try {
77
+ const { stdout } = await exec("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd: root });
78
+ const branch = stdout.trim();
79
+ // "HEAD" means detached HEAD state — not a named branch.
80
+ return branch === "HEAD" ? null : branch || null;
81
+ }
82
+ catch {
83
+ return null;
84
+ }
85
+ }
13
86
  //# sourceMappingURL=git.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/util/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAEjC,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAY;IAC9C,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3E,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/util/git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Rate-limited progress reporter for the scan loop. Emits a single line on
3
+ * stderr — rewriting in place when stderr is a TTY, appending one line per
4
+ * tick otherwise (CI logs).
5
+ *
6
+ * Rate limit: emit when either ≥50 ticks have happened since the last emit
7
+ * OR ≥250ms have elapsed. Tuned so the line moves smoothly on TTYs without
8
+ * spamming non-TTY logs.
9
+ */
10
+ export type ProgressOptions = {
11
+ total: number;
12
+ writer: (s: string) => void;
13
+ isTTY: boolean;
14
+ /** Verb prefix in the rendered line (default: "Scanned"). */
15
+ label?: string;
16
+ };
17
+ export type Progress = {
18
+ tick(): void;
19
+ done(): void;
20
+ };
21
+ export declare function createProgress(opts: ProgressOptions): Progress;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Rate-limited progress reporter for the scan loop. Emits a single line on
3
+ * stderr — rewriting in place when stderr is a TTY, appending one line per
4
+ * tick otherwise (CI logs).
5
+ *
6
+ * Rate limit: emit when either ≥50 ticks have happened since the last emit
7
+ * OR ≥250ms have elapsed. Tuned so the line moves smoothly on TTYs without
8
+ * spamming non-TTY logs.
9
+ */
10
+ const COUNT_THRESHOLD = 50;
11
+ const TIME_THRESHOLD_MS = 250;
12
+ export function createProgress(opts) {
13
+ const start = Date.now();
14
+ let processed = 0;
15
+ let lastEmitCount = -1; // forces emission on the first tick
16
+ let lastEmitTime = 0;
17
+ const label = opts.label ?? "Scanned";
18
+ function emit() {
19
+ const pct = opts.total > 0 ? ((processed / opts.total) * 100).toFixed(1) : "0.0";
20
+ const elapsedS = ((Date.now() - start) / 1000).toFixed(1);
21
+ const body = `${label} ${processed} / ${opts.total} files (${pct}%) — ${elapsedS}s elapsed`;
22
+ if (opts.isTTY) {
23
+ opts.writer(`\r${body}\x1b[K`);
24
+ }
25
+ else {
26
+ opts.writer(`${body}\n`);
27
+ }
28
+ lastEmitCount = processed;
29
+ lastEmitTime = Date.now();
30
+ }
31
+ return {
32
+ tick() {
33
+ processed += 1;
34
+ // sinceEmit counts the current tick, so the COUNT_THRESHOLDth tick since
35
+ // the last emit fires this branch (e.g. with threshold 50: emit at the
36
+ // 1st tick, then at the 50th, 99th, …). Always emit on the final tick
37
+ // so the bar shows 100% before the next phase starts.
38
+ const sinceEmit = processed - lastEmitCount;
39
+ const elapsedSinceEmit = Date.now() - lastEmitTime;
40
+ if (lastEmitCount === -1 ||
41
+ sinceEmit >= COUNT_THRESHOLD - 1 ||
42
+ elapsedSinceEmit >= TIME_THRESHOLD_MS ||
43
+ processed === opts.total) {
44
+ emit();
45
+ }
46
+ },
47
+ done() {
48
+ if (opts.isTTY && lastEmitCount > 0) {
49
+ opts.writer("\r\x1b[K");
50
+ }
51
+ },
52
+ };
53
+ }
54
+ //# sourceMappingURL=progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.js","sourceRoot":"","sources":["../../src/util/progress.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAeH,MAAM,eAAe,GAAG,EAAE,CAAC;AAC3B,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAE9B,MAAM,UAAU,cAAc,CAAC,IAAqB;IAClD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,oCAAoC;IAC5D,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC;IAEtC,SAAS,IAAI;QACX,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QACjF,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC1D,MAAM,IAAI,GAAG,GAAG,KAAK,IAAI,SAAS,MAAM,IAAI,CAAC,KAAK,WAAW,GAAG,QAAQ,QAAQ,WAAW,CAAC;QAC5F,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,QAAQ,CAAC,CAAC;QACjC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;QAC3B,CAAC;QACD,aAAa,GAAG,SAAS,CAAC;QAC1B,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC5B,CAAC;IAED,OAAO;QACL,IAAI;YACF,SAAS,IAAI,CAAC,CAAC;YACf,yEAAyE;YACzE,uEAAuE;YACvE,sEAAsE;YACtE,sDAAsD;YACtD,MAAM,SAAS,GAAG,SAAS,GAAG,aAAa,CAAC;YAC5C,MAAM,gBAAgB,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,YAAY,CAAC;YACnD,IACE,aAAa,KAAK,CAAC,CAAC;gBACpB,SAAS,IAAI,eAAe,GAAG,CAAC;gBAChC,gBAAgB,IAAI,iBAAiB;gBACrC,SAAS,KAAK,IAAI,CAAC,KAAK,EACxB,CAAC;gBACD,IAAI,EAAE,CAAC;YACT,CAAC;QACH,CAAC;QACD,IAAI;YACF,IAAI,IAAI,CAAC,KAAK,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;gBACpC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -2,5 +2,6 @@ export type WalkOptions = {
2
2
  root: string;
3
3
  include: string[];
4
4
  exclude: string[];
5
+ gitignore: boolean;
5
6
  };
6
7
  export declare function walkFiles(opts: WalkOptions): Promise<string[]>;
@@ -1,12 +1,18 @@
1
- import { glob } from "glob";
1
+ import { globby } from "globby";
2
2
  export async function walkFiles(opts) {
3
- const matched = await glob(opts.include, {
3
+ // `dot: false` skips `.next/`, `.nuxt/`, `.turbo/`, etc. unless the user
4
+ // explicitly globs them in. `gitignore: true` is the default at the config
5
+ // layer; the explicit knob exists so users can opt out for WIP scans of
6
+ // untracked work. `suppressErrors` silences EACCES on unreadable dirs
7
+ // (vendored fixtures, transient OS turds) — the walker keeps going.
8
+ return globby(opts.include, {
4
9
  cwd: opts.root,
5
- nodir: true,
6
- absolute: true,
7
10
  ignore: opts.exclude,
11
+ gitignore: opts.gitignore,
8
12
  dot: false,
13
+ absolute: true,
14
+ onlyFiles: true,
15
+ suppressErrors: true,
9
16
  });
10
- return matched;
11
17
  }
12
18
  //# sourceMappingURL=files.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/walker/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAQ5B,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAiB;IAC/C,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;QACvC,GAAG,EAAE,IAAI,CAAC,IAAI;QACd,KAAK,EAAE,IAAI;QACX,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,IAAI,CAAC,OAAO;QACpB,GAAG,EAAE,KAAK;KACX,CAAC,CAAC;IACH,OAAO,OAAO,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/walker/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAShC,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAiB;IAC/C,yEAAyE;IACzE,2EAA2E;IAC3E,wEAAwE;IACxE,sEAAsE;IACtE,oEAAoE;IACpE,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE;QAC1B,GAAG,EAAE,IAAI,CAAC,IAAI;QACd,MAAM,EAAE,IAAI,CAAC,OAAO;QACpB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,GAAG,EAAE,KAAK;QACV,QAAQ,EAAE,IAAI;QACd,SAAS,EAAE,IAAI;QACf,cAAc,EAAE,IAAI;KACrB,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { WorkspaceGraph } from "./types.js";
2
+ export declare function buildWorkspaceGraph(rootPath: string): WorkspaceGraph;
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Build a workspace graph from a repository root.
3
+ *
4
+ * Two independent steps:
5
+ * - sniffPackageManager: lockfile-based; sets graph.packageManager. Always
6
+ * runs; returns "unknown" when no lockfile is found.
7
+ * - detectWorkspacePackages: pnpm-workspace.yaml → package.json#workspaces →
8
+ * empty array. Independent of step 1.
9
+ *
10
+ * Glob expansion uses globby (already a CLI dep).
11
+ * Pure; no I/O beyond config-file reads.
12
+ */
13
+ import { existsSync, readFileSync } from "node:fs";
14
+ import { join, resolve } from "node:path";
15
+ import { globbySync } from "globby";
16
+ import * as yaml from "js-yaml";
17
+ export function buildWorkspaceGraph(rootPath) {
18
+ const absRoot = resolve(rootPath);
19
+ const rootPkgJsonPath = join(absRoot, "package.json");
20
+ const rootPkg = readJsonSafely(rootPkgJsonPath) ?? {};
21
+ const rootPackageName = typeof rootPkg.name === "string" ? rootPkg.name : "<unnamed>";
22
+ return {
23
+ packageManager: sniffPackageManager(absRoot),
24
+ rootPath: absRoot,
25
+ rootPackageName,
26
+ packages: detectWorkspacePackages(absRoot, rootPkg),
27
+ };
28
+ }
29
+ function sniffPackageManager(absRoot) {
30
+ if (existsSync(join(absRoot, "pnpm-lock.yaml")))
31
+ return "pnpm";
32
+ if (existsSync(join(absRoot, "package-lock.json")))
33
+ return "npm";
34
+ if (existsSync(join(absRoot, "yarn.lock")))
35
+ return "yarn";
36
+ return "unknown";
37
+ }
38
+ function detectWorkspacePackages(absRoot, rootPkg) {
39
+ // pnpm-workspace.yaml wins when both configs present.
40
+ const pnpmYamlPath = join(absRoot, "pnpm-workspace.yaml");
41
+ if (existsSync(pnpmYamlPath)) {
42
+ const yamlContent = readFileSync(pnpmYamlPath, "utf8");
43
+ let parsed;
44
+ try {
45
+ parsed = yaml.load(yamlContent);
46
+ }
47
+ catch {
48
+ parsed = null;
49
+ }
50
+ const globs = isWorkspaceYaml(parsed) ? parsed.packages : [];
51
+ return expandPackages(absRoot, globs);
52
+ }
53
+ // package.json#workspaces (array or object form).
54
+ const workspaces = rootPkg.workspaces;
55
+ if (Array.isArray(workspaces)) {
56
+ return expandPackages(absRoot, workspaces);
57
+ }
58
+ if (workspaces &&
59
+ typeof workspaces === "object" &&
60
+ Array.isArray(workspaces.packages)) {
61
+ return expandPackages(absRoot, workspaces.packages);
62
+ }
63
+ // No workspace config → single-package repo.
64
+ return [];
65
+ }
66
+ function expandPackages(absRoot, entries) {
67
+ if (entries.length === 0)
68
+ return [];
69
+ // Split literal paths from globs: globby (fast-glob) treats a bare "foo"
70
+ // as "foo/**" and returns subdirectories instead of foo itself, so literal
71
+ // workspace entries must be resolved directly.
72
+ const literals = [];
73
+ const globs = [];
74
+ for (const e of entries) {
75
+ if (/[*?[\]{}]/.test(e))
76
+ globs.push(e);
77
+ else
78
+ literals.push(e);
79
+ }
80
+ const matched = literals.map((p) => resolve(absRoot, p));
81
+ if (globs.length > 0) {
82
+ matched.push(...globbySync(globs, {
83
+ cwd: absRoot,
84
+ onlyDirectories: true,
85
+ absolute: true,
86
+ suppressErrors: true,
87
+ }));
88
+ }
89
+ const packages = [];
90
+ const seenNames = new Set();
91
+ for (const dir of matched) {
92
+ const pkgJson = readJsonSafely(join(dir, "package.json"));
93
+ if (!pkgJson)
94
+ continue;
95
+ if (typeof pkgJson.name !== "string" || pkgJson.name.length === 0)
96
+ continue;
97
+ if (seenNames.has(pkgJson.name))
98
+ continue;
99
+ seenNames.add(pkgJson.name);
100
+ packages.push({ name: pkgJson.name, absolutePath: dir, packageJson: pkgJson });
101
+ }
102
+ return packages;
103
+ }
104
+ function readJsonSafely(path) {
105
+ try {
106
+ return JSON.parse(readFileSync(path, "utf8"));
107
+ }
108
+ catch {
109
+ return null;
110
+ }
111
+ }
112
+ function isWorkspaceYaml(p) {
113
+ return (typeof p === "object" &&
114
+ p !== null &&
115
+ Array.isArray(p.packages));
116
+ }
117
+ //# sourceMappingURL=build-graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-graph.js","sourceRoot":"","sources":["../../src/workspace/build-graph.ts"],"names":[],"mappings":"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"}