@component-compass/plugin-core 0.1.23 → 0.1.28

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 (63) hide show
  1. package/dist/diagnostic.d.ts +15 -27
  2. package/dist/diagnostic.js +4 -8
  3. package/dist/diagnostic.js.map +1 -1
  4. package/dist/index.d.ts +3 -11
  5. package/dist/index.js +1 -6
  6. package/dist/index.js.map +1 -1
  7. package/dist/occurrence-id.d.ts +4 -4
  8. package/dist/occurrence-id.js +4 -4
  9. package/dist/project-props.d.ts +4 -4
  10. package/dist/project-props.js +3 -3
  11. package/dist/scan-types.d.ts +16 -121
  12. package/dist/scan-types.js +1 -2
  13. package/dist/scan-types.js.map +1 -1
  14. package/dist/types.d.ts +0 -62
  15. package/dist/v2/component-key.d.ts +3 -0
  16. package/dist/v2/component-key.js +12 -0
  17. package/dist/v2/component-key.js.map +1 -0
  18. package/dist/v2/index.d.ts +9 -0
  19. package/dist/v2/index.js +9 -0
  20. package/dist/v2/index.js.map +1 -0
  21. package/dist/v2/resolved-occurrences.d.ts +4 -0
  22. package/dist/v2/resolved-occurrences.js +8 -0
  23. package/dist/v2/resolved-occurrences.js.map +1 -0
  24. package/dist/v2/scan-stats.d.ts +16 -0
  25. package/dist/v2/scan-stats.js +13 -0
  26. package/dist/v2/scan-stats.js.map +1 -0
  27. package/dist/v2/schema-version.d.ts +8 -0
  28. package/dist/v2/schema-version.js +16 -0
  29. package/dist/v2/schema-version.js.map +1 -0
  30. package/dist/v2/schema.d.ts +4875 -0
  31. package/dist/v2/schema.js +188 -0
  32. package/dist/v2/schema.js.map +1 -0
  33. package/dist/v2/tag-attribution.d.ts +9 -0
  34. package/dist/v2/tag-attribution.js +70 -0
  35. package/dist/v2/tag-attribution.js.map +1 -0
  36. package/dist/v2/tag-vocabulary.d.ts +17 -0
  37. package/dist/v2/tag-vocabulary.js +33 -0
  38. package/dist/v2/tag-vocabulary.js.map +1 -0
  39. package/dist/v2/validate.d.ts +18 -0
  40. package/dist/v2/validate.js +20 -0
  41. package/dist/v2/validate.js.map +1 -0
  42. package/package.json +19 -6
  43. package/dist/builder.d.ts +0 -21
  44. package/dist/builder.js +0 -49
  45. package/dist/builder.js.map +0 -1
  46. package/dist/enrichment.d.ts +0 -28
  47. package/dist/enrichment.js +0 -2
  48. package/dist/enrichment.js.map +0 -1
  49. package/dist/logical-id.d.ts +0 -4
  50. package/dist/logical-id.js +0 -48
  51. package/dist/logical-id.js.map +0 -1
  52. package/dist/output-types.d.ts +0 -316
  53. package/dist/output-types.js +0 -2
  54. package/dist/output-types.js.map +0 -1
  55. package/dist/schema.d.ts +0 -204
  56. package/dist/schema.js +0 -62
  57. package/dist/schema.js.map +0 -1
  58. package/dist/validate.d.ts +0 -9
  59. package/dist/validate.js +0 -18
  60. package/dist/validate.js.map +0 -1
  61. package/dist/via-types.d.ts +0 -64
  62. package/dist/via-types.js +0 -2
  63. package/dist/via-types.js.map +0 -1
@@ -0,0 +1,188 @@
1
+ import { z } from "zod";
2
+ import { componentKey } from "./component-key.js";
3
+ import { SCHEMA_VERSION } from "./schema-version.js";
4
+ /** A non-null, non-array object. */
5
+ export function isPlainObject(value) {
6
+ return typeof value === "object" && value !== null && !Array.isArray(value);
7
+ }
8
+ /** A nested shape typed here in TypeScript, checked as a plain object only. */
9
+ const plainObject = () => z.custom((value) => isPlainObject(value));
10
+ const nonEmptyString = z.string().min(1);
11
+ const finiteNumber = z.number().finite();
12
+ /** A string `Date.parse` accepts. */
13
+ const timestamp = z.string().refine((value) => !Number.isNaN(Date.parse(value)));
14
+ /** Adds a cross-field issue at `path`, relative to the refined value. */
15
+ function fail(ctx, path) {
16
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path });
17
+ }
18
+ /**
19
+ * An open list keyed by `kind`: a known kind is checked against its variant, and any other non-empty kind passes
20
+ * with its other fields kept, unchecked.
21
+ */
22
+ function openKinds(...variants) {
23
+ const known = z.discriminatedUnion("kind", variants);
24
+ const other = z
25
+ .object({ kind: nonEmptyString })
26
+ .passthrough()
27
+ .superRefine((value, ctx) => {
28
+ // A known kind gets here only when its variant failed: its variant's issues, at their fields, reject it.
29
+ if (!known.optionsMap.has(value.kind))
30
+ return;
31
+ for (const issue of known.safeParse(value).error?.issues ?? [])
32
+ ctx.addIssue(issue);
33
+ });
34
+ return z.union([known, other]);
35
+ }
36
+ /** An open list of plain values: any non-empty string passes, including one this version doesn't know. */
37
+ const openValue = nonEmptyString;
38
+ /**
39
+ * Whether an open-list value has the known `kind`, narrowing it to that variant. The narrowing holds for a value
40
+ * `validateArtifact` accepted, which checks a known kind's fields, and for one the scanner built as `Known<T>`.
41
+ */
42
+ export function isKind(value, kind) {
43
+ return value.kind === kind;
44
+ }
45
+ /** The fields naming a repository declaration, in both an identity and an attribution target. */
46
+ const repositoryDeclarationFields = { repoId: nonEmptyString, filePath: nonEmptyString, exportName: nonEmptyString };
47
+ const identitySchema = z.discriminatedUnion("kind", [
48
+ z.object({ kind: z.literal("package-export"), packageName: nonEmptyString, publicEntry: z.string(), exportName: nonEmptyString }),
49
+ z.object({ kind: z.literal("repository-declaration"), ...repositoryDeclarationFields }),
50
+ z.object({ kind: z.literal("tag"), tagName: nonEmptyString }),
51
+ ]);
52
+ const frameworkSchema = z.enum(["react", "vue"]);
53
+ const creditSchema = openKinds(z.object({ kind: z.literal("render") }), z.object({ kind: z.literal("argument"), callee: z.string(), index: finiteNumber }));
54
+ const sourceLocSchema = z.object({ file: z.string(), line: finiteNumber, column: finiteNumber });
55
+ const traceStepSchema = openKinds(z.object({ kind: z.literal("import"), specifier: z.string(), name: z.string() }), z.object({ kind: z.literal("tag"), written: z.string() }), z.object({ kind: z.literal("hoc"), callee: z.string() }), z.object({ kind: z.literal("lazy"), callee: z.string() }), z.object({ kind: z.literal("dynamic-map"), mapName: z.string(), mapLoc: sourceLocSchema }), z.object({ kind: z.literal("helper-call"), callee: z.string(), calleeFile: z.string() }), z.object({ kind: z.literal("prop-forward"), bindingName: z.string(), constructionSite: sourceLocSchema }));
56
+ const unresolvedReasonSchema = openKinds(z.object({ kind: z.literal("package-not-installed"), packageName: nonEmptyString }), z.object({ kind: z.literal("module-not-found") }), z.object({ kind: z.literal("unbound-name"), name: nonEmptyString }), z.object({ kind: z.literal("chain-bailed"), code: openValue }));
57
+ const resolutionSchema = z.discriminatedUnion("status", [
58
+ z.object({ status: z.literal("resolved"), componentId: z.string() }),
59
+ z.object({
60
+ status: z.literal("unresolved"),
61
+ reason: unresolvedReasonSchema,
62
+ /** Never present on an unresolved occurrence. */
63
+ componentId: z.never().optional(),
64
+ }),
65
+ ]);
66
+ const occurrenceSchema = z.object({
67
+ occurrenceId: nonEmptyString,
68
+ resolution: resolutionSchema,
69
+ filePath: z.string(),
70
+ line: finiteNumber,
71
+ column: finiteNumber,
72
+ credit: creditSchema,
73
+ trace: z.array(traceStepSchema),
74
+ props: z.record(z.string(), plainObject()),
75
+ events: z.array(z.string()).optional(),
76
+ ownerComponentId: z.string().optional(),
77
+ depth: finiteNumber.optional(),
78
+ });
79
+ const attributionTargetSchema = z.discriminatedUnion("kind", [
80
+ z.object({ kind: z.literal("package"), packageName: nonEmptyString }),
81
+ z.object({ kind: z.literal("repository"), ...repositoryDeclarationFields }),
82
+ ]);
83
+ const evidenceRecordSchema = z.object({
84
+ source: z.enum(["registration", "global-declaration", "cem"]),
85
+ strength: openValue,
86
+ /** Repository-relative file, or a package coordinate. Never an absolute path. */
87
+ locator: z.union([
88
+ z.object({ filePath: z.string(), line: finiteNumber }),
89
+ z.object({ packageName: z.string(), version: z.string().nullable() }),
90
+ ]),
91
+ target: attributionTargetSchema.optional(),
92
+ disposition: openValue,
93
+ });
94
+ const tagAttributionSchema = z.discriminatedUnion("status", [
95
+ z.object({
96
+ status: z.literal("resolved"),
97
+ target: attributionTargetSchema,
98
+ confidence: openValue,
99
+ evidence: z.array(evidenceRecordSchema),
100
+ }),
101
+ z.object({ status: z.literal("unknown"), reason: openValue, evidence: z.array(evidenceRecordSchema) }),
102
+ z.object({
103
+ status: z.literal("conflict"),
104
+ strongestClass: openValue,
105
+ candidates: z.array(attributionTargetSchema),
106
+ evidence: z.array(evidenceRecordSchema),
107
+ }),
108
+ ]);
109
+ const propDistributionSchema = z.object({
110
+ values: z.array(plainObject()),
111
+ dynamic: finiteNumber,
112
+ omitted: finiteNumber,
113
+ other: finiteNumber.optional(),
114
+ truncated: finiteNumber.optional(),
115
+ });
116
+ const componentSchema = z
117
+ .object({
118
+ id: z.string(),
119
+ identity: identitySchema,
120
+ /** Package exports and repository declarations only; absent on tags. */
121
+ framework: frameworkSchema.optional(),
122
+ /** Tag identities only; computed from this scan's evidence. */
123
+ attribution: tagAttributionSchema.optional(),
124
+ stats: z.object({ occurrenceCount: finiteNumber, fileCount: finiteNumber }),
125
+ usage: z.enum(["direct", "root", "none"]),
126
+ props: z.record(z.string(), propDistributionSchema),
127
+ events: z.record(z.string(), z.object({ boundCount: finiteNumber })).optional(),
128
+ composition: plainObject(),
129
+ /** Repository declarations only. */
130
+ declared: plainObject().optional(),
131
+ /** Repository declarations only: declaration position in `identity.filePath`. */
132
+ definition: z.object({ line: finiteNumber, column: finiteNumber }).optional(),
133
+ /** Repository declarations only: owning workspace package name. */
134
+ owningPackage: z.string().optional(),
135
+ version: z.string().nullable(),
136
+ createdAt: timestamp.nullable().optional(),
137
+ updatedAt: timestamp.nullable().optional(),
138
+ })
139
+ .superRefine((component, ctx) => {
140
+ const onTag = component.identity.kind === "tag";
141
+ if (component.id !== componentKey(component.identity))
142
+ fail(ctx, ["id"]);
143
+ if (component.attribution !== undefined && !onTag)
144
+ fail(ctx, ["attribution"]);
145
+ if (onTag ? component.framework !== undefined : component.framework === undefined)
146
+ fail(ctx, ["framework"]);
147
+ });
148
+ const scanMetaSchema = z.object({
149
+ schemaVersion: z.literal(SCHEMA_VERSION),
150
+ scannerVersion: z.string(),
151
+ scanId: nonEmptyString,
152
+ scannedAt: timestamp,
153
+ repo: z.object({
154
+ id: nonEmptyString,
155
+ gitRemote: z.string().nullable(),
156
+ commit: nonEmptyString,
157
+ /** The committer date of `commit`. */
158
+ committedAt: timestamp,
159
+ initialCommit: z.string().nullable(),
160
+ branch: z.string().nullable(),
161
+ }),
162
+ });
163
+ /** The whole artefact: component ids and occurrence ids are unique, and a resolved occurrence names a listed component. */
164
+ export const artifactSchema = z
165
+ .object({
166
+ meta: scanMetaSchema,
167
+ components: z.array(componentSchema),
168
+ occurrences: z.array(occurrenceSchema),
169
+ diagnostics: z.array(plainObject()),
170
+ })
171
+ .superRefine((artifact, ctx) => {
172
+ const componentIds = new Set();
173
+ for (const [index, component] of artifact.components.entries()) {
174
+ if (componentIds.has(component.id))
175
+ fail(ctx, ["components", index, "id"]);
176
+ componentIds.add(component.id);
177
+ }
178
+ const occurrenceIds = new Set();
179
+ for (const [index, { occurrenceId, resolution }] of artifact.occurrences.entries()) {
180
+ if (occurrenceIds.has(occurrenceId))
181
+ fail(ctx, ["occurrences", index, "occurrenceId"]);
182
+ occurrenceIds.add(occurrenceId);
183
+ if (resolution.status === "resolved" && !componentIds.has(resolution.componentId)) {
184
+ fail(ctx, ["occurrences", index, "resolution", "componentId"]);
185
+ }
186
+ }
187
+ });
188
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/v2/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { KnownEvidenceRecord, KnownTagAttribution } from "./schema.js";
2
+ /**
3
+ * A tag's attribution from every evidence record found for it: the strongest
4
+ * class that carries a target decides. One target there resolves the tag with
5
+ * that class as confidence; several are a conflict; no targeted record leaves
6
+ * it unknown. Every record is kept, sorted, and given its disposition against
7
+ * the outcome, so the result never depends on input order.
8
+ */
9
+ export declare function resolveTagAttribution(evidence: readonly KnownEvidenceRecord[]): KnownTagAttribution;
@@ -0,0 +1,70 @@
1
+ /** Strongest class first. */
2
+ const STRENGTHS = ["observed", "declared"];
3
+ /** A target as JSON with its keys in a fixed order. */
4
+ function targetKey(target) {
5
+ return target.kind === "package"
6
+ ? JSON.stringify({ kind: target.kind, packageName: target.packageName })
7
+ : JSON.stringify({ kind: target.kind, repoId: target.repoId, filePath: target.filePath, exportName: target.exportName });
8
+ }
9
+ const compareText = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
10
+ /** File locators before package coordinates; a file's lines in numeric order. */
11
+ function compareLocators(a, b) {
12
+ if ("filePath" in a)
13
+ return "filePath" in b ? compareText(a.filePath, b.filePath) || a.line - b.line : -1;
14
+ if ("filePath" in b)
15
+ return 1;
16
+ return compareText(a.packageName, b.packageName) || compareText(a.version ?? "", b.version ?? "");
17
+ }
18
+ /** Strongest class first, then source, locator and target. */
19
+ function compareRecords(a, b) {
20
+ return (STRENGTHS.indexOf(a.strength) - STRENGTHS.indexOf(b.strength) ||
21
+ compareText(a.source, b.source) ||
22
+ compareLocators(a.locator, b.locator) ||
23
+ compareText(a.target !== undefined ? targetKey(a.target) : "", b.target !== undefined ? targetKey(b.target) : ""));
24
+ }
25
+ /**
26
+ * A tag's attribution from every evidence record found for it: the strongest
27
+ * class that carries a target decides. One target there resolves the tag with
28
+ * that class as confidence; several are a conflict; no targeted record leaves
29
+ * it unknown. Every record is kept, sorted, and given its disposition against
30
+ * the outcome, so the result never depends on input order.
31
+ */
32
+ export function resolveTagAttribution(evidence) {
33
+ const records = [...evidence].sort(compareRecords);
34
+ const strongestClass = STRENGTHS.find((s) => records.some((r) => r.strength === s && r.target !== undefined));
35
+ if (strongestClass === undefined) {
36
+ const unresolved = records.map((r) => withDisposition(r, "unresolved"));
37
+ return { status: "unknown", reason: records.length === 0 ? "absent" : "unresolved", evidence: unresolved };
38
+ }
39
+ const candidates = new Map();
40
+ for (const r of records) {
41
+ if (r.strength === strongestClass && r.target !== undefined)
42
+ candidates.set(targetKey(r.target), r.target);
43
+ }
44
+ if (candidates.size === 1) {
45
+ const [[resolvedKey, target]] = [...candidates];
46
+ return {
47
+ status: "resolved",
48
+ target,
49
+ confidence: strongestClass,
50
+ evidence: records.map((r) => withDisposition(r, r.target === undefined ? "unresolved" : targetKey(r.target) === resolvedKey ? "supports" : "contradicts")),
51
+ };
52
+ }
53
+ return {
54
+ status: "conflict",
55
+ strongestClass,
56
+ candidates: [...candidates.values()].sort((a, b) => compareText(targetKey(a), targetKey(b))),
57
+ evidence: records.map((r) => withDisposition(r, r.target === undefined ? "unresolved" : candidates.has(targetKey(r.target)) ? "candidate" : "contradicts")),
58
+ };
59
+ }
60
+ /** The record in schema key order, with `disposition` set. */
61
+ function withDisposition(record, disposition) {
62
+ return {
63
+ source: record.source,
64
+ strength: record.strength,
65
+ locator: record.locator,
66
+ ...(record.target !== undefined ? { target: record.target } : {}),
67
+ disposition,
68
+ };
69
+ }
70
+ //# sourceMappingURL=tag-attribution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tag-attribution.js","sourceRoot":"","sources":["../../src/v2/tag-attribution.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * The HTML Standard's "valid custom element name", §4.13.3 Core concepts
3
+ * (https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name):
4
+ * a valid element local name (DOM Standard,
5
+ * https://dom.spec.whatwg.org/#valid-element-local-name) whose first code
6
+ * point is an ASCII lower alpha, that contains no ASCII upper alpha, that
7
+ * contains U+002D (-), and that is not one of the reserved names below.
8
+ *
9
+ * With an ASCII-alpha first code point, a valid element local name is one
10
+ * that contains no ASCII whitespace, U+0000 NULL, U+002F (/) or U+003E (>).
11
+ */
12
+ /** The hyphenated names SVG and MathML already use, which no custom element may take. */
13
+ export declare const RESERVED_CUSTOM_ELEMENT_NAMES: ReadonlySet<string>;
14
+ /** The written tag name, ASCII-lowercased: the name an HTML document gives the element. */
15
+ export declare function canonicalTagName(written: string): string;
16
+ /** True when `name` is a valid custom element name. */
17
+ export declare function isValidCustomElementName(name: string): boolean;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The HTML Standard's "valid custom element name", §4.13.3 Core concepts
3
+ * (https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name):
4
+ * a valid element local name (DOM Standard,
5
+ * https://dom.spec.whatwg.org/#valid-element-local-name) whose first code
6
+ * point is an ASCII lower alpha, that contains no ASCII upper alpha, that
7
+ * contains U+002D (-), and that is not one of the reserved names below.
8
+ *
9
+ * With an ASCII-alpha first code point, a valid element local name is one
10
+ * that contains no ASCII whitespace, U+0000 NULL, U+002F (/) or U+003E (>).
11
+ */
12
+ /** The hyphenated names SVG and MathML already use, which no custom element may take. */
13
+ export const RESERVED_CUSTOM_ELEMENT_NAMES = new Set([
14
+ "annotation-xml",
15
+ "color-profile",
16
+ "font-face",
17
+ "font-face-src",
18
+ "font-face-uri",
19
+ "font-face-format",
20
+ "font-face-name",
21
+ "missing-glyph",
22
+ ]);
23
+ /** A lower-alpha first code point, then none of ASCII whitespace, NULL, `/`, `>` or an ASCII upper alpha. */
24
+ const LOWER_ALPHA_LOCAL_NAME = /^[a-z][^\0\t\n\f\r />A-Z]*$/;
25
+ /** The written tag name, ASCII-lowercased: the name an HTML document gives the element. */
26
+ export function canonicalTagName(written) {
27
+ return written.replace(/[A-Z]/g, (c) => c.toLowerCase());
28
+ }
29
+ /** True when `name` is a valid custom element name. */
30
+ export function isValidCustomElementName(name) {
31
+ return LOWER_ALPHA_LOCAL_NAME.test(name) && name.includes("-") && !RESERVED_CUSTOM_ELEMENT_NAMES.has(name);
32
+ }
33
+ //# sourceMappingURL=tag-vocabulary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tag-vocabulary.js","sourceRoot":"","sources":["../../src/v2/tag-vocabulary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,yFAAyF;AACzF,MAAM,CAAC,MAAM,6BAA6B,GAAwB,IAAI,GAAG,CAAC;IACxE,gBAAgB;IAChB,eAAe;IACf,WAAW;IACX,eAAe;IACf,eAAe;IACf,kBAAkB;IAClB,gBAAgB;IAChB,eAAe;CAChB,CAAC,CAAC;AAEH,6GAA6G;AAC7G,MAAM,sBAAsB,GAAG,6BAA6B,CAAC;AAE7D,2FAA2F;AAC3F,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,OAAO,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAC3D,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,wBAAwB,CAAC,IAAY;IACnD,OAAO,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,6BAA6B,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC7G,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { type ScanArtifact } from "./schema.js";
2
+ export type ValidationResult = {
3
+ ok: true;
4
+ artifact: ScanArtifact;
5
+ } | {
6
+ ok: false;
7
+ reason: "unsupported_version";
8
+ version: number | "invalid";
9
+ } | {
10
+ ok: false;
11
+ reason: "invalid_artifact";
12
+ path: string;
13
+ };
14
+ /**
15
+ * Checks a parsed artefact against the v2 contract: the schema version first, then the first failing JSON path.
16
+ * A valid artefact is returned as the input object itself, unknown keys included.
17
+ */
18
+ export declare function validateArtifact(value: unknown): ValidationResult;
@@ -0,0 +1,20 @@
1
+ import { artifactSchema, isPlainObject } from "./schema.js";
2
+ import { SCHEMA_VERSION, schemaVersionOf } from "./schema-version.js";
3
+ /** Formats an issue path as `a.b[0].c`: an index as `[n]`, a key as `.key`, with no leading dot. */
4
+ function formatPath(path) {
5
+ return path.map((segment) => (typeof segment === "number" ? `[${segment}]` : `.${segment}`)).join("").replace(/^\./, "");
6
+ }
7
+ /**
8
+ * Checks a parsed artefact against the v2 contract: the schema version first, then the first failing JSON path.
9
+ * A valid artefact is returned as the input object itself, unknown keys included.
10
+ */
11
+ export function validateArtifact(value) {
12
+ const version = schemaVersionOf(isPlainObject(value) && "meta" in value ? value.meta : undefined);
13
+ if (version !== SCHEMA_VERSION)
14
+ return { ok: false, reason: "unsupported_version", version };
15
+ const result = artifactSchema.safeParse(value);
16
+ if (result.success)
17
+ return { ok: true, artifact: value };
18
+ return { ok: false, reason: "invalid_artifact", path: formatPath(result.error.issues[0]?.path ?? []) };
19
+ }
20
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/v2/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAqB,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAOtE,oGAAoG;AACpG,SAAS,UAAU,CAAC,IAAkC;IACpD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC3H,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,MAAM,OAAO,GAAG,eAAe,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAClG,IAAI,OAAO,KAAK,cAAc;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,qBAAqB,EAAE,OAAO,EAAE,CAAC;IAC7F,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/C,IAAI,MAAM,CAAC,OAAO;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAqB,EAAE,CAAC;IACzE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC,EAAE,CAAC;AACzG,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,19 @@
1
1
  {
2
2
  "name": "@component-compass/plugin-core",
3
- "version": "0.1.23",
3
+ "version": "0.1.28",
4
+ "description": "Scan artifact types and component identity helpers shared by component-compass packages.",
5
+ "keywords": [
6
+ "design-system",
7
+ "custom-elements-manifest"
8
+ ],
9
+ "license": "MIT",
10
+ "homepage": "https://github.com/siggerzz/component-compass/tree/main/packages/plugin-core",
11
+ "bugs": "https://github.com/siggerzz/component-compass/issues",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/siggerzz/component-compass.git",
15
+ "directory": "packages/plugin-core"
16
+ },
4
17
  "type": "module",
5
18
  "main": "./dist/index.js",
6
19
  "types": "./dist/index.d.ts",
@@ -9,13 +22,13 @@
9
22
  "types": "./dist/index.d.ts",
10
23
  "import": "./dist/index.js"
11
24
  },
12
- "./logical-id": {
13
- "types": "./dist/logical-id.d.ts",
14
- "import": "./dist/logical-id.js"
15
- },
16
25
  "./id": {
17
26
  "types": "./dist/id.d.ts",
18
27
  "import": "./dist/id.js"
28
+ },
29
+ "./v2": {
30
+ "types": "./dist/v2/index.d.ts",
31
+ "import": "./dist/v2/index.js"
19
32
  }
20
33
  },
21
34
  "files": [
@@ -30,7 +43,7 @@
30
43
  },
31
44
  "dependencies": {
32
45
  "@noble/hashes": "1.8.0",
33
- "ajv": "8.20.0"
46
+ "zod": "3.25.76"
34
47
  },
35
48
  "devDependencies": {
36
49
  "@types/node": "24.12.2",
package/dist/builder.d.ts DELETED
@@ -1,21 +0,0 @@
1
- import type { ManifestComponent, ManifestFile, ManifestSource } from "./types.js";
2
- type BuilderOpts = {
3
- source: ManifestSource;
4
- package: string;
5
- };
6
- type AddInput = Extract<ManifestComponent, {
7
- kind: "custom-element";
8
- }> | Extract<ManifestComponent, {
9
- kind: "react-component";
10
- }> | Extract<ManifestComponent, {
11
- kind: "vue-component";
12
- }>;
13
- export declare class ManifestBuilder {
14
- private readonly source;
15
- private readonly packageName;
16
- private readonly components;
17
- constructor(opts: BuilderOpts);
18
- addComponent(c: AddInput): this;
19
- build(): ManifestFile;
20
- }
21
- export {};
package/dist/builder.js DELETED
@@ -1,49 +0,0 @@
1
- import { compareComponentId } from "./id.js";
2
- import { validateManifest } from "./validate.js";
3
- const SCHEMA_VERSION = "2.0.0";
4
- const expectedKindFor = {
5
- cem: "custom-element",
6
- react: "react-component",
7
- vue: "vue-component",
8
- };
9
- export class ManifestBuilder {
10
- source;
11
- packageName;
12
- components = [];
13
- constructor(opts) {
14
- this.source = opts.source;
15
- this.packageName = opts.package;
16
- }
17
- addComponent(c) {
18
- const expected = expectedKindFor[this.source];
19
- if (c.kind !== expected) {
20
- throw new Error(`Component kind "${c.kind}" does not match builder source "${this.source}" (expected kind "${expected}")`);
21
- }
22
- this.components.push(c);
23
- return this;
24
- }
25
- build() {
26
- const sorted = [...this.components].sort(compareComponents);
27
- const out = {
28
- schemaVersion: SCHEMA_VERSION,
29
- source: this.source,
30
- package: this.packageName,
31
- components: sorted,
32
- };
33
- const result = validateManifest(out);
34
- if (!result.ok) {
35
- throw new Error(`Built manifest fails validation:\n${result.errors.join("\n")}`);
36
- }
37
- return out;
38
- }
39
- }
40
- function compareComponents(a, b) {
41
- return compareComponentId(toId(a), toId(b));
42
- }
43
- function toId(c) {
44
- if (c.kind === "custom-element") {
45
- return { kind: "custom-element", tagName: c.tagName, source: c.source };
46
- }
47
- return { kind: c.kind, export: c.export, source: c.source };
48
- }
49
- //# sourceMappingURL=builder.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"builder.js","sourceRoot":"","sources":["../src/builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAE7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,cAAc,GAAG,OAAO,CAAC;AAE/B,MAAM,eAAe,GAAsD;IACzE,GAAG,EAAE,gBAAgB;IACrB,KAAK,EAAE,iBAAiB;IACxB,GAAG,EAAE,eAAe;CACrB,CAAC;AASF,MAAM,OAAO,eAAe;IACT,MAAM,CAAiB;IACvB,WAAW,CAAS;IACpB,UAAU,GAAwB,EAAE,CAAC;IAEtD,YAAY,IAAiB;QAC3B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC;IAClC,CAAC;IAED,YAAY,CAAC,CAAW;QACtB,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9C,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CACb,mBAAmB,CAAC,CAAC,IAAI,oCAAoC,IAAI,CAAC,MAAM,qBAAqB,QAAQ,IAAI,CAC1G,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK;QACH,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAC5D,MAAM,GAAG,GAAiB;YACxB,aAAa,EAAE,cAAc;YAC7B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,OAAO,EAAE,IAAI,CAAC,WAAW;YACzB,UAAU,EAAE,MAAM;SACnB,CAAC;QACF,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACrC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,qCAAqC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnF,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF;AAED,SAAS,iBAAiB,CAAC,CAAoB,EAAE,CAAoB;IACnE,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,CAAC;AAED,SAAS,IAAI,CAAC,CAAoB;IAChC,IAAI,CAAC,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;QAChC,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;IAC1E,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;AAC9D,CAAC"}
@@ -1,28 +0,0 @@
1
- import type { IndexedComponent } from "./scan-types.js";
2
- /**
3
- * Manifest source for enrichment of a resolver-discovered leaf package.
4
- *
5
- * - "authored": leaf shipped a `custom-elements.json` or
6
- * `component-compass-manifest.json` at its package root.
7
- * - null: no enrichment available — identity stays opaque
8
- * (`components[].manifest === null` in the artifact).
9
- */
10
- export type Enrichment = {
11
- source: "authored";
12
- data: AuthoredLeafPayload;
13
- } | null;
14
- /**
15
- * Payload shape held by the lazy resolver for a successfully-loaded leaf
16
- * manifest. Per-leaf, not per-component — carries every component the leaf
17
- * declares plus the manifest source metadata.
18
- */
19
- export type AuthoredLeafPayload = {
20
- /** Every component declared in the leaf's authored manifest. */
21
- components: IndexedComponent[];
22
- /** Absolute filesystem path of the loaded manifest file. */
23
- manifestPath: string;
24
- /** Authored format the manifest was loaded from. */
25
- manifestKind: "cem" | "component-compass-manifest";
26
- /** Leaf package's `version` field, when readable. */
27
- packageVersion?: string;
28
- };
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=enrichment.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"enrichment.js","sourceRoot":"","sources":["../src/enrichment.ts"],"names":[],"mappings":""}
@@ -1,4 +0,0 @@
1
- import type { OutputIdentity } from "./output-types.js";
2
- export declare function logicalKeyFor(identity: OutputIdentity): string | null;
3
- export declare function hashLogicalKey(key: string): string;
4
- export declare function computeLogicalId(identity: OutputIdentity, physicalId: string): string;
@@ -1,48 +0,0 @@
1
- /**
2
- * THE logical-id seam. A logical component groups the physical
3
- * identities that realize it; the key is a pure function of one identity:
4
- * - external custom-element -> logical::<tagName>
5
- * - external react/vue with `wraps` -> its TARGET's tag key (same as above)
6
- * - everything else -> null (singleton: logicalId = physical id)
7
- * Tag keys are deliberately modulePath-free and derivable
8
- * from the identity alone so every repo lands on the same id.
9
- * Keyed on tag name alone, not package+tag: tag names
10
- * are the platform's global-uniqueness contract, and package-keying split a
11
- * resolved custom element from its package-unresolved twin onto two logical
12
- * ids for the same element.
13
- * Do not re-derive these keys anywhere else — import from here (CLI stamps
14
- * at scan time; web-shared derives only for legacy stored artifacts).
15
- *
16
- * This module is ISOMORPHIC on purpose. `deriveLogicalId` (web-shared) is
17
- * reachable from `"use client"` components, so the seam gets bundled for the
18
- * browser as well as run in Node. Hashing therefore goes through
19
- * `@noble/hashes` (zero-dependency, no `node:crypto`); `hashLogicalKey` stays
20
- * byte-identical to the `createHash("sha1")` form it replaced — see the
21
- * byte-identity suite in tests/logical-id.test.ts. Keep this file free of
22
- * *unconditional* Node builtins: anything added here ships to the client.
23
- * (`@noble/hashes/utils` resolves `node:crypto` only under the `node` export
24
- * condition, via `@noble/hashes/crypto` -> `cryptoNode.js`; isomorphism rests
25
- * on bundlers picking the browser condition, not on the module graph being
26
- * literally builtin-free.)
27
- */
28
- import { sha1 } from "@noble/hashes/legacy";
29
- import { bytesToHex, utf8ToBytes } from "@noble/hashes/utils";
30
- export function logicalKeyFor(identity) {
31
- if (identity.scope !== "external")
32
- return null;
33
- if (identity.kind === "custom-element" && identity.tagName !== undefined) {
34
- return `logical::${identity.tagName}`;
35
- }
36
- if (identity.wraps !== undefined) {
37
- return `logical::${identity.wraps.tagName}`;
38
- }
39
- return null;
40
- }
41
- export function hashLogicalKey(key) {
42
- return bytesToHex(sha1(utf8ToBytes(key))).slice(0, 16);
43
- }
44
- export function computeLogicalId(identity, physicalId) {
45
- const key = logicalKeyFor(identity);
46
- return key === null ? physicalId : hashLogicalKey(key);
47
- }
48
- //# sourceMappingURL=logical-id.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"logical-id.js","sourceRoot":"","sources":["../src/logical-id.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAG9D,MAAM,UAAU,aAAa,CAAC,QAAwB;IACpD,IAAI,QAAQ,CAAC,KAAK,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IAC/C,IAAI,QAAQ,CAAC,IAAI,KAAK,gBAAgB,IAAI,QAAQ,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACzE,OAAO,YAAY,QAAQ,CAAC,OAAO,EAAE,CAAC;IACxC,CAAC;IACD,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO,YAAY,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;IAC9C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,OAAO,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,QAAwB,EAAE,UAAkB;IAC3E,MAAM,GAAG,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IACpC,OAAO,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;AACzD,CAAC"}