@usefragments/core 1.11.0 → 2.0.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-3LLRNCPX.js → chunk-MZ2FS7U4.js} +1 -1
- package/dist/chunk-MZ2FS7U4.js.map +1 -0
- package/dist/{chunk-RPSEABY3.js → chunk-QPOKQ5H6.js} +30 -34
- package/dist/chunk-QPOKQ5H6.js.map +1 -0
- package/dist/codes/index.d.ts +1 -1
- package/dist/codes/index.js +1 -1
- package/dist/compiled-types/index.d.ts +1 -1
- package/dist/generate/index.d.ts +1 -1
- package/dist/{governance-BAsy1k2H.d.ts → governance-hOPXGbbs.d.ts} +3 -3
- package/dist/index.d.ts +145 -6026
- package/dist/index.js +298 -860
- package/dist/index.js.map +1 -1
- package/dist/preview-runtime.d.ts +1 -1
- package/dist/react-types.d.ts +1 -1
- package/dist/schemas/index.js +1 -1
- package/dist/storyAdapter.d.ts +1 -1
- package/dist/test-utils.d.ts +1 -1
- package/dist/topology/index.d.ts +1 -1
- package/dist/topology/index.js +1 -1
- package/package.json +1 -1
- package/src/approved-contract-tokens.test.ts +39 -0
- package/src/approved-contract-tokens.ts +18 -0
- package/src/canonical-source.ts +41 -0
- package/src/codes/__tests__/codes.test.ts +4 -0
- package/src/codes/codes.ts +10 -0
- package/src/domain-ids.test.ts +9 -26
- package/src/domain-ids.ts +0 -45
- package/src/evaluation/evaluate.ts +17 -7
- package/src/evaluation/evaluation-v2-receipt-v1.test.ts +20 -8
- package/src/evaluation/index.ts +1 -1
- package/src/facts/builders.ts +4 -0
- package/src/facts/fact-index.ts +4 -0
- package/src/facts/facts.test.ts +70 -0
- package/src/facts/types.ts +4 -0
- package/src/governance.ts +18 -0
- package/src/identity/usage.test.ts +64 -0
- package/src/identity/usage.ts +7 -1
- package/src/index.ts +15 -79
- package/src/rules/components-prefer-library.ts +110 -33
- package/src/topology/resolve-area.ts +1 -1
- package/src/types.ts +0 -3
- package/dist/chunk-3LLRNCPX.js.map +0 -1
- package/dist/chunk-RPSEABY3.js.map +0 -1
- package/src/feature-plan/digest.ts +0 -217
- package/src/feature-plan/feature-plan-v1.test.ts +0 -529
- package/src/feature-plan/index.ts +0 -65
- package/src/feature-plan/types.ts +0 -628
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/topology/resolve-area.ts"],"sourcesContent":["/**\n * Topology — map a repo-relative file path to its product area.\n *\n * This is the DRY keystone of the topology layer: the ONLY area-matching\n * implementation in the monorepo. Consumers (CLI scan, Cloud managed-editor\n * preview, cross-repo reconciliation) import it; none reimplements glob/area\n * logic. Pure and browser-safe — no Node, no parser deps.\n *\n * See `docs/fragments-v1/ARCHITECTURE.md §1`.\n */\n\nexport type AreaCriticality = \"low\" | \"medium\" | \"high\" | \"revenue\" | \"regulated\";\n\nexport interface Area {\n id: string;\n name: string;\n criticality: AreaCriticality;\n owners: string[];\n /** Globs matched against repo-relative file paths in v0. */\n files: string[];\n /** Stored for later route-topology adapters; NOT matched in v0. */\n routes?: string[];\n /** Tie-break: higher wins. Defaults to declaration order. */\n priority?: number;\n}\n\nexport interface Topology {\n /** Bump signals \"re-tag\" to consumers that cache. */\n version: number;\n /** Whether area file globs are matched relative to app.path or repo root. Defaults to \"app\". */\n base?: \"app\" | \"repo\";\n /** Array (not a keyed record) so precedence is deterministic. */\n areas: Area[];\n}\n\nexport interface AreaMatch {\n areaId: string;\n areaName: string;\n criticality: AreaCriticality;\n owners: string[];\n /** The winning pattern — surfaced in reports for transparency. */\n matchedGlob: string;\n}\n\n/**\n * Compile a minimal glob to an anchored RegExp. We intentionally do NOT depend\n * on picomatch: core stays lean, the surface we need is small, and we want\n * exact control over Next.js route-group parens (`(marketing)` is a literal\n * path segment here, not an extglob group).\n *\n * Semantics:\n * - `/**` at a segment boundary (end-of-glob or before `/`) → \"this directory\n * and everything under it\": the leading slash is optional, so\n * `src/app/checkout/**` matches `src/app/checkout` AND any descendant.\n * - a bare/leading `**` → matches across path separators (`.*`). Note a\n * leading globstar-then-slash does NOT match the root (use a lone `**`\n * for \"everything\").\n * - `*` → matches within a single segment (`[^/]*`)\n * - `?` → a single non-separator char\n * - `{a,b}` → alternation `(?:a|b)`\n * - every other regex-significant char (`.`, `(`, `)`, `+`, …) is literal\n *\n * Throws on a malformed pattern (e.g. an unbalanced `{`). Callers compile via\n * `compile()`, which catches the throw so a config typo degrades one glob to a\n * non-match instead of aborting the whole scan.\n */\nfunction globToRegExp(glob: string): RegExp {\n let out = \"\";\n let braceDepth = 0;\n let i = 0;\n while (i < glob.length) {\n const ch = glob[i];\n\n // `/**` at a segment boundary → optional slash + anything-below. Matches\n // the directory itself (`a/**` ⇒ `a`) and every descendant.\n if (\n ch === \"/\" &&\n glob[i + 1] === \"*\" &&\n glob[i + 2] === \"*\" &&\n (glob[i + 3] === undefined || glob[i + 3] === \"/\")\n ) {\n out += \"(?:/.*)?\";\n i += 3; // consume `/**`; a trailing `/` (in `a/**/b`) is handled next pass\n continue;\n }\n\n // Bare/leading globstar — crosses path separators.\n if (ch === \"*\" && glob[i + 1] === \"*\") {\n out += \".*\";\n i += 2;\n continue;\n }\n\n switch (ch) {\n case \"*\":\n out += \"[^/]*\"; // single segment\n break;\n case \"?\":\n out += \"[^/]\";\n break;\n case \"{\":\n braceDepth += 1;\n out += \"(?:\";\n break;\n case \"}\":\n if (braceDepth > 0) {\n braceDepth -= 1;\n out += \")\";\n } else {\n out += \"\\\\}\";\n }\n break;\n case \",\":\n out += braceDepth > 0 ? \"|\" : \",\";\n break;\n // Regex-significant chars kept literal (parens cover route groups).\n case \".\":\n case \"(\":\n case \")\":\n case \"+\":\n case \"^\":\n case \"$\":\n case \"|\":\n case \"[\":\n case \"]\":\n case \"\\\\\":\n out += `\\\\${ch}`;\n break;\n default:\n out += ch;\n }\n i += 1;\n }\n return new RegExp(`^${out}$`);\n}\n\ninterface CompiledArea {\n area: Area;\n matchers: { glob: string; re: RegExp }[];\n}\n\n/**\n * Cache compiled matchers per topology object. Consumers pass the same\n * `topology` for every finding in a run, so this turns N×globs recompiles into\n * one. A reloaded config is a new object → fresh entry, so `version` bumps need\n * no manual invalidation.\n */\nconst compiledCache = new WeakMap<Topology, CompiledArea[]>();\n\nfunction compile(topology: Topology): CompiledArea[] {\n const cached = compiledCache.get(topology);\n if (cached) return cached;\n\n // Order by (priority desc, declaration order). Decorate-sort-undecorate keeps\n // the sort stable across engines.\n const ordered = topology.areas\n .map((area, index) => ({ area, index }))\n .sort((a, b) => {\n const pa = a.area.priority ?? 0;\n const pb = b.area.priority ?? 0;\n if (pa !== pb) return pb - pa;\n return a.index - b.index;\n })\n .map(({ area }) => ({\n area,\n matchers: area.files.flatMap((glob) => {\n try {\n return [{ glob, re: globToRegExp(glob) }];\n } catch {\n // A malformed glob (e.g. unbalanced `{`) compiles to an invalid\n // RegExp. Skip it rather than aborting the entire scan — topology\n // config is user-authored, so one typo must not take down\n // `fragments check`. Its files simply fall through to \"Unassigned\".\n if (typeof console !== \"undefined\") {\n console.warn(\n `[topology] ignoring invalid glob in area \"${area.id}\": ${JSON.stringify(glob)}`\n );\n }\n return [];\n }\n }),\n }));\n\n compiledCache.set(topology, ordered);\n return ordered;\n}\n\n/** Normalize to a POSIX, repo-relative path before matching. */\nfunction normalizePath(repoRelPath: string): string {\n return repoRelPath.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\").replace(/^\\/+/, \"\");\n}\n\n/**\n * Resolve the product area for a repo-relative path. First match by\n * `(priority desc, declaration order)`. Returns `null` when nothing matches —\n * the caller buckets that as the explicit \"Unassigned\" area (never dropped;\n * dropping unmatched evidence would make coverage lie).\n */\nexport function resolveArea(repoRelPath: string, topology: Topology): AreaMatch | null {\n const path = normalizePath(repoRelPath);\n for (const { area, matchers } of compile(topology)) {\n for (const { glob, re } of matchers) {\n if (re.test(path)) {\n return {\n areaId: area.id,\n areaName: area.name,\n criticality: area.criticality,\n owners: area.owners,\n matchedGlob: glob,\n };\n }\n }\n }\n return null;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -571,6 +571,16 @@ var CODES = [
|
|
|
571
571
|
lifecycle: "experimental",
|
|
572
572
|
fixAvailable: false,
|
|
573
573
|
evidenceRequired: false
|
|
574
|
+
}),
|
|
575
|
+
code({
|
|
576
|
+
code: "FUI9012",
|
|
577
|
+
ruleId: "contract/write-not-entitled",
|
|
578
|
+
category: "system",
|
|
579
|
+
defaultSeverity: "critical",
|
|
580
|
+
title: "Contract write requires a paid workspace",
|
|
581
|
+
lifecycle: "experimental",
|
|
582
|
+
fixAvailable: false,
|
|
583
|
+
evidenceRequired: false
|
|
574
584
|
})
|
|
575
585
|
];
|
|
576
586
|
var byCode = new Map(
|
|
@@ -589,7 +599,6 @@ import { z as z2 } from "zod";
|
|
|
589
599
|
// src/domain-ids.ts
|
|
590
600
|
import { z } from "zod";
|
|
591
601
|
var FULL_DIGEST_PATTERN = /^[0-9a-f]{64}$/u;
|
|
592
|
-
var WORKFLOW_ENTROPY_PATTERN = /^[0-9a-f]{32}$/u;
|
|
593
602
|
var digestHexStringSchema = z.string().regex(FULL_DIGEST_PATTERN, "Expected 64 lowercase hexadecimal characters");
|
|
594
603
|
var digestHexSchema = digestHexStringSchema;
|
|
595
604
|
var analysisPlanIdStringSchema = z.string().regex(/^apl_[0-9a-f]{64}$/u, "Invalid analysis plan ID");
|
|
@@ -598,14 +607,6 @@ var analysisPlanIdSchema = analysisPlanIdStringSchema.transform(
|
|
|
598
607
|
);
|
|
599
608
|
var evaluationReceiptIdSchema = z.string().regex(/^evr_[0-9a-f]{64}$/u, "Invalid evaluation receipt ID").transform((value) => value);
|
|
600
609
|
var evaluationReceiptIdStringSchema = z.string().regex(/^evr_[0-9a-f]{64}$/u, "Invalid evaluation receipt ID");
|
|
601
|
-
var featurePlanIdStringSchema = z.string().regex(/^fpl_[0-9a-f]{32}$/u, "Invalid feature plan ID");
|
|
602
|
-
var featurePlanIdSchema = featurePlanIdStringSchema.transform(
|
|
603
|
-
(value) => value
|
|
604
|
-
);
|
|
605
|
-
var featureRevisionIdStringSchema = z.string().regex(/^fpr_[0-9a-f]{64}$/u, "Invalid feature revision ID");
|
|
606
|
-
var featureRevisionIdSchema = featureRevisionIdStringSchema.transform(
|
|
607
|
-
(value) => value
|
|
608
|
-
);
|
|
609
610
|
function parseDigestHex(value) {
|
|
610
611
|
return digestHexSchema.parse(value);
|
|
611
612
|
}
|
|
@@ -618,27 +619,12 @@ function evaluationReceiptIdFromDigest(digest) {
|
|
|
618
619
|
function mintEvaluationReceiptId(resultDigest) {
|
|
619
620
|
return evaluationReceiptIdFromDigest(resultDigest);
|
|
620
621
|
}
|
|
621
|
-
function featureRevisionIdFromDigest(digest) {
|
|
622
|
-
return featureRevisionIdSchema.parse(`fpr_${parseDigestHex(digest)}`);
|
|
623
|
-
}
|
|
624
|
-
function featurePlanIdFromEntropy(entropyHex) {
|
|
625
|
-
if (!WORKFLOW_ENTROPY_PATTERN.test(entropyHex)) {
|
|
626
|
-
throw new TypeError("Feature plan entropy must be exactly 128-bit lowercase hexadecimal");
|
|
627
|
-
}
|
|
628
|
-
return featurePlanIdSchema.parse(`fpl_${entropyHex}`);
|
|
629
|
-
}
|
|
630
622
|
function parseAnalysisPlanId(value) {
|
|
631
623
|
return analysisPlanIdSchema.parse(value);
|
|
632
624
|
}
|
|
633
625
|
function parseEvaluationReceiptId(value) {
|
|
634
626
|
return evaluationReceiptIdSchema.parse(value);
|
|
635
627
|
}
|
|
636
|
-
function parseFeaturePlanId(value) {
|
|
637
|
-
return featurePlanIdSchema.parse(value);
|
|
638
|
-
}
|
|
639
|
-
function parseFeatureRevisionId(value) {
|
|
640
|
-
return featureRevisionIdSchema.parse(value);
|
|
641
|
-
}
|
|
642
628
|
|
|
643
629
|
// src/facts/integrity.ts
|
|
644
630
|
var CANONICAL_FACT_MAX_CONFLICTS_V1 = 1e3;
|
|
@@ -875,6 +861,7 @@ function makeComponentDefinitionFact(input) {
|
|
|
875
861
|
componentKey: input.componentKey,
|
|
876
862
|
renderRoot: input.renderRoot,
|
|
877
863
|
propSurface: [...input.propSurface],
|
|
864
|
+
...input.location ? { location: { ...input.location } } : {},
|
|
878
865
|
...input.stylingChannel ? { stylingChannel: { ...input.stylingChannel } } : {}
|
|
879
866
|
};
|
|
880
867
|
}
|
|
@@ -1218,7 +1205,8 @@ function makeUsageComponentFact(input) {
|
|
|
1218
1205
|
}),
|
|
1219
1206
|
kind: "usage_component",
|
|
1220
1207
|
nodeId: input.nodeId,
|
|
1221
|
-
componentId: input.componentId
|
|
1208
|
+
componentId: input.componentId,
|
|
1209
|
+
...input.definitionKey ? { definitionKey: input.definitionKey } : {}
|
|
1222
1210
|
};
|
|
1223
1211
|
}
|
|
1224
1212
|
function makeUsageImportFact(input) {
|
|
@@ -1438,6 +1426,10 @@ function logicalFactForComparison(fact) {
|
|
|
1438
1426
|
const { location: _location, sourceNames: _sourceNames, ...logicalFact } = fact;
|
|
1439
1427
|
return logicalFact;
|
|
1440
1428
|
}
|
|
1429
|
+
if (fact.kind === "component_definition") {
|
|
1430
|
+
const { location: _location, ...logicalFact } = fact;
|
|
1431
|
+
return { ...logicalFact, componentId: logicalComponentId(fact.componentId) };
|
|
1432
|
+
}
|
|
1441
1433
|
if (fact.kind === "jsx_import_path_preferred") {
|
|
1442
1434
|
return {
|
|
1443
1435
|
...fact,
|
|
@@ -1900,6 +1892,17 @@ var componentGovernanceRecordSchema = z4.discriminatedUnion("kind", [
|
|
|
1900
1892
|
a11yRequireNameRecordSchema
|
|
1901
1893
|
]);
|
|
1902
1894
|
var componentGovernanceRecordsSchema = z4.array(componentGovernanceRecordSchema);
|
|
1895
|
+
function parseComponentGovernancePolicyJson(policyJson) {
|
|
1896
|
+
try {
|
|
1897
|
+
const parsed = JSON.parse(policyJson);
|
|
1898
|
+
const record = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
1899
|
+
const candidate = Array.isArray(parsed) ? parsed : record?.governance ?? record?.rules;
|
|
1900
|
+
const result = componentGovernanceRecordsSchema.safeParse(candidate);
|
|
1901
|
+
return result.success ? result.data : null;
|
|
1902
|
+
} catch {
|
|
1903
|
+
return null;
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1903
1906
|
var componentPolicyMatchSchema = z4.object({
|
|
1904
1907
|
componentKey: z4.string().min(1).optional(),
|
|
1905
1908
|
componentId: z4.string().min(1).optional(),
|
|
@@ -3061,20 +3064,12 @@ export {
|
|
|
3061
3064
|
analysisPlanIdSchema,
|
|
3062
3065
|
evaluationReceiptIdSchema,
|
|
3063
3066
|
evaluationReceiptIdStringSchema,
|
|
3064
|
-
featurePlanIdStringSchema,
|
|
3065
|
-
featurePlanIdSchema,
|
|
3066
|
-
featureRevisionIdStringSchema,
|
|
3067
|
-
featureRevisionIdSchema,
|
|
3068
3067
|
parseDigestHex,
|
|
3069
3068
|
analysisPlanIdFromDigest,
|
|
3070
3069
|
evaluationReceiptIdFromDigest,
|
|
3071
3070
|
mintEvaluationReceiptId,
|
|
3072
|
-
featureRevisionIdFromDigest,
|
|
3073
|
-
featurePlanIdFromEntropy,
|
|
3074
3071
|
parseAnalysisPlanId,
|
|
3075
3072
|
parseEvaluationReceiptId,
|
|
3076
|
-
parseFeaturePlanId,
|
|
3077
|
-
parseFeatureRevisionId,
|
|
3078
3073
|
CANONICAL_FACT_MAX_CONFLICTS_V1,
|
|
3079
3074
|
CANONICAL_FACT_MAX_VALUES_PER_CONFLICT_V1,
|
|
3080
3075
|
CANONICAL_FACT_MAX_PROVENANCE_PER_VALUE_V1,
|
|
@@ -3147,6 +3142,7 @@ export {
|
|
|
3147
3142
|
globalGovernanceRecordSchema,
|
|
3148
3143
|
componentGovernanceRecordSchema,
|
|
3149
3144
|
componentGovernanceRecordsSchema,
|
|
3145
|
+
parseComponentGovernancePolicyJson,
|
|
3150
3146
|
canonicalBridgeV1Schema,
|
|
3151
3147
|
governanceConfigSchema,
|
|
3152
3148
|
markPresetSourcedRules,
|
|
@@ -3190,4 +3186,4 @@ export {
|
|
|
3190
3186
|
normalizeFinding,
|
|
3191
3187
|
normalizeViolation
|
|
3192
3188
|
};
|
|
3193
|
-
//# sourceMappingURL=chunk-
|
|
3189
|
+
//# sourceMappingURL=chunk-QPOKQ5H6.js.map
|