@component-compass/plugin-core 0.0.5 → 0.1.1

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.
@@ -15,19 +15,41 @@ export type Diagnostic = {
15
15
  nameType: string;
16
16
  detail: string;
17
17
  } | {
18
- code: "vue-tag-low-confidence";
18
+ code: "low-confidence-tag";
19
19
  severity: "info";
20
20
  filePath: string;
21
21
  line?: number;
22
22
  column?: number;
23
23
  tagName: string;
24
- emittedAs: "vue-component" | "custom-element";
25
24
  } | {
26
25
  code: "local-index-duplicate-tag";
27
26
  severity: "warning";
28
27
  filePath: string;
29
28
  tagName: string;
30
29
  conflictsWith: string;
30
+ } | {
31
+ code: "unresolved-import";
32
+ severity: "warning";
33
+ filePath: string;
34
+ line: number;
35
+ column: number;
36
+ specifier: string;
37
+ } | {
38
+ code: "unresolved-reference";
39
+ severity: "info";
40
+ filePath: string;
41
+ line: number;
42
+ column: number;
43
+ symbol: string;
44
+ memberChain: string[];
45
+ } | {
46
+ code: "cycle-in-resolution";
47
+ severity: "warning";
48
+ filePath: string;
49
+ line: number;
50
+ column: number;
51
+ symbol: string;
52
+ depth: number;
31
53
  } | {
32
54
  code: "cycle-detected";
33
55
  severity: "warning";
@@ -27,10 +27,16 @@ function dedupKey(d) {
27
27
  switch (d.code) {
28
28
  case "jsx-shape-unsupported":
29
29
  return `${d.code}::${d.filePath}::${d.line ?? ""}::${d.column ?? ""}::${d.nameType}`;
30
- case "vue-tag-low-confidence":
30
+ case "low-confidence-tag":
31
31
  return `${d.code}::${d.filePath}::${d.line ?? ""}::${d.column ?? ""}::${d.tagName}`;
32
32
  case "local-index-duplicate-tag":
33
33
  return `${d.code}::${d.filePath}::${d.tagName}`;
34
+ case "unresolved-import":
35
+ return `${d.code}::${d.filePath}::${d.line}::${d.column}::${d.specifier}`;
36
+ case "unresolved-reference":
37
+ return `${d.code}::${d.filePath}::${d.line}::${d.column}::${d.symbol}::${d.memberChain.join(".")}`;
38
+ case "cycle-in-resolution":
39
+ return `${d.code}::${d.filePath}::${d.symbol}`;
34
40
  case "cycle-detected":
35
41
  return `${d.code}::${d.filePath}::${d.exportName}`;
36
42
  case "chain-too-deep":
@@ -1 +1 @@
1
- {"version":3,"file":"diagnostic.js","sourceRoot":"","sources":["../src/diagnostic.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAqDH,SAAS,iBAAiB,CAAC,CAAQ;IACjC,MAAM,IAAI,KAAK,CAAC,8BAA+B,CAAsB,CAAC,IAAI,EAAE,CAAC,CAAC;AAChF,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAS,QAAQ,CAAC,CAAa;IAC7B,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,uBAAuB;YAC1B,OAAO,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,IAAI,IAAI,EAAE,KAAK,CAAC,CAAC,MAAM,IAAI,EAAE,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC;QACvF,KAAK,wBAAwB;YAC3B,OAAO,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,IAAI,IAAI,EAAE,KAAK,CAAC,CAAC,MAAM,IAAI,EAAE,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;QACtF,KAAK,2BAA2B;YAC9B,OAAO,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;QAClD,KAAK,gBAAgB;YACnB,OAAO,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC;QACrD,KAAK,gBAAgB;YACnB,OAAO,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC;QACrD;YACE,OAAO,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAChC,CAAC;AACH,CAAC;AAID,MAAM,UAAU,yBAAyB;IACvC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,OAAO;QACL,IAAI,CAAC,CAAC;YACJ,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;YACxB,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,OAAO;YAC1B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACd,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,KAAK;YACH,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;YAC5B,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;YACnB,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,OAAO,GAAG,CAAC;QACb,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"diagnostic.js","sourceRoot":"","sources":["../src/diagnostic.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA+EH,SAAS,iBAAiB,CAAC,CAAQ;IACjC,MAAM,IAAI,KAAK,CAAC,8BAA+B,CAAsB,CAAC,IAAI,EAAE,CAAC,CAAC;AAChF,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAS,QAAQ,CAAC,CAAa;IAC7B,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,uBAAuB;YAC1B,OAAO,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,IAAI,IAAI,EAAE,KAAK,CAAC,CAAC,MAAM,IAAI,EAAE,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC;QACvF,KAAK,oBAAoB;YACvB,OAAO,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,IAAI,IAAI,EAAE,KAAK,CAAC,CAAC,MAAM,IAAI,EAAE,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;QACtF,KAAK,2BAA2B;YAC9B,OAAO,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;QAClD,KAAK,mBAAmB;YACtB,OAAO,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,SAAS,EAAE,CAAC;QAC5E,KAAK,sBAAsB;YACzB,OAAO,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACrG,KAAK,qBAAqB;YACxB,OAAO,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;QACjD,KAAK,gBAAgB;YACnB,OAAO,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC;QACrD,KAAK,gBAAgB;YACnB,OAAO,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC;QACrD;YACE,OAAO,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAChC,CAAC;AACH,CAAC;AAID,MAAM,UAAU,yBAAyB;IACvC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,OAAO;QACL,IAAI,CAAC,CAAC;YACJ,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;YACxB,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,OAAO;YAC1B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACd,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,KAAK;YACH,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;YAC5B,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;YACnB,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,OAAO,GAAG,CAAC;QACb,CAAC;KACF,CAAC;AACJ,CAAC"}
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ export { validateManifest } from "./validate.js";
4
4
  export type { ValidationResult } from "./validate.js";
5
5
  export { manifestJsonSchema } from "./schema.js";
6
6
  export { ManifestBuilder } from "./builder.js";
7
- export type { TagName, WrapperId, ImportRole, ImportEntry, IndexedComponent, Loc, WarningCode, Warning, ScanConfig, PropUsage, OccurrenceVia, Occurrence, WrapperDef, FileImport, ParseResult, ParseContext, ParserPlugin, ScanOutput, ManifestRef, ScanStats, DetectorId, LocalDefinition, LocalDefinitionIndex, ResolveLazyManifest, LookupByTag, LazyResolverHit, CemIndex, CemIndexEntry, } from "./scan-types.js";
7
+ export type { TagName, WrapperId, ImportRole, ImportEntry, IndexedComponent, Loc, WarningCode, Warning, ScanConfig, PropUsage, OccurrenceVia, Occurrence, WrapperDef, FileImport, ParseResult, ParseContext, ParserPlugin, ScanOutput, ManifestRef, ScanStats, DetectorId, LocalDefinition, LocalDefinitionIndex, ResolveLazyManifest, ResolveLocalExport, LookupByTag, LazyResolverHit, CemIndex, CemIndexEntry, } from "./scan-types.js";
8
8
  export { asTagName, asWrapperId, emptyLocalIndex } from "./scan-types.js";
9
9
  export type { Enrichment, AuthoredLeafPayload, DerivedLeafPayload } from "./enrichment.js";
10
10
  export { normalizeOwnerPath } from "./owner-utils.js";
@@ -13,3 +13,4 @@ export type { CompositionRollup } from "./output-types.js";
13
13
  export * from "./output-types.js";
14
14
  export type { Diagnostic, DiagnosticSeverity, DiagnosticCollector, DiagnosticCode } from "./diagnostic.js";
15
15
  export { createDiagnosticCollector } from "./diagnostic.js";
16
+ export type { ResolveImport } from "./resolve-import-type.js";
@@ -1,11 +1,22 @@
1
1
  /**
2
- * Stable per-occurrence id keyed on (componentId, filePath, line, column).
2
+ * Stable per-occurrence id keyed on (componentId, filePath, line, column,
3
+ * ownerComponentId?).
3
4
  *
4
- * Inputs use the FINAL artifact componentId string (the hashed form that
5
- * appears on `OutputOccurrence.componentId`), so downstream consumers can
6
- * re-derive: `id === computeOccurrenceId(o.componentId, o.filePath, o.line, o.column)`.
5
+ * Inputs use the FINAL artifact componentId strings (the hashed forms that
6
+ * appear on `OutputOccurrence.componentId` / `OutputOccurrence.ownerComponentId`),
7
+ * so downstream consumers can re-derive:
8
+ * id === computeOccurrenceId(o.componentId, o.filePath, o.line, o.column, o.ownerComponentId)
7
9
  *
8
- * 64 bits of entropy via 16-char SHA-256 truncation. Birthday-bound collision
9
- * at ~4 billion occurrences; full hash is overkill for current scale.
10
+ * `ownerComponentId` participates in the hash so that one JSX call site
11
+ * fanning out to multiple owner resolutions (helper-call fanout see
12
+ * docs/superpowers/specs/2026-05-22-phantom-owner-attribution-design.md)
13
+ * produces distinct ids per resolution. When `ownerComponentId` is
14
+ * undefined (parser-direct occurrence with no owner, or root JSX), the
15
+ * hash is computed without an owner segment — keeps the same shape as
16
+ * pre-fanout occurrences.
17
+ *
18
+ * 64 bits of entropy via 16-char SHA-256 truncation. Birthday-bound
19
+ * collision at ~4 billion occurrences; full hash is overkill for current
20
+ * scale.
10
21
  */
11
- export declare function computeOccurrenceId(componentId: string, filePath: string, line: number, column: number): string;
22
+ export declare function computeOccurrenceId(componentId: string, filePath: string, line: number, column: number, ownerComponentId?: string): string;
@@ -1,18 +1,28 @@
1
1
  import { createHash } from "node:crypto";
2
2
  /**
3
- * Stable per-occurrence id keyed on (componentId, filePath, line, column).
3
+ * Stable per-occurrence id keyed on (componentId, filePath, line, column,
4
+ * ownerComponentId?).
4
5
  *
5
- * Inputs use the FINAL artifact componentId string (the hashed form that
6
- * appears on `OutputOccurrence.componentId`), so downstream consumers can
7
- * re-derive: `id === computeOccurrenceId(o.componentId, o.filePath, o.line, o.column)`.
6
+ * Inputs use the FINAL artifact componentId strings (the hashed forms that
7
+ * appear on `OutputOccurrence.componentId` / `OutputOccurrence.ownerComponentId`),
8
+ * so downstream consumers can re-derive:
9
+ * id === computeOccurrenceId(o.componentId, o.filePath, o.line, o.column, o.ownerComponentId)
8
10
  *
9
- * 64 bits of entropy via 16-char SHA-256 truncation. Birthday-bound collision
10
- * at ~4 billion occurrences; full hash is overkill for current scale.
11
+ * `ownerComponentId` participates in the hash so that one JSX call site
12
+ * fanning out to multiple owner resolutions (helper-call fanout see
13
+ * docs/superpowers/specs/2026-05-22-phantom-owner-attribution-design.md)
14
+ * produces distinct ids per resolution. When `ownerComponentId` is
15
+ * undefined (parser-direct occurrence with no owner, or root JSX), the
16
+ * hash is computed without an owner segment — keeps the same shape as
17
+ * pre-fanout occurrences.
18
+ *
19
+ * 64 bits of entropy via 16-char SHA-256 truncation. Birthday-bound
20
+ * collision at ~4 billion occurrences; full hash is overkill for current
21
+ * scale.
11
22
  */
12
- export function computeOccurrenceId(componentId, filePath, line, column) {
13
- return createHash("sha256")
14
- .update(`${componentId}|${filePath}|${line}|${column}`)
15
- .digest("hex")
16
- .slice(0, 16);
23
+ export function computeOccurrenceId(componentId, filePath, line, column, ownerComponentId) {
24
+ const base = `${componentId}|${filePath}|${line}|${column}`;
25
+ const key = ownerComponentId !== undefined ? `${base}|${ownerComponentId}` : base;
26
+ return createHash("sha256").update(key).digest("hex").slice(0, 16);
17
27
  }
18
28
  //# sourceMappingURL=occurrence-id.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"occurrence-id.js","sourceRoot":"","sources":["../src/occurrence-id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CACjC,WAAmB,EACnB,QAAgB,EAChB,IAAY,EACZ,MAAc;IAEd,OAAO,UAAU,CAAC,QAAQ,CAAC;SACxB,MAAM,CAAC,GAAG,WAAW,IAAI,QAAQ,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;SACtD,MAAM,CAAC,KAAK,CAAC;SACb,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"occurrence-id.js","sourceRoot":"","sources":["../src/occurrence-id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,mBAAmB,CACjC,WAAmB,EACnB,QAAgB,EAChB,IAAY,EACZ,MAAc,EACd,gBAAyB;IAEzB,MAAM,IAAI,GAAG,GAAG,WAAW,IAAI,QAAQ,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;IAC5D,MAAM,GAAG,GAAG,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAClF,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACrE,CAAC"}
@@ -11,37 +11,59 @@ export type OutputIdentity = {
11
11
  scope: ComponentScope;
12
12
  kind: ComponentKindOutput;
13
13
  /**
14
- * For ds + external lanes: the npm package name as resolved by the manifest layer.
14
+ * For external lane: the npm package name as resolved by the manifest layer.
15
15
  * For local lane: the owning workspace package's name when the file resides inside
16
16
  * one. Absent for root-level local files (non-workspace single-package repos).
17
17
  */
18
18
  packageName?: string;
19
19
  /**
20
- * For resolver-driven external identities: the file Node's import resolution
21
- * (and any further chain walking) landed on, relative to the leaf package
22
- * root, POSIX-normalised. Disambiguates distinct components reached via
23
- * different subpaths of the same package. Absent for byTag-driven external
24
- * identities (which disambiguate via `tagName` alone) and for local identities
25
- * (which use `filePath` instead).
20
+ * For external identities reached via a subpath import: the subpath after
21
+ * the package name (e.g. `@shoelace-style/shoelace/dist/components/button`
22
+ * → `"dist/components/button"`), POSIX-normalised. Disambiguates distinct
23
+ * components reached via different subpaths of the same package.
24
+ * - Populated string: import specifier carried a subpath.
25
+ * - Absent (`undefined`): not applicable — bare package specifier (e.g.
26
+ * `react`), byTag-driven external identities, or local identities.
27
+ * Derived from the specifier string alone — does not depend on whether
28
+ * the moduleResolver succeeded. Independent canonical signal.
26
29
  */
27
30
  modulePath?: string;
28
31
  /** For react-component / vue-component. */
29
32
  exportName?: string;
30
33
  /** For custom-element. */
31
34
  tagName?: string;
32
- /** Present for local; absent for ds/external. */
35
+ /** Present for local; absent for external. */
33
36
  repoId?: string;
34
- /** Present for local; absent for ds/external. Repo-relative path of the defining file. */
37
+ /** Present for local; absent for external. Repo-relative path of the defining file. */
35
38
  filePath?: string;
36
39
  /**
37
40
  * Source position of the local-component declaration (the function/class
38
41
  * keyword for declarations; the variable identifier for `const Foo = ...`).
39
- * Only set when `scope === "local"`. Absent for ds / external / wc.
42
+ * Only set when `scope === "local"`. Absent for external / custom-element.
40
43
  */
41
44
  definition?: {
42
45
  line: number;
43
46
  column: number;
44
47
  };
48
+ /**
49
+ * Cross-link from a React wrapper to the underlying custom element it wraps.
50
+ * Set on react-component identities whose package's CEM declares a
51
+ * custom-element with `className === this.exportName`.
52
+ * Absent when no CEM match or for non-wrapper imports.
53
+ * Does NOT participate in componentId hashing.
54
+ */
55
+ wraps?: {
56
+ kind: "custom-element";
57
+ tagName: string;
58
+ packageName: string;
59
+ };
60
+ /**
61
+ * Cross-link from a custom element to all React wrappers pointing at it.
62
+ * Sorted array of componentIds (deterministic order). Populated in the
63
+ * post-resolve aggregation phase of scan.ts.
64
+ * Does NOT participate in componentId hashing.
65
+ */
66
+ wrappedBy?: string[];
45
67
  };
46
68
  export type PropDecl = {
47
69
  type?: string;
@@ -85,15 +107,14 @@ export type DerivedManifestData = {
85
107
  slots?: Record<string, SlotDecl>;
86
108
  invocable?: Record<string, InvocableDecl>;
87
109
  };
88
- export type DynamicKind = "spread" | "expr" | "identifier";
89
110
  /**
90
111
  * Per-occurrence prop value:
91
112
  * - a literal (string/number/boolean/null) when the source value is statically known,
92
- * - a `{ __dynamic }` marker when the value is a non-literal expression,
113
+ * - a `{ __dynamic: true }` marker when the value is a non-literal expression,
93
114
  * - or absent (key omitted from the map) when the prop was not set on the occurrence.
94
115
  */
95
116
  export type PropValueState = string | number | boolean | null | {
96
- __dynamic: DynamicKind;
117
+ __dynamic: true;
97
118
  };
98
119
  export type PropDistribution = {
99
120
  /** Stringified literal value -> occurrence count. */
@@ -143,7 +164,12 @@ export type OutputOccurrence = {
143
164
  filePath: string;
144
165
  line: number;
145
166
  column: number;
167
+ /** Outer-most access pattern (alias for viaChain[0]). */
146
168
  via: OccurrenceVia;
169
+ /** Full provenance chain from JSX site to resolved identity, outermost-first.
170
+ * Single-element for direct imports; multi-element for HOC chains, lazy boundaries
171
+ * through barrels, etc. */
172
+ viaChain: OccurrenceVia[];
147
173
  props: Record<string, PropValueState>;
148
174
  /** Phase 2: stable id keyed on (componentId, filePath, line, column). */
149
175
  occurrenceId: string;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Function type for "where does this import specifier point?" — the single
3
+ * source of truth consumed by both the lazy resolver and the
4
+ * classifyImportOrigin helper. Implementation lives in
5
+ * `cli/src/walker/resolve-import.ts` (knows about node-resolve quirks,
6
+ * tsconfig paths, config aliases). Type lives here so plugin-core consumers
7
+ * (ast-utils, parsers) can depend on it without depending on the CLI.
8
+ *
9
+ * Returns the absolute file path the specifier resolves to, or null if no
10
+ * resolution layer matches.
11
+ *
12
+ * See ADR 0001 for the dual-role rationale and CONTEXT.md "ResolveImport"
13
+ * entry for the glossary definition.
14
+ */
15
+ export type ResolveImport = (from: string, spec: string) => string | null;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=resolve-import-type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-import-type.js","sourceRoot":"","sources":["../src/resolve-import-type.ts"],"names":[],"mappings":""}
@@ -63,6 +63,20 @@ export type LazyResolverHit = {
63
63
  matched: IndexedComponent | null;
64
64
  };
65
65
  export type ResolveLazyManifest = (fromFile: string, specifier: string, exportName: string) => LazyResolverHit | null;
66
+ /**
67
+ * File-path-anchored local barrel walker. Given a known-local file and an
68
+ * export name, walks `export { X } from "./Y"` / `export * from "./Y"` chains
69
+ * to the terminal file the chain ended at. Returns null on cross-package
70
+ * boundary, cycle, max-hop overflow, or unresolvable re-export specifier.
71
+ * The terminal `exportName` may differ from the input when the chain renames
72
+ * (`export { X as Y } from "./Z"`); caller does the final byPath lookup to
73
+ * confirm the file actually exports the returned name. Backed by the lazy
74
+ * resolver's `parsedBarrel` cache.
75
+ */
76
+ export type ResolveLocalExport = (filePath: string, exportName: string) => {
77
+ filePath: string;
78
+ exportName: string;
79
+ } | null;
66
80
  export type LookupByTag = (tagName: string) => Extract<IndexedComponent, {
67
81
  kind: "custom-element";
68
82
  }> | null;
@@ -124,14 +138,6 @@ export type PropUsage = {
124
138
  name: string;
125
139
  isDynamic: boolean;
126
140
  literalValue?: string | number | boolean;
127
- /**
128
- * When `isDynamic` is true, distinguishes the kind of dynamic value:
129
- * - "spread" — JSX spread attribute (`{...rest}`); name is `"...rest"`.
130
- * - "identifier" — bare identifier reference (`prop={someVar}`).
131
- * - "expr" — any other expression (`prop={a + b}`, calls, ternaries, etc.).
132
- * Omitted when `isDynamic` is false.
133
- */
134
- dynamicKind?: "spread" | "expr" | "identifier";
135
141
  };
136
142
  export type { OccurrenceVia } from "./via-types.js";
137
143
  export type Occurrence = {
@@ -208,8 +214,16 @@ export type ParseContext = {
208
214
  config: ScanConfig;
209
215
  resolveImport: (from: string, spec: string) => string | null;
210
216
  resolveLazyManifest: ResolveLazyManifest;
217
+ resolveLocalExport: ResolveLocalExport;
211
218
  lookupByTag: LookupByTag;
212
219
  repoRoot: string;
220
+ /**
221
+ * Set of package names known to belong to the scan's repo (workspace
222
+ * siblings + declared deps). Threaded into `classifyImportOrigin` so
223
+ * specifiers that don't resolve on disk (uninstalled workspace siblings)
224
+ * can still recover external-package identity.
225
+ */
226
+ knownPackageNames?: ReadonlySet<string>;
213
227
  /** Shared diagnostic collector for the scan run. */
214
228
  collector?: DiagnosticCollector;
215
229
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"scan-types.js","sourceRoot":"","sources":["../src/scan-types.ts"],"names":[],"mappings":"AAsBA,kEAAkE;AAClE,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAS,EAAW,EAAE,CAAC,CAAY,CAAC;AAC9D,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAS,EAAa,EAAE,CAAC,CAAc,CAAC;AA2GpE,MAAM,CAAC,MAAM,eAAe,GAAyB;IACnD,MAAM,EAAE,IAAI,GAAG,EAAE;IACjB,KAAK,EAAE,IAAI,GAAG,EAAE;CACjB,CAAC"}
1
+ {"version":3,"file":"scan-types.js","sourceRoot":"","sources":["../src/scan-types.ts"],"names":[],"mappings":"AAsBA,kEAAkE;AAClE,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAS,EAAW,EAAE,CAAC,CAAY,CAAC;AAC9D,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAS,EAAa,EAAE,CAAC,CAAc,CAAC;AA0HpE,MAAM,CAAC,MAAM,eAAe,GAAyB;IACnD,MAAM,EAAE,IAAI,GAAG,EAAE;IACjB,KAAK,EAAE,IAAI,GAAG,EAAE;CACjB,CAAC"}
package/dist/types.d.ts CHANGED
@@ -6,6 +6,7 @@ export type ComponentSource = {
6
6
  } | {
7
7
  type: "local";
8
8
  filePath: string;
9
+ exportName?: string;
9
10
  } | {
10
11
  type: "unknown";
11
12
  };
@@ -25,4 +25,38 @@ export type OccurrenceVia = {
25
25
  kind: "context-provider";
26
26
  } | {
27
27
  kind: "local-component";
28
+ } | {
29
+ kind: "hoc-wrapper";
30
+ hocCallee: string;
31
+ specifier: string;
32
+ import: string;
33
+ } | {
34
+ kind: "dynamic-map";
35
+ mapName: string;
36
+ mapLoc: {
37
+ file: string;
38
+ line: number;
39
+ column: number;
40
+ };
41
+ } | {
42
+ kind: "lazy-import";
43
+ wrapperCallee: string;
44
+ specifier: string;
45
+ import: string;
46
+ } | {
47
+ kind: "dynamic-binding";
48
+ bindingName: string;
49
+ bindingSource: "parameter" | "hook-return";
50
+ } | {
51
+ kind: "prop-forward";
52
+ bindingName: string;
53
+ constructionSite: {
54
+ file: string;
55
+ line: number;
56
+ column: number;
57
+ };
58
+ } | {
59
+ kind: "helper-call";
60
+ callee: string;
61
+ calleeFile: string;
28
62
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@component-compass/plugin-core",
3
- "version": "0.0.5",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -21,12 +21,12 @@
21
21
  "clean": "rm -rf dist .turbo"
22
22
  },
23
23
  "dependencies": {
24
- "ajv": "^8.17.0"
24
+ "ajv": "8.20.0"
25
25
  },
26
26
  "devDependencies": {
27
- "@types/node": "^24.0.0",
28
- "typescript": "^5.9.0",
29
- "vitest": "^4.0.0"
27
+ "@types/node": "24.12.2",
28
+ "typescript": "5.9.3",
29
+ "vitest": "4.1.5"
30
30
  },
31
31
  "engines": {
32
32
  "node": ">=24"