@usefragments/core 1.4.0 → 1.5.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.
- package/dist/{chunk-CBSNXFOD.js → chunk-AOG4FTV6.js} +146 -6
- package/dist/chunk-AOG4FTV6.js.map +1 -0
- package/dist/{chunk-57QDBEHQ.js → chunk-ZHS52OT4.js} +3 -9
- package/dist/chunk-ZHS52OT4.js.map +1 -0
- package/dist/codes/index.d.ts +2 -2
- package/dist/codes/index.js +2 -2
- package/dist/compiled-types/index.d.ts +1 -1
- package/dist/generate/index.d.ts +1 -1
- package/dist/{governance-DxdJV6lx.d.ts → governance-B88uR3Zq.d.ts} +229 -1
- package/dist/{index-0lmh0Lbo.d.ts → index-DbkPE46t.d.ts} +48 -8
- package/dist/index.d.ts +779 -158
- package/dist/index.js +674 -127
- package/dist/index.js.map +1 -1
- package/dist/react-types.d.ts +1 -1
- package/dist/registry.d.ts +18 -18
- package/dist/schemas/index.d.ts +1 -1
- package/dist/schemas/index.js +1 -1
- package/dist/test-utils.d.ts +1 -1
- package/package.json +1 -1
- package/src/agent-format.test.ts +1 -0
- package/src/canonical-bridge.ts +46 -0
- package/src/canonical-direction.ts +118 -0
- package/src/codes/codes.ts +18 -0
- package/src/conform.ts +5 -0
- package/src/contract/preimage.test.ts +40 -0
- package/src/contract/preimage.ts +20 -0
- package/src/effective-governance-inputs.test.ts +52 -0
- package/src/effective-governance-inputs.ts +106 -0
- package/src/facts/builders.ts +70 -2
- package/src/facts/compile.ts +20 -2
- package/src/facts/fact-index.ts +4 -0
- package/src/facts/facts.test.ts +30 -0
- package/src/facts/index.ts +6 -0
- package/src/facts/types.ts +86 -7
- package/src/governance-integrity.test.ts +22 -0
- package/src/governance-integrity.ts +10 -4
- package/src/governance.test.ts +93 -0
- package/src/governance.ts +76 -0
- package/src/identity/classify.test.ts +185 -0
- package/src/identity/classify.ts +257 -0
- package/src/identity/component-key.test.ts +32 -0
- package/src/identity/component-key.ts +35 -0
- package/src/identity/usage.ts +39 -0
- package/src/index.ts +48 -0
- package/src/rules/__tests__/fix-emission-invariant.test.ts +35 -4
- package/src/rules/components-prefer-library.test.ts +151 -0
- package/src/rules/components-prefer-library.ts +46 -4
- package/src/rules/components-shadow-component.test.ts +145 -0
- package/src/rules/components-shadow-component.ts +81 -0
- package/src/rules/fix-availability.ts +2 -0
- package/src/rules/index.ts +14 -0
- package/src/rules/jsx-preferred-import-path.ts +45 -9
- package/src/rules/rules.test.ts +202 -6
- package/src/rules/spacing-resolution.ts +2 -2
- package/src/rules/styles-no-raw-color.test.ts +6 -1
- package/src/rules/styles-no-raw-color.ts +3 -2
- package/src/rules/styles-no-raw-dimensions.ts +5 -7
- package/src/rules/styles-no-raw-spacing.ts +5 -2
- package/src/rules/styles-no-raw-typography.ts +7 -4
- package/src/rules/taxonomy.test.ts +19 -1
- package/src/rules/tiers.ts +9 -5
- package/src/rules/token-candidates.ts +36 -0
- package/src/rules/tokens-require-dual-fallback.ts +2 -1
- package/src/rules/tokens-upstream-drift.test.ts +111 -0
- package/src/rules/tokens-upstream-drift.ts +57 -0
- package/src/rules/utils.ts +22 -14
- package/src/schema.ts +28 -0
- package/src/schemas/index.ts +5 -8
- package/src/token-types.ts +71 -1
- package/src/types.ts +18 -0
- package/dist/chunk-57QDBEHQ.js.map +0 -1
- package/dist/chunk-CBSNXFOD.js.map +0 -1
package/dist/react-types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ComponentType, ReactNode, JSX } from 'react';
|
|
2
|
-
export { F as FragmentDefinition, a as FragmentDefinitionV2 } from './governance-
|
|
2
|
+
export { F as FragmentDefinition, a as FragmentDefinitionV2 } from './governance-B88uR3Zq.js';
|
|
3
3
|
import 'zod';
|
|
4
4
|
import './topology/index.js';
|
|
5
5
|
import './types-xJ2xyp_G.js';
|
package/dist/registry.d.ts
CHANGED
|
@@ -216,7 +216,7 @@ declare const registryComponentSchema: z.ZodObject<{
|
|
|
216
216
|
componentId: string;
|
|
217
217
|
name: string;
|
|
218
218
|
publicRef: string;
|
|
219
|
-
tier: "
|
|
219
|
+
tier: "core" | "custom" | "utility" | "composition";
|
|
220
220
|
examples: unknown[];
|
|
221
221
|
files: {
|
|
222
222
|
path: string;
|
|
@@ -264,7 +264,7 @@ declare const registryComponentSchema: z.ZodObject<{
|
|
|
264
264
|
provenance?: Record<string, unknown> | undefined;
|
|
265
265
|
category?: string | undefined;
|
|
266
266
|
contract?: unknown;
|
|
267
|
-
tier?: "
|
|
267
|
+
tier?: "core" | "custom" | "utility" | "composition" | undefined;
|
|
268
268
|
examples?: unknown[] | undefined;
|
|
269
269
|
styleFiles?: string[] | undefined;
|
|
270
270
|
tokenDependencies?: string[] | undefined;
|
|
@@ -498,7 +498,7 @@ declare const registryManifestDraftSchema: z.ZodObject<{
|
|
|
498
498
|
componentId: string;
|
|
499
499
|
name: string;
|
|
500
500
|
publicRef: string;
|
|
501
|
-
tier: "
|
|
501
|
+
tier: "core" | "custom" | "utility" | "composition";
|
|
502
502
|
examples: unknown[];
|
|
503
503
|
files: {
|
|
504
504
|
path: string;
|
|
@@ -546,7 +546,7 @@ declare const registryManifestDraftSchema: z.ZodObject<{
|
|
|
546
546
|
provenance?: Record<string, unknown> | undefined;
|
|
547
547
|
category?: string | undefined;
|
|
548
548
|
contract?: unknown;
|
|
549
|
-
tier?: "
|
|
549
|
+
tier?: "core" | "custom" | "utility" | "composition" | undefined;
|
|
550
550
|
examples?: unknown[] | undefined;
|
|
551
551
|
styleFiles?: string[] | undefined;
|
|
552
552
|
tokenDependencies?: string[] | undefined;
|
|
@@ -611,7 +611,7 @@ declare const registryManifestDraftSchema: z.ZodObject<{
|
|
|
611
611
|
componentId: string;
|
|
612
612
|
name: string;
|
|
613
613
|
publicRef: string;
|
|
614
|
-
tier: "
|
|
614
|
+
tier: "core" | "custom" | "utility" | "composition";
|
|
615
615
|
examples: unknown[];
|
|
616
616
|
files: {
|
|
617
617
|
path: string;
|
|
@@ -713,7 +713,7 @@ declare const registryManifestDraftSchema: z.ZodObject<{
|
|
|
713
713
|
provenance?: Record<string, unknown> | undefined;
|
|
714
714
|
category?: string | undefined;
|
|
715
715
|
contract?: unknown;
|
|
716
|
-
tier?: "
|
|
716
|
+
tier?: "core" | "custom" | "utility" | "composition" | undefined;
|
|
717
717
|
examples?: unknown[] | undefined;
|
|
718
718
|
styleFiles?: string[] | undefined;
|
|
719
719
|
tokenDependencies?: string[] | undefined;
|
|
@@ -971,7 +971,7 @@ declare const registryManifestSchema: z.ZodObject<{
|
|
|
971
971
|
componentId: string;
|
|
972
972
|
name: string;
|
|
973
973
|
publicRef: string;
|
|
974
|
-
tier: "
|
|
974
|
+
tier: "core" | "custom" | "utility" | "composition";
|
|
975
975
|
examples: unknown[];
|
|
976
976
|
files: {
|
|
977
977
|
path: string;
|
|
@@ -1019,7 +1019,7 @@ declare const registryManifestSchema: z.ZodObject<{
|
|
|
1019
1019
|
provenance?: Record<string, unknown> | undefined;
|
|
1020
1020
|
category?: string | undefined;
|
|
1021
1021
|
contract?: unknown;
|
|
1022
|
-
tier?: "
|
|
1022
|
+
tier?: "core" | "custom" | "utility" | "composition" | undefined;
|
|
1023
1023
|
examples?: unknown[] | undefined;
|
|
1024
1024
|
styleFiles?: string[] | undefined;
|
|
1025
1025
|
tokenDependencies?: string[] | undefined;
|
|
@@ -1086,7 +1086,7 @@ declare const registryManifestSchema: z.ZodObject<{
|
|
|
1086
1086
|
componentId: string;
|
|
1087
1087
|
name: string;
|
|
1088
1088
|
publicRef: string;
|
|
1089
|
-
tier: "
|
|
1089
|
+
tier: "core" | "custom" | "utility" | "composition";
|
|
1090
1090
|
examples: unknown[];
|
|
1091
1091
|
files: {
|
|
1092
1092
|
path: string;
|
|
@@ -1189,7 +1189,7 @@ declare const registryManifestSchema: z.ZodObject<{
|
|
|
1189
1189
|
provenance?: Record<string, unknown> | undefined;
|
|
1190
1190
|
category?: string | undefined;
|
|
1191
1191
|
contract?: unknown;
|
|
1192
|
-
tier?: "
|
|
1192
|
+
tier?: "core" | "custom" | "utility" | "composition" | undefined;
|
|
1193
1193
|
examples?: unknown[] | undefined;
|
|
1194
1194
|
styleFiles?: string[] | undefined;
|
|
1195
1195
|
tokenDependencies?: string[] | undefined;
|
|
@@ -1450,7 +1450,7 @@ declare const registryArtifactSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1450
1450
|
componentId: string;
|
|
1451
1451
|
name: string;
|
|
1452
1452
|
publicRef: string;
|
|
1453
|
-
tier: "
|
|
1453
|
+
tier: "core" | "custom" | "utility" | "composition";
|
|
1454
1454
|
examples: unknown[];
|
|
1455
1455
|
files: {
|
|
1456
1456
|
path: string;
|
|
@@ -1498,7 +1498,7 @@ declare const registryArtifactSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1498
1498
|
provenance?: Record<string, unknown> | undefined;
|
|
1499
1499
|
category?: string | undefined;
|
|
1500
1500
|
contract?: unknown;
|
|
1501
|
-
tier?: "
|
|
1501
|
+
tier?: "core" | "custom" | "utility" | "composition" | undefined;
|
|
1502
1502
|
examples?: unknown[] | undefined;
|
|
1503
1503
|
styleFiles?: string[] | undefined;
|
|
1504
1504
|
tokenDependencies?: string[] | undefined;
|
|
@@ -1565,7 +1565,7 @@ declare const registryArtifactSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1565
1565
|
componentId: string;
|
|
1566
1566
|
name: string;
|
|
1567
1567
|
publicRef: string;
|
|
1568
|
-
tier: "
|
|
1568
|
+
tier: "core" | "custom" | "utility" | "composition";
|
|
1569
1569
|
examples: unknown[];
|
|
1570
1570
|
files: {
|
|
1571
1571
|
path: string;
|
|
@@ -1668,7 +1668,7 @@ declare const registryArtifactSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1668
1668
|
provenance?: Record<string, unknown> | undefined;
|
|
1669
1669
|
category?: string | undefined;
|
|
1670
1670
|
contract?: unknown;
|
|
1671
|
-
tier?: "
|
|
1671
|
+
tier?: "core" | "custom" | "utility" | "composition" | undefined;
|
|
1672
1672
|
examples?: unknown[] | undefined;
|
|
1673
1673
|
styleFiles?: string[] | undefined;
|
|
1674
1674
|
tokenDependencies?: string[] | undefined;
|
|
@@ -1773,7 +1773,7 @@ declare const registryArtifactSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1773
1773
|
componentId: string;
|
|
1774
1774
|
name: string;
|
|
1775
1775
|
publicRef: string;
|
|
1776
|
-
tier: "
|
|
1776
|
+
tier: "core" | "custom" | "utility" | "composition";
|
|
1777
1777
|
examples: unknown[];
|
|
1778
1778
|
files: {
|
|
1779
1779
|
path: string;
|
|
@@ -1886,7 +1886,7 @@ declare const registryArtifactSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1886
1886
|
provenance?: Record<string, unknown> | undefined;
|
|
1887
1887
|
category?: string | undefined;
|
|
1888
1888
|
contract?: unknown;
|
|
1889
|
-
tier?: "
|
|
1889
|
+
tier?: "core" | "custom" | "utility" | "composition" | undefined;
|
|
1890
1890
|
examples?: unknown[] | undefined;
|
|
1891
1891
|
styleFiles?: string[] | undefined;
|
|
1892
1892
|
tokenDependencies?: string[] | undefined;
|
|
@@ -1979,7 +1979,7 @@ declare const registryArtifactSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1979
1979
|
componentId: string;
|
|
1980
1980
|
name: string;
|
|
1981
1981
|
publicRef: string;
|
|
1982
|
-
tier: "
|
|
1982
|
+
tier: "core" | "custom" | "utility" | "composition";
|
|
1983
1983
|
examples: unknown[];
|
|
1984
1984
|
files: {
|
|
1985
1985
|
path: string;
|
|
@@ -2092,7 +2092,7 @@ declare const registryArtifactSchema: z.ZodEffects<z.ZodObject<{
|
|
|
2092
2092
|
provenance?: Record<string, unknown> | undefined;
|
|
2093
2093
|
category?: string | undefined;
|
|
2094
2094
|
contract?: unknown;
|
|
2095
|
-
tier?: "
|
|
2095
|
+
tier?: "core" | "custom" | "utility" | "composition" | undefined;
|
|
2096
2096
|
examples?: unknown[] | undefined;
|
|
2097
2097
|
styleFiles?: string[] | undefined;
|
|
2098
2098
|
tokenDependencies?: string[] | undefined;
|
package/dist/schemas/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import 'zod';
|
|
2
2
|
export { LegacySeverityLevel, Severity, SeverityLevel, legacySeverityLevelSchema, severityLevelSchema, severitySchema } from '../severity.js';
|
|
3
|
-
export { b as AGENT_FORMAT_SCHEMA_VERSION, c as AgentErrorEnvelope, A as AgentFormat, d as AgentOutput, Q as FactEvidence, R as FactLocation, F as Finding, a as FindingFix, f as FindingReplaceClassTokenFix, g as FindingReplaceComponentFix, h as FindingReplaceImportFix, i as FindingReplacePropValueFix, j as FindingReplaceStyleValueFix, k as Fix, G as GovernanceVerdict, l as GovernanceVerdictMetadata, S as SuppressionDirective, V as ValidatorResult, n as Violation, o as agentErrorEnvelopeSchema, T as agentFindingSchema, p as agentFormatSchema, q as agentIntegritySchema, r as agentOutputSchema, U as agentPlanSchema, t as factEvidenceSchema, u as factLocationSchema, v as findingFixSchema, w as findingReplaceClassTokenFixSchema, x as findingReplaceComponentFixSchema, y as findingReplaceImportFixSchema, z as findingReplacePropValueFixSchema, B as findingReplaceStyleValueFixSchema, C as findingSchema, D as fixSchema, H as governanceVerdictMetadataSchema, J as governanceVerdictSchema, K as normalizeFinding, L as normalizeSeverity, M as normalizeViolation, N as suppressionDirectiveSchema, O as validatorResultSchema, P as violationSchema } from '../index-
|
|
3
|
+
export { b as AGENT_FORMAT_SCHEMA_VERSION, c as AgentErrorEnvelope, A as AgentFormat, d as AgentOutput, Q as FactEvidence, R as FactLocation, F as Finding, a as FindingFix, f as FindingReplaceClassTokenFix, g as FindingReplaceComponentFix, h as FindingReplaceImportFix, i as FindingReplacePropValueFix, j as FindingReplaceStyleValueFix, k as Fix, G as GovernanceVerdict, l as GovernanceVerdictMetadata, S as SuppressionDirective, V as ValidatorResult, n as Violation, o as agentErrorEnvelopeSchema, T as agentFindingSchema, p as agentFormatSchema, q as agentIntegritySchema, r as agentOutputSchema, U as agentPlanSchema, t as factEvidenceSchema, u as factLocationSchema, v as findingFixSchema, w as findingReplaceClassTokenFixSchema, x as findingReplaceComponentFixSchema, y as findingReplaceImportFixSchema, z as findingReplacePropValueFixSchema, B as findingReplaceStyleValueFixSchema, C as findingSchema, D as fixSchema, H as governanceVerdictMetadataSchema, J as governanceVerdictSchema, K as normalizeFinding, L as normalizeSeverity, M as normalizeViolation, N as suppressionDirectiveSchema, O as validatorResultSchema, P as violationSchema } from '../index-DbkPE46t.js';
|
package/dist/schemas/index.js
CHANGED
package/dist/test-utils.d.ts
CHANGED
package/package.json
CHANGED
package/src/agent-format.test.ts
CHANGED
|
@@ -232,6 +232,7 @@ describe("buildAgentFormat", () => {
|
|
|
232
232
|
scope: { method: "full", gitOk: true },
|
|
233
233
|
engineVersion: `sha256:${"b".repeat(64)}`,
|
|
234
234
|
scopeHash: "c".repeat(64),
|
|
235
|
+
inputsHash: "e".repeat(64),
|
|
235
236
|
inputFilesHash: "d".repeat(64),
|
|
236
237
|
},
|
|
237
238
|
verdict: { exitCode: 0, reasons: [], gatingFindingCount: 0 },
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { ContractCanonicalMappingInput } from "./contract/preimage.js";
|
|
2
|
+
import type { CanonicalBridgeV1 } from "./governance.js";
|
|
3
|
+
import { ownedImportMatchesRoot } from "./package-identity-match.js";
|
|
4
|
+
|
|
5
|
+
export function canonicalBridgeUnderlyingKey(input: {
|
|
6
|
+
packageName: string;
|
|
7
|
+
exportName: string;
|
|
8
|
+
}): string {
|
|
9
|
+
return `${input.packageName}\u0000${input.exportName}`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function canonicalBridgeContractMappings(
|
|
13
|
+
bridges: readonly CanonicalBridgeV1[] | undefined
|
|
14
|
+
): ContractCanonicalMappingInput[] {
|
|
15
|
+
return (bridges ?? []).map((bridge) => ({
|
|
16
|
+
component: `${bridge.underlying.packageName}#${bridge.underlying.exportName}`,
|
|
17
|
+
canonical: bridge.local.componentKey,
|
|
18
|
+
status: "confirmed",
|
|
19
|
+
importPath: bridge.local.moduleSpecifier,
|
|
20
|
+
bridge: {
|
|
21
|
+
underlyingPackageName: bridge.underlying.packageName,
|
|
22
|
+
underlyingExportName: bridge.underlying.exportName,
|
|
23
|
+
localComponentKey: bridge.local.componentKey,
|
|
24
|
+
localExportName: bridge.local.exportName,
|
|
25
|
+
implementationFiles: [...bridge.local.implementationFiles],
|
|
26
|
+
decisionSource: bridge.decision.source,
|
|
27
|
+
},
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function canonicalBridgeMatchesUnderlyingImport(
|
|
32
|
+
bridge: CanonicalBridgeV1,
|
|
33
|
+
source: string,
|
|
34
|
+
imported: string
|
|
35
|
+
): boolean {
|
|
36
|
+
if (!ownedImportMatchesRoot(source, bridge.underlying.packageName)) return false;
|
|
37
|
+
if (source === bridge.underlying.packageName) {
|
|
38
|
+
return imported === bridge.underlying.exportName;
|
|
39
|
+
}
|
|
40
|
+
const subpath = source.slice(bridge.underlying.packageName.length + 1);
|
|
41
|
+
const leaf = subpath.split("/").at(-1);
|
|
42
|
+
return (
|
|
43
|
+
leaf === bridge.underlying.exportName &&
|
|
44
|
+
(imported === "default" || imported === bridge.underlying.exportName)
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import type { CanonicalSource } from "./governance.js";
|
|
2
|
+
import type { FactIndex } from "./facts/index.js";
|
|
3
|
+
import { ownedImportMatchesRoot } from "./package-identity-match.js";
|
|
4
|
+
|
|
5
|
+
export interface CanonicalDirectionConflict {
|
|
6
|
+
packageName: string;
|
|
7
|
+
exportName: string;
|
|
8
|
+
wrapperComponentKey: string;
|
|
9
|
+
wrapperFile: string;
|
|
10
|
+
wrapperExportName: string;
|
|
11
|
+
state: "unresolved" | "sanctioned";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Project exact, source-backed conflicts between an exported local wrapper and
|
|
16
|
+
* an npm canonical export. Name similarity, prop overlap, and mixed render
|
|
17
|
+
* trees are deliberately insufficient: this projection can deactivate policy.
|
|
18
|
+
*/
|
|
19
|
+
export function projectCanonicalDirectionConflicts(
|
|
20
|
+
ix: FactIndex,
|
|
21
|
+
canonicalSources: readonly CanonicalSource[]
|
|
22
|
+
): CanonicalDirectionConflict[] {
|
|
23
|
+
const npmSources = canonicalSources.filter(
|
|
24
|
+
(source): source is Extract<CanonicalSource, { kind: "npm" }> => source.kind === "npm"
|
|
25
|
+
);
|
|
26
|
+
if (npmSources.length === 0) return [];
|
|
27
|
+
|
|
28
|
+
const identityByComponent = new Map(
|
|
29
|
+
ix.byKind("component_identity").map((identity) => [identity.componentKey, identity])
|
|
30
|
+
);
|
|
31
|
+
const conflicts: CanonicalDirectionConflict[] = [];
|
|
32
|
+
|
|
33
|
+
for (const definition of ix.byKind("component_definition")) {
|
|
34
|
+
if (!definition.exported || definition.renderRoot.resolution !== "canonical") continue;
|
|
35
|
+
const target = npmTarget(definition.renderRoot.canonical, npmSources);
|
|
36
|
+
if (!target) continue;
|
|
37
|
+
|
|
38
|
+
const identity = identityByComponent.get(definition.componentKey);
|
|
39
|
+
if (
|
|
40
|
+
identity?.decisionId &&
|
|
41
|
+
decisionTargetsExport(identity.canonicalTarget, target.exportName)
|
|
42
|
+
) {
|
|
43
|
+
if (identity.state === "shadow") continue;
|
|
44
|
+
if (identity.state === "variant" && identity.confidence === "confirmed") {
|
|
45
|
+
conflicts.push({
|
|
46
|
+
...target,
|
|
47
|
+
wrapperComponentKey: definition.componentKey,
|
|
48
|
+
wrapperFile: definition.file,
|
|
49
|
+
wrapperExportName: definition.exportName,
|
|
50
|
+
state: "sanctioned",
|
|
51
|
+
});
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
conflicts.push({
|
|
57
|
+
...target,
|
|
58
|
+
wrapperComponentKey: definition.componentKey,
|
|
59
|
+
wrapperFile: definition.file,
|
|
60
|
+
wrapperExportName: definition.exportName,
|
|
61
|
+
state: "unresolved",
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return conflicts.sort(
|
|
66
|
+
(left, right) =>
|
|
67
|
+
left.packageName.localeCompare(right.packageName) ||
|
|
68
|
+
left.exportName.localeCompare(right.exportName) ||
|
|
69
|
+
left.wrapperComponentKey.localeCompare(right.wrapperComponentKey)
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function canonicalDirectionConflictsTarget(
|
|
74
|
+
conflicts: readonly CanonicalDirectionConflict[],
|
|
75
|
+
importPath: string | undefined,
|
|
76
|
+
exportName: string
|
|
77
|
+
): boolean {
|
|
78
|
+
if (!importPath) return false;
|
|
79
|
+
return conflicts.some(
|
|
80
|
+
(conflict) =>
|
|
81
|
+
ownedImportMatchesRoot(importPath, conflict.packageName) && conflict.exportName === exportName
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function npmTarget(
|
|
86
|
+
canonicalTarget: string,
|
|
87
|
+
sources: readonly Extract<CanonicalSource, { kind: "npm" }>[]
|
|
88
|
+
): { packageName: string; exportName: string } | null {
|
|
89
|
+
const separator = canonicalTarget.lastIndexOf("#");
|
|
90
|
+
if (separator <= 0 || separator === canonicalTarget.length - 1) return null;
|
|
91
|
+
const importPath = canonicalTarget.slice(0, separator);
|
|
92
|
+
const imported = canonicalTarget
|
|
93
|
+
.slice(separator + 1)
|
|
94
|
+
.split(".")
|
|
95
|
+
.at(-1);
|
|
96
|
+
if (!imported) return null;
|
|
97
|
+
|
|
98
|
+
for (const source of sources) {
|
|
99
|
+
if (!ownedImportMatchesRoot(importPath, source.specifier)) continue;
|
|
100
|
+
const subpath = packageSubpath(importPath, source.specifier);
|
|
101
|
+
const exportName =
|
|
102
|
+
imported === "default" ? subpath.split("/").filter(Boolean).at(-1) : imported;
|
|
103
|
+
if (!exportName) continue;
|
|
104
|
+
if (source.exclude?.includes(exportName)) continue;
|
|
105
|
+
if (source.include && !source.include.includes(exportName)) continue;
|
|
106
|
+
return { packageName: source.specifier, exportName };
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function packageSubpath(importPath: string, packageName: string): string {
|
|
112
|
+
return importPath === packageName ? "" : importPath.slice(packageName.length + 1);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function decisionTargetsExport(target: string | undefined, exportName: string): boolean {
|
|
116
|
+
if (!target) return true;
|
|
117
|
+
return target === exportName || target.split("#").at(-1)?.split(".").at(-1) === exportName;
|
|
118
|
+
}
|
package/src/codes/codes.ts
CHANGED
|
@@ -108,6 +108,15 @@ export const CODES = [
|
|
|
108
108
|
fixAvailable: false,
|
|
109
109
|
evidenceRequired: true,
|
|
110
110
|
}),
|
|
111
|
+
ruleCode({
|
|
112
|
+
code: "FUI1007",
|
|
113
|
+
ruleId: "components/shadow-component",
|
|
114
|
+
category: "canonical-usage",
|
|
115
|
+
defaultSeverity: "moderate",
|
|
116
|
+
title: "Component shadows a canonical primitive",
|
|
117
|
+
lifecycle: "experimental",
|
|
118
|
+
evidenceRequired: true,
|
|
119
|
+
}),
|
|
111
120
|
code({
|
|
112
121
|
code: "FUI2001",
|
|
113
122
|
ruleId: "tokens/require-design-tokens",
|
|
@@ -255,6 +264,15 @@ export const CODES = [
|
|
|
255
264
|
lifecycle: "experimental",
|
|
256
265
|
evidenceRequired: true,
|
|
257
266
|
}),
|
|
267
|
+
ruleCode({
|
|
268
|
+
code: "FUI2017",
|
|
269
|
+
ruleId: "tokens/upstream-drift",
|
|
270
|
+
category: "tokens",
|
|
271
|
+
defaultSeverity: "moderate",
|
|
272
|
+
title: "Local token differs from its declared upstream source",
|
|
273
|
+
lifecycle: "experimental",
|
|
274
|
+
evidenceRequired: true,
|
|
275
|
+
}),
|
|
258
276
|
ruleCode({
|
|
259
277
|
code: "FUI3001",
|
|
260
278
|
ruleId: "a11y/required-accessible-name",
|
package/src/conform.ts
CHANGED
|
@@ -20,6 +20,11 @@ export interface ConformInput {
|
|
|
20
20
|
filename?: string;
|
|
21
21
|
/** deterministic (default) applies safe edits; none returns findings only. */
|
|
22
22
|
apply?: "deterministic" | "none";
|
|
23
|
+
/** Explicit request to consolidate a known shadow into its canonical root. */
|
|
24
|
+
shadowConsolidation?: {
|
|
25
|
+
shadow: string;
|
|
26
|
+
canonicalTarget?: string;
|
|
27
|
+
};
|
|
23
28
|
}
|
|
24
29
|
|
|
25
30
|
export interface ConformLocation {
|
|
@@ -162,6 +162,46 @@ describe("§3 proposed mappings are not identity", () => {
|
|
|
162
162
|
});
|
|
163
163
|
});
|
|
164
164
|
|
|
165
|
+
describe("confirmed canonical bridge identity", () => {
|
|
166
|
+
const bridgeMapping = {
|
|
167
|
+
component: "@mui/material#Button",
|
|
168
|
+
canonical: "src/components/Button.tsx#Button",
|
|
169
|
+
status: "confirmed" as const,
|
|
170
|
+
importPath: "@/components",
|
|
171
|
+
bridge: {
|
|
172
|
+
underlyingPackageName: "@mui/material",
|
|
173
|
+
underlyingExportName: "Button",
|
|
174
|
+
localComponentKey: "src/components/Button.tsx#Button",
|
|
175
|
+
localExportName: "Button",
|
|
176
|
+
implementationFiles: ["src/components/Button.tsx"],
|
|
177
|
+
decisionSource: "authored" as const,
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
it("moves only canonicalMap when enforcement changes, not when provenance changes", () => {
|
|
182
|
+
const base = projectContractPreimage({ canonicalMappings: [bridgeMapping] });
|
|
183
|
+
const changedEnforcement = projectContractPreimage({
|
|
184
|
+
canonicalMappings: [
|
|
185
|
+
{
|
|
186
|
+
...bridgeMapping,
|
|
187
|
+
bridge: { ...bridgeMapping.bridge, implementationFiles: ["src/ui/Button.tsx"] },
|
|
188
|
+
},
|
|
189
|
+
],
|
|
190
|
+
});
|
|
191
|
+
const changedProvenance = projectContractPreimage({
|
|
192
|
+
canonicalMappings: [
|
|
193
|
+
{
|
|
194
|
+
...bridgeMapping,
|
|
195
|
+
bridge: { ...bridgeMapping.bridge, decisionSource: "migration" as const },
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
expect(diffContractDomains(base, changedEnforcement)).toEqual(["canonicalMap"]);
|
|
201
|
+
expect(changedProvenance).toEqual(base);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
165
205
|
describe("§4 domain diff names what moved", () => {
|
|
166
206
|
it("confirming a mapping + adding a composition rule changes canonicalMap and policy", () => {
|
|
167
207
|
const preimageBase = projectContractPreimage(catalogFixtureA);
|
package/src/contract/preimage.ts
CHANGED
|
@@ -87,6 +87,15 @@ export interface ContractCanonicalMappingInput {
|
|
|
87
87
|
status: CanonicalMappingStatus;
|
|
88
88
|
/** Local/offline canonical import target, when the mapping is config-authored. */
|
|
89
89
|
importPath?: string;
|
|
90
|
+
/** Confirmed package-to-local relation metadata. Absent for legacy mappings. */
|
|
91
|
+
bridge?: {
|
|
92
|
+
underlyingPackageName: string;
|
|
93
|
+
underlyingExportName: string;
|
|
94
|
+
localComponentKey: string;
|
|
95
|
+
localExportName: string;
|
|
96
|
+
implementationFiles: readonly string[];
|
|
97
|
+
decisionSource: "authored" | "migration";
|
|
98
|
+
};
|
|
90
99
|
/** Explicit raw element or semantic resolutions covered by a local declaration. */
|
|
91
100
|
resolves?: readonly {
|
|
92
101
|
tag: string;
|
|
@@ -253,6 +262,17 @@ function projectCanonicalMap(
|
|
|
253
262
|
importPath: mapping.importPath
|
|
254
263
|
? projectV1OwnedImportIdentity(mapping.importPath)
|
|
255
264
|
: undefined,
|
|
265
|
+
bridge: mapping.bridge
|
|
266
|
+
? {
|
|
267
|
+
underlyingPackageName: projectV1OwnedImportIdentity(
|
|
268
|
+
mapping.bridge.underlyingPackageName
|
|
269
|
+
),
|
|
270
|
+
underlyingExportName: mapping.bridge.underlyingExportName,
|
|
271
|
+
localComponentKey: projectV1OwnedComponentId(mapping.bridge.localComponentKey),
|
|
272
|
+
localExportName: mapping.bridge.localExportName,
|
|
273
|
+
implementationFiles: [...mapping.bridge.implementationFiles].sort(),
|
|
274
|
+
}
|
|
275
|
+
: undefined,
|
|
256
276
|
resolves: mapping.resolves ? sortCanonical(mapping.resolves) : undefined,
|
|
257
277
|
propMapping: mapping.propMapping
|
|
258
278
|
? sortCanonical(
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { compileEffectiveGovernanceInputs } from "./effective-governance-inputs.js";
|
|
4
|
+
|
|
5
|
+
function fixture() {
|
|
6
|
+
return compileEffectiveGovernanceInputs({
|
|
7
|
+
policySource: "config",
|
|
8
|
+
configPath: "./fragments.config.ts",
|
|
9
|
+
configDigest: "a".repeat(64),
|
|
10
|
+
policy: {
|
|
11
|
+
canonicalBridges: [
|
|
12
|
+
{
|
|
13
|
+
underlying: { packageName: "@mui/material", exportName: "Button" },
|
|
14
|
+
local: {
|
|
15
|
+
componentKey: "src/components/Button.tsx#Button",
|
|
16
|
+
moduleSpecifier: "@/components/Button",
|
|
17
|
+
exportName: "Button",
|
|
18
|
+
implementationFiles: ["src/components/Button.tsx"],
|
|
19
|
+
},
|
|
20
|
+
decision: { state: "confirmed", source: "authored" },
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
componentDefinitionFiles: ["src/components/Button.tsx"],
|
|
25
|
+
tokens: { declared: [], loadedDefinitions: 0, diagnostics: [] },
|
|
26
|
+
eligibility: { include: ["src/**/*.tsx"], exclude: ["src/**/*.stories.tsx"] },
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe("compileEffectiveGovernanceInputs", () => {
|
|
31
|
+
it("normalizes operational inputs into a separate stable identity", () => {
|
|
32
|
+
const first = fixture();
|
|
33
|
+
const second = fixture();
|
|
34
|
+
expect(first).toEqual(second);
|
|
35
|
+
expect(first.inputsHash).toMatch(/^[a-f0-9]{64}$/u);
|
|
36
|
+
expect(first.config.path).toBe("fragments.config.ts");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("moves inputsHash for config/source state without changing contract identity here", () => {
|
|
40
|
+
const first = fixture();
|
|
41
|
+
const next = compileEffectiveGovernanceInputs({
|
|
42
|
+
policySource: first.policySource,
|
|
43
|
+
configPath: first.config.path,
|
|
44
|
+
configDigest: "b".repeat(64),
|
|
45
|
+
policy: { canonicalBridges: first.components.canonicalBridges },
|
|
46
|
+
componentDefinitionFiles: first.components.definitionFiles,
|
|
47
|
+
tokens: { declared: [], loadedDefinitions: 0, diagnostics: [] },
|
|
48
|
+
eligibility: first.eligibility,
|
|
49
|
+
});
|
|
50
|
+
expect(next.inputsHash).not.toBe(first.inputsHash);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { canonicalPreimage, contractHash } from "./contract/hash.js";
|
|
2
|
+
import type { GovernanceConfig } from "./governance.js";
|
|
3
|
+
import type { TokenCatalog } from "./token-types.js";
|
|
4
|
+
|
|
5
|
+
export const EFFECTIVE_GOVERNANCE_INPUTS_SCHEMA = "effective-governance-inputs:v1" as const;
|
|
6
|
+
|
|
7
|
+
export interface EffectiveGovernanceInputsSourceState {
|
|
8
|
+
declared: readonly string[];
|
|
9
|
+
loadedDefinitions: number;
|
|
10
|
+
diagnostics: readonly string[];
|
|
11
|
+
catalog?: TokenCatalog;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface CompileEffectiveGovernanceInputsOptions {
|
|
15
|
+
policySource: "config" | "preset" | "fallback" | "none";
|
|
16
|
+
configPath: string | null;
|
|
17
|
+
configDigest: string | null;
|
|
18
|
+
policy: GovernanceConfig | undefined;
|
|
19
|
+
componentDefinitionFiles: readonly string[];
|
|
20
|
+
tokens: EffectiveGovernanceInputsSourceState;
|
|
21
|
+
eligibility: {
|
|
22
|
+
include: readonly string[];
|
|
23
|
+
exclude: readonly string[];
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface EffectiveGovernanceInputs {
|
|
28
|
+
schema: typeof EFFECTIVE_GOVERNANCE_INPUTS_SCHEMA;
|
|
29
|
+
policySource: CompileEffectiveGovernanceInputsOptions["policySource"];
|
|
30
|
+
config: { path: string | null; digest: string | null };
|
|
31
|
+
components: {
|
|
32
|
+
canonicalSources: NonNullable<GovernanceConfig["canonicalSources"]>;
|
|
33
|
+
canonicalBridges: NonNullable<GovernanceConfig["canonicalBridges"]>;
|
|
34
|
+
definitionFiles: string[];
|
|
35
|
+
};
|
|
36
|
+
tokens: {
|
|
37
|
+
declared: string[];
|
|
38
|
+
loadedDefinitions: number;
|
|
39
|
+
diagnostics: string[];
|
|
40
|
+
catalog?: TokenCatalog;
|
|
41
|
+
};
|
|
42
|
+
eligibility: { include: string[]; exclude: string[] };
|
|
43
|
+
inputsHash: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Compile one deterministic, post-authority account of the operational inputs
|
|
48
|
+
* available to governance consumers. This is deliberately distinct from FCID
|
|
49
|
+
* (enforced contract identity) and scopeHash (the files selected for one Run).
|
|
50
|
+
*/
|
|
51
|
+
export function compileEffectiveGovernanceInputs(
|
|
52
|
+
options: CompileEffectiveGovernanceInputsOptions
|
|
53
|
+
): EffectiveGovernanceInputs {
|
|
54
|
+
const projection = {
|
|
55
|
+
schema: EFFECTIVE_GOVERNANCE_INPUTS_SCHEMA,
|
|
56
|
+
policySource: options.policySource,
|
|
57
|
+
config: {
|
|
58
|
+
path: options.configPath ? normalizePath(options.configPath) : null,
|
|
59
|
+
digest: options.configDigest,
|
|
60
|
+
},
|
|
61
|
+
components: {
|
|
62
|
+
canonicalSources: sortRecords(options.policy?.canonicalSources ?? []),
|
|
63
|
+
canonicalBridges: sortRecords(options.policy?.canonicalBridges ?? []),
|
|
64
|
+
definitionFiles: normalizePaths(options.componentDefinitionFiles),
|
|
65
|
+
},
|
|
66
|
+
tokens: {
|
|
67
|
+
declared: normalizePaths(options.tokens.declared),
|
|
68
|
+
loadedDefinitions: options.tokens.loadedDefinitions,
|
|
69
|
+
diagnostics: [...options.tokens.diagnostics].sort(),
|
|
70
|
+
...(options.tokens.catalog
|
|
71
|
+
? {
|
|
72
|
+
catalog: {
|
|
73
|
+
...options.tokens.catalog,
|
|
74
|
+
configuredSources: normalizePaths(options.tokens.catalog.configuredSources),
|
|
75
|
+
parsedSources: normalizePaths(options.tokens.catalog.parsedSources),
|
|
76
|
+
definitions: sortRecords(options.tokens.catalog.definitions),
|
|
77
|
+
diagnostics: sortRecords(options.tokens.catalog.diagnostics),
|
|
78
|
+
references: sortRecords(options.tokens.catalog.references),
|
|
79
|
+
...(options.tokens.catalog.sourceStates
|
|
80
|
+
? { sourceStates: sortRecords(options.tokens.catalog.sourceStates) }
|
|
81
|
+
: {}),
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
: {}),
|
|
85
|
+
},
|
|
86
|
+
eligibility: {
|
|
87
|
+
include: normalizePaths(options.eligibility.include),
|
|
88
|
+
exclude: normalizePaths(options.eligibility.exclude),
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
return { ...projection, inputsHash: contractHash(projection) };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function normalizePaths(values: readonly string[]): string[] {
|
|
95
|
+
return [...new Set(values.map(normalizePath))].sort();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function normalizePath(value: string): string {
|
|
99
|
+
return value.replace(/\\/gu, "/").replace(/^\.\//u, "");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function sortRecords<T>(values: readonly T[]): T[] {
|
|
103
|
+
return [...values].sort((left, right) =>
|
|
104
|
+
canonicalPreimage(left).localeCompare(canonicalPreimage(right))
|
|
105
|
+
);
|
|
106
|
+
}
|