project-tiny-context-harness 0.8.4 → 0.8.6
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/LICENSE +21 -21
- package/README.md +394 -363
- package/assets/README.md +570 -514
- package/assets/README.zh-CN.md +331 -300
- package/assets/agents/.gitkeep +1 -1
- package/assets/agents/AGENTS_CORE.md +45 -25
- package/assets/context_templates/architecture.md +26 -25
- package/assets/context_templates/area.md +32 -31
- package/assets/context_templates/context.toml +30 -24
- package/assets/context_templates/deployment.md +35 -35
- package/assets/context_templates/global.md +57 -57
- package/assets/context_templates/product-surface-contract.md +70 -70
- package/assets/context_templates/screen-contract.md +189 -189
- package/assets/context_templates/verification.md +31 -30
- package/assets/github/.gitkeep +1 -1
- package/assets/github/harness.yml +39 -39
- package/assets/make/.gitkeep +1 -1
- package/assets/make/ty-context.mk +48 -48
- package/assets/skills/context_development_engineer/SKILL.md +155 -122
- package/assets/skills/context_full_project_export/SKILL.md +28 -28
- package/assets/skills/context_harness_upgrade/SKILL.md +60 -60
- package/assets/skills/context_product_plan/SKILL.md +99 -79
- package/assets/skills/context_surface_contract/SKILL.md +191 -191
- package/assets/skills/context_uiux_design/SKILL.md +171 -171
- package/assets/skills/design-resource-authoring/SKILL.md +86 -84
- package/assets/skills/design-resource-authoring/references/downstream-handoff.md +138 -123
- package/assets/skills/design-resource-authoring/references/open-design-provider.md +132 -127
- package/assets/skills/design-resource-authoring/references/resource-selection.md +181 -154
- package/assets/skills/design-system-authoring/SKILL.md +57 -57
- package/assets/skills/design-system-authoring/agents/openai.yaml +6 -6
- package/assets/skills/design-system-authoring/references/authority-adoption.md +48 -48
- package/assets/skills/design-system-authoring/references/open-design-design-system-provider.md +110 -110
- package/assets/skills/long-task-workflow/SKILL.md +98 -92
- package/assets/skills/long-task-workflow/agents/openai.yaml +3 -1
- package/assets/skills/long-task-workflow/references/authority-lifecycle.md +72 -72
- package/assets/skills/long-task-workflow/references/contract-authoring.md +122 -101
- package/assets/skills/long-task-workflow/references/evidence-design.md +82 -61
- package/assets/skills/long-task-workflow/references/source-authoring.md +109 -90
- package/assets/skills/source-plan-authoring/SKILL.md +14 -14
- package/assets/tools/validate_context.py +442 -442
- package/dist/commands/long-task-authoring.js +27 -2
- package/dist/lib/context-default-footprint.js +2 -0
- package/dist/lib/context-manifest.js +6 -0
- package/dist/lib/context-templates.js +1 -1
- package/dist/lib/design-resource-fact-enums.d.ts +20 -0
- package/dist/lib/design-resource-fact-enums.js +170 -0
- package/dist/lib/design-resource-fact-locator-extractors.d.ts +8 -0
- package/dist/lib/design-resource-fact-locator-extractors.js +108 -0
- package/dist/lib/design-resource-fact-locator-resolver.d.ts +3 -0
- package/dist/lib/design-resource-fact-locator-resolver.js +112 -0
- package/dist/lib/design-resource-fact-locator-validation.d.ts +5 -0
- package/dist/lib/design-resource-fact-locator-validation.js +16 -0
- package/dist/lib/design-resource-fact-manifest-catalog.d.ts +4 -0
- package/dist/lib/design-resource-fact-manifest-catalog.js +249 -0
- package/dist/lib/design-resource-fact-manifest-model.d.ts +91 -0
- package/dist/lib/design-resource-fact-manifest-model.js +21 -0
- package/dist/lib/design-resource-fact-manifest-shape-axes.d.ts +6 -0
- package/dist/lib/design-resource-fact-manifest-shape-axes.js +159 -0
- package/dist/lib/design-resource-fact-manifest-shape-evidence.d.ts +4 -0
- package/dist/lib/design-resource-fact-manifest-shape-evidence.js +59 -0
- package/dist/lib/design-resource-fact-manifest-shape-facts.d.ts +4 -0
- package/dist/lib/design-resource-fact-manifest-shape-facts.js +109 -0
- package/dist/lib/design-resource-fact-manifest-shape-inspector.d.ts +5 -0
- package/dist/lib/design-resource-fact-manifest-shape-inspector.js +144 -0
- package/dist/lib/design-resource-fact-manifest-shape.d.ts +7 -0
- package/dist/lib/design-resource-fact-manifest-shape.js +75 -0
- package/dist/lib/design-resource-fact-manifest-types.d.ts +3 -0
- package/dist/lib/design-resource-fact-manifest-types.js +3 -0
- package/dist/lib/design-resource-fact-manifest-universe.d.ts +5 -0
- package/dist/lib/design-resource-fact-manifest-universe.js +50 -0
- package/dist/lib/design-resource-fact-manifest-validation.d.ts +3 -0
- package/dist/lib/design-resource-fact-manifest-validation.js +106 -0
- package/dist/lib/design-resource-fact-policy.d.ts +18 -0
- package/dist/lib/design-resource-fact-policy.js +72 -1
- package/dist/lib/design-resource-fact-property-methods.d.ts +3 -0
- package/dist/lib/design-resource-fact-property-methods.js +158 -0
- package/dist/lib/design-resource-fact-shape-primitives.d.ts +3 -0
- package/dist/lib/design-resource-fact-shape-primitives.js +18 -0
- package/dist/lib/design-resource-fact-types.d.ts +164 -0
- package/dist/lib/design-resource-fact-types.js +1 -0
- package/dist/lib/design-resource-fact-universe-assets.d.ts +4 -0
- package/dist/lib/design-resource-fact-universe-assets.js +71 -0
- package/dist/lib/design-resource-fact-universe-catalog.d.ts +4 -0
- package/dist/lib/design-resource-fact-universe-catalog.js +151 -0
- package/dist/lib/design-resource-fact-universe-conditions.d.ts +2 -0
- package/dist/lib/design-resource-fact-universe-conditions.js +92 -0
- package/dist/lib/design-resource-fact-universe-facts.d.ts +4 -0
- package/dist/lib/design-resource-fact-universe-facts.js +108 -0
- package/dist/lib/design-resource-fact-universe-helpers.d.ts +30 -0
- package/dist/lib/design-resource-fact-universe-helpers.js +167 -0
- package/dist/lib/design-resource-fact-universe-inspector.d.ts +7 -0
- package/dist/lib/design-resource-fact-universe-inspector.js +119 -0
- package/dist/lib/design-resource-fact-universe-proof.d.ts +4 -0
- package/dist/lib/design-resource-fact-universe-proof.js +113 -0
- package/dist/lib/design-resource-fact-universe-subjects.d.ts +5 -0
- package/dist/lib/design-resource-fact-universe-subjects.js +97 -0
- package/dist/lib/design-resource-fact-universe-variations.d.ts +2 -0
- package/dist/lib/design-resource-fact-universe-variations.js +75 -0
- package/dist/lib/design-resource-fact-value-validation.d.ts +2 -0
- package/dist/lib/design-resource-fact-value-validation.js +80 -0
- package/dist/lib/design-resource-handoff-file-primitives.js +2 -0
- package/dist/lib/design-resource-handoff-file-validation.js +13 -100
- package/dist/lib/design-resource-handoff-policy.d.ts +1 -0
- package/dist/lib/design-resource-handoff-policy.js +118 -11
- package/dist/lib/design-resource-handoff-shape-evidence.js +46 -3
- package/dist/lib/design-resource-handoff-shape-primitives.d.ts +5 -0
- package/dist/lib/design-resource-handoff-shape-primitives.js +28 -0
- package/dist/lib/design-resource-handoff-shape-structure.js +143 -22
- package/dist/lib/design-resource-handoff-shape.js +25 -0
- package/dist/lib/design-resource-handoff-types.d.ts +97 -21
- package/dist/lib/design-resource-handoff-types.js +22 -0
- package/dist/lib/design-resource-handoff-validation-coverage.d.ts +1 -1
- package/dist/lib/design-resource-handoff-validation-coverage.js +145 -118
- package/dist/lib/design-resource-handoff-validation-fact-cells.d.ts +2 -0
- package/dist/lib/design-resource-handoff-validation-fact-cells.js +60 -0
- package/dist/lib/design-resource-handoff-validation-fact-records.d.ts +2 -0
- package/dist/lib/design-resource-handoff-validation-fact-records.js +90 -0
- package/dist/lib/design-resource-handoff-validation-facts.js +10 -94
- package/dist/lib/design-resource-handoff-validation-proofs.d.ts +2 -0
- package/dist/lib/design-resource-handoff-validation-proofs.js +67 -0
- package/dist/lib/design-resource-handoff-validation-resource-closure.d.ts +3 -0
- package/dist/lib/design-resource-handoff-validation-resource-closure.js +88 -0
- package/dist/lib/design-resource-handoff-validation-structure.js +43 -14
- package/dist/lib/design-resource-handoff-validation.js +32 -0
- package/dist/lib/design-resource-handoff-web-dependency-validation.d.ts +2 -1
- package/dist/lib/design-resource-handoff-web-dependency-validation.js +67 -7
- package/dist/lib/execution-target-capabilities.d.ts +1 -1
- package/dist/lib/execution-target-capabilities.js +14 -0
- package/dist/lib/long-task-activation-validation.js +6 -2
- package/dist/lib/long-task-applicability-shape.js +3 -3
- package/dist/lib/long-task-authoring-authority-preview.js +1 -0
- package/dist/lib/long-task-authority-policy.d.ts +1 -0
- package/dist/lib/long-task-authority-policy.js +1 -0
- package/dist/lib/long-task-authority.js +13 -0
- package/dist/lib/long-task-claim-definitions.js +13 -1
- package/dist/lib/long-task-claims.js +23 -1
- package/dist/lib/long-task-contract-types.d.ts +3 -0
- package/dist/lib/long-task-delivery-compiler.js +1 -0
- package/dist/lib/long-task-delivery-parser.js +11 -1
- package/dist/lib/long-task-delivery-types.d.ts +1 -0
- package/dist/lib/long-task-delivery-types.js +1 -0
- package/dist/lib/long-task-delivery-validation.js +17 -0
- package/dist/lib/long-task-design-resource-handoff.js +62 -38
- package/dist/lib/long-task-design-target-capabilities.d.ts +14 -0
- package/dist/lib/long-task-design-target-capabilities.js +126 -0
- package/dist/lib/long-task-evidence-capability-codec.d.ts +94 -0
- package/dist/lib/long-task-evidence-capability-codec.js +395 -22
- package/dist/lib/long-task-evidence-capability-policy.js +18 -0
- package/dist/lib/long-task-evidence-capability-runtime.js +78 -0
- package/dist/lib/long-task-evidence-capability-types.d.ts +114 -1
- package/dist/lib/long-task-outcome-parser.js +4 -0
- package/dist/lib/long-task-playwright-capability-records.d.ts +5 -0
- package/dist/lib/long-task-playwright-capability-records.js +146 -0
- package/dist/lib/long-task-playwright-case-evidence.d.ts +3 -2
- package/dist/lib/long-task-playwright-case-evidence.js +10 -79
- package/dist/lib/long-task-playwright-case-primitives.d.ts +28 -0
- package/dist/lib/long-task-playwright-case-primitives.js +143 -0
- package/dist/lib/long-task-playwright-evidence.d.ts +1 -1
- package/dist/lib/long-task-playwright-evidence.js +10 -75
- package/dist/lib/long-task-runner-freeze.d.ts +2 -2
- package/dist/lib/long-task-runner-freeze.js +15 -1
- package/dist/lib/long-task-runtime-types.d.ts +4 -1
- package/dist/lib/long-task-semantic-contract-types.d.ts +1 -1
- package/dist/lib/long-task-semantic-drift-migration.js +2 -2
- package/dist/lib/long-task-semantic-fact-binding-types.d.ts +57 -0
- package/dist/lib/long-task-semantic-fact-binding-types.js +1 -0
- package/dist/lib/long-task-semantic-fact-closure-primitives.d.ts +5 -0
- package/dist/lib/long-task-semantic-fact-closure-primitives.js +43 -0
- package/dist/lib/long-task-semantic-fact-closure.d.ts +13 -0
- package/dist/lib/long-task-semantic-fact-closure.js +48 -0
- package/dist/lib/long-task-semantic-fact-contract-closure.d.ts +4 -0
- package/dist/lib/long-task-semantic-fact-contract-closure.js +24 -0
- package/dist/lib/long-task-semantic-fact-contract-facts.d.ts +4 -0
- package/dist/lib/long-task-semantic-fact-contract-facts.js +30 -0
- package/dist/lib/long-task-semantic-fact-contract-proofs.d.ts +4 -0
- package/dist/lib/long-task-semantic-fact-contract-proofs.js +97 -0
- package/dist/lib/long-task-semantic-fact-evidence.d.ts +21 -0
- package/dist/lib/long-task-semantic-fact-evidence.js +165 -0
- package/dist/lib/long-task-semantic-fact-input-closure.d.ts +4 -0
- package/dist/lib/long-task-semantic-fact-input-closure.js +101 -0
- package/dist/lib/long-task-semantic-fact-provenance-closure.d.ts +4 -0
- package/dist/lib/long-task-semantic-fact-provenance-closure.js +140 -0
- package/dist/lib/long-task-semantic-fact-shape.d.ts +3 -0
- package/dist/lib/long-task-semantic-fact-shape.js +89 -0
- package/dist/lib/long-task-semantic-fact-value-closure.d.ts +3 -0
- package/dist/lib/long-task-semantic-fact-value-closure.js +110 -0
- package/dist/lib/long-task-shape-primitives.d.ts +2 -1
- package/dist/lib/long-task-shape-primitives.js +7 -0
- package/dist/lib/long-task-source-item-parser.js +25 -6
- package/dist/lib/long-task-source-target-continuity.js +4 -1
- package/dist/lib/long-task-source-target-index.d.ts +1 -1
- package/dist/lib/long-task-source-target-index.js +5 -1
- package/dist/lib/long-task-ui-design-policy.js +8 -4
- package/dist/lib/long-task-ui-surface-shape.js +83 -1
- package/dist/lib/long-task-ui-surface-types.d.ts +29 -0
- package/dist/lib/modularity.js +7 -1
- package/dist/lib/semantic-fact-base-types.d.ts +14 -0
- package/dist/lib/semantic-fact-base-types.js +1 -0
- package/dist/lib/semantic-fact-catalog.d.ts +8 -0
- package/dist/lib/semantic-fact-catalog.js +191 -0
- package/dist/lib/semantic-fact-condition-shape.d.ts +48 -0
- package/dist/lib/semantic-fact-condition-shape.js +111 -0
- package/dist/lib/semantic-fact-input-shape.d.ts +34 -0
- package/dist/lib/semantic-fact-input-shape.js +111 -0
- package/dist/lib/semantic-fact-inventory-types.d.ts +147 -0
- package/dist/lib/semantic-fact-inventory-types.js +1 -0
- package/dist/lib/semantic-fact-manifest-shape.d.ts +4 -0
- package/dist/lib/semantic-fact-manifest-shape.js +135 -0
- package/dist/lib/semantic-fact-manifest-types.d.ts +58 -0
- package/dist/lib/semantic-fact-manifest-types.js +19 -0
- package/dist/lib/semantic-fact-policy-authority.d.ts +8 -0
- package/dist/lib/semantic-fact-policy-authority.js +79 -0
- package/dist/lib/semantic-fact-policy-census.d.ts +2 -0
- package/dist/lib/semantic-fact-policy-census.js +80 -0
- package/dist/lib/semantic-fact-policy-condition-references.d.ts +7 -0
- package/dist/lib/semantic-fact-policy-condition-references.js +19 -0
- package/dist/lib/semantic-fact-policy-conditions.d.ts +2 -0
- package/dist/lib/semantic-fact-policy-conditions.js +105 -0
- package/dist/lib/semantic-fact-policy-facts.d.ts +3 -0
- package/dist/lib/semantic-fact-policy-facts.js +73 -0
- package/dist/lib/semantic-fact-policy-primitives.d.ts +26 -0
- package/dist/lib/semantic-fact-policy-primitives.js +169 -0
- package/dist/lib/semantic-fact-policy-proofs.d.ts +2 -0
- package/dist/lib/semantic-fact-policy-proofs.js +75 -0
- package/dist/lib/semantic-fact-policy-properties.d.ts +3 -0
- package/dist/lib/semantic-fact-policy-properties.js +84 -0
- package/dist/lib/semantic-fact-policy-units.d.ts +4 -0
- package/dist/lib/semantic-fact-policy-units.js +103 -0
- package/dist/lib/semantic-fact-policy.d.ts +17 -0
- package/dist/lib/semantic-fact-policy.js +41 -0
- package/dist/lib/semantic-fact-proof-shape.d.ts +51 -0
- package/dist/lib/semantic-fact-proof-shape.js +121 -0
- package/dist/lib/semantic-fact-proof-types.d.ts +74 -0
- package/dist/lib/semantic-fact-proof-types.js +1 -0
- package/dist/lib/semantic-fact-property-shape.d.ts +29 -0
- package/dist/lib/semantic-fact-property-shape.js +77 -0
- package/dist/lib/semantic-fact-shape-constants.d.ts +3 -0
- package/dist/lib/semantic-fact-shape-constants.js +38 -0
- package/dist/lib/semantic-fact-shape-primitives.d.ts +15 -0
- package/dist/lib/semantic-fact-shape-primitives.js +68 -0
- package/dist/lib/semantic-fact-source-parser.d.ts +9 -0
- package/dist/lib/semantic-fact-source-parser.js +46 -0
- package/dist/lib/semantic-fact-support-shape.d.ts +21 -0
- package/dist/lib/semantic-fact-support-shape.js +59 -0
- package/dist/lib/semantic-fact-types.d.ts +5 -0
- package/dist/lib/semantic-fact-types.js +5 -0
- package/dist/lib/semantic-fact-unit-shape.d.ts +34 -0
- package/dist/lib/semantic-fact-unit-shape.js +89 -0
- package/dist/lib/semantic-fact-value-shape.d.ts +12 -0
- package/dist/lib/semantic-fact-value-shape.js +39 -0
- package/dist/schemas/long-task-delivery-v2/long-task-delivery-v2.schema.json +1339 -131
- package/migrations/README.md +15 -15
- package/package.json +84 -84
- package/source-mappings.yaml +25 -25
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { DESIGN_RESOURCE_STANDARD_PROPERTIES, DESIGN_RESOURCE_STANDARD_PROPERTY_BY_KEY, } from "./design-resource-fact-manifest-catalog.js";
|
|
2
|
+
import { designFactMethodIsCompatible } from "./design-resource-fact-policy.js";
|
|
3
|
+
import { factCellFingerprint, invalid, nonempty, refsKnown, sameSet, sameSetValue, unique, validateBasis, } from "./design-resource-fact-universe-helpers.js";
|
|
4
|
+
export function validateManifestPropertyCatalog(manifest, census) {
|
|
5
|
+
const properties = new Map(manifest.properties.map((property) => [property.key, property]));
|
|
6
|
+
for (const standard of DESIGN_RESOURCE_STANDARD_PROPERTIES) {
|
|
7
|
+
const actual = properties.get(standard.key);
|
|
8
|
+
if (!actual)
|
|
9
|
+
invalid("manifest_standard_property_missing", standard.key);
|
|
10
|
+
if (!actual.standard ||
|
|
11
|
+
actual.family !== standard.family ||
|
|
12
|
+
actual.dimension !== standard.dimension ||
|
|
13
|
+
actual.value_kind !== standard.value_kind ||
|
|
14
|
+
!sameSetValue(actual.required_methods, standard.required_methods) ||
|
|
15
|
+
!sameSetValue(actual.inspector_capability_refs, standard.inspector_capability_refs))
|
|
16
|
+
invalid("manifest_standard_property_definition_mismatch", standard.key);
|
|
17
|
+
}
|
|
18
|
+
for (const property of manifest.properties)
|
|
19
|
+
validateProperty(property, manifest, census);
|
|
20
|
+
}
|
|
21
|
+
function validateProperty(property, manifest, census) {
|
|
22
|
+
unique(property.required_methods, `manifest_property_required_method_duplicate:${property.key}`);
|
|
23
|
+
nonempty(property.required_methods, `manifest_property_required_method_required:${property.key}`);
|
|
24
|
+
for (const method of property.required_methods)
|
|
25
|
+
if (!designFactMethodIsCompatible(property.dimension, method))
|
|
26
|
+
invalid("manifest_property_required_method_incompatible", `${property.key}:${property.dimension}:${method}`);
|
|
27
|
+
unique(property.inspector_capability_refs, `manifest_property_capability_duplicate:${property.key}`);
|
|
28
|
+
nonempty(property.inspector_capability_refs, `manifest_property_capability_required:${property.key}`);
|
|
29
|
+
for (const capability of property.inspector_capability_refs)
|
|
30
|
+
if (!manifest.inspector.capability_refs.includes(capability))
|
|
31
|
+
invalid("manifest_inspector_property_capability_missing", `${property.key}:${capability}`);
|
|
32
|
+
if (property.standard) {
|
|
33
|
+
if (!DESIGN_RESOURCE_STANDARD_PROPERTY_BY_KEY.has(property.key))
|
|
34
|
+
invalid("manifest_unknown_standard_property", property.key);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
if (!property.key.startsWith("custom."))
|
|
38
|
+
invalid("manifest_custom_property_namespace_required", property.key);
|
|
39
|
+
nonempty(property.census_refs, `manifest_custom_property_census_required:${property.key}`);
|
|
40
|
+
}
|
|
41
|
+
refsKnown(property.census_refs, census, "manifest_property_census_unknown", property.key);
|
|
42
|
+
}
|
|
43
|
+
export function validateManifestCensusOwnership(manifest) {
|
|
44
|
+
const ownership = censusOwnershipSets(manifest);
|
|
45
|
+
for (const entry of manifest.inspector.census) {
|
|
46
|
+
if (entry.disposition !== "covered")
|
|
47
|
+
continue;
|
|
48
|
+
if (!censusEntryHasOwner(entry, ownership))
|
|
49
|
+
invalid("manifest_census_semantic_owner_missing", `${entry.key}:${entry.kind}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function censusOwnershipSets(manifest) {
|
|
53
|
+
return {
|
|
54
|
+
inspectorInputs: new Set(manifest.inspector.input_resources.map((item) => item.resource_ref)),
|
|
55
|
+
subject: new Set(manifest.subjects.flatMap((subject) => subject.census_refs)),
|
|
56
|
+
condition: new Set(manifest.axis_dispositions.flatMap((axis) => axis.values.flatMap((value) => value.census_refs))),
|
|
57
|
+
variation: new Set(manifest.variation_axis_dispositions.flatMap((axis) => axis.values.flatMap((value) => value.census_refs))),
|
|
58
|
+
property: new Set(manifest.properties.flatMap((property) => property.census_refs)),
|
|
59
|
+
lineage: new Set(manifest.lineage_nodes.flatMap((node) => node.census_refs)),
|
|
60
|
+
dynamic: new Set(manifest.subjects.flatMap((subject) => [subject.presence_rule_ref, subject.population_ref].filter((ref) => ref !== null))),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function censusEntryHasOwner(entry, sets) {
|
|
64
|
+
if (entry.kind === "resource")
|
|
65
|
+
return sets.inspectorInputs.has(entry.resource_ref);
|
|
66
|
+
if (entry.kind === "node")
|
|
67
|
+
return sets.subject.has(entry.key);
|
|
68
|
+
if (entry.kind === "declaration")
|
|
69
|
+
return [
|
|
70
|
+
sets.condition,
|
|
71
|
+
sets.variation,
|
|
72
|
+
sets.property,
|
|
73
|
+
sets.lineage,
|
|
74
|
+
sets.dynamic,
|
|
75
|
+
].some((set) => set.has(entry.key));
|
|
76
|
+
if (entry.kind === "variant" ||
|
|
77
|
+
entry.kind === "state" ||
|
|
78
|
+
entry.kind === "interaction_phase")
|
|
79
|
+
return sets.variation.has(entry.key) || sets.dynamic.has(entry.key);
|
|
80
|
+
if (entry.kind === "token")
|
|
81
|
+
return sets.lineage.has(entry.key);
|
|
82
|
+
if (entry.kind === "custom_property")
|
|
83
|
+
return sets.property.has(entry.key) || sets.lineage.has(entry.key);
|
|
84
|
+
if (entry.kind === "asset_reference" || entry.kind === "relation")
|
|
85
|
+
return sets.subject.has(entry.key) || sets.property.has(entry.key);
|
|
86
|
+
return entry.kind === "dynamic_population" && sets.dynamic.has(entry.key);
|
|
87
|
+
}
|
|
88
|
+
export function validateManifestFactCells(manifest, sourceItems, census) {
|
|
89
|
+
const subjects = new Map(manifest.subjects.map((subject) => [subject.key, subject]));
|
|
90
|
+
const conditions = new Set(manifest.conditions.map((item) => item.key));
|
|
91
|
+
const variations = new Map(manifest.variations.map((item) => [item.key, item]));
|
|
92
|
+
const properties = new Set(manifest.properties.map((item) => item.key));
|
|
93
|
+
const actual = new Map();
|
|
94
|
+
const coveredFacts = [];
|
|
95
|
+
for (const cell of manifest.fact_cells) {
|
|
96
|
+
validateFactCellReferences(cell, manifest, subjects, conditions, variations, properties);
|
|
97
|
+
validateBasis(cell, sourceItems, census, `manifest_fact_cell:${cell.key}`);
|
|
98
|
+
const fingerprint = factCellFingerprint(cell);
|
|
99
|
+
if (actual.has(fingerprint))
|
|
100
|
+
invalid("manifest_fact_cell_duplicate", `${actual.get(fingerprint)}:${cell.key}`);
|
|
101
|
+
actual.set(fingerprint, cell.key);
|
|
102
|
+
validateFactCellDisposition(cell, coveredFacts);
|
|
103
|
+
}
|
|
104
|
+
sameSet([...actual.keys()], expectedFactCellFingerprints(manifest), "manifest_expected_fact_cell_universe_mismatch", manifest.target_key);
|
|
105
|
+
unique(coveredFacts, "manifest_fact_ref_reused_by_cells");
|
|
106
|
+
sameSet(coveredFacts, manifest.facts.map((fact) => fact.key), "manifest_expected_canonical_fact_set_mismatch", manifest.target_key);
|
|
107
|
+
}
|
|
108
|
+
function validateFactCellReferences(cell, manifest, subjects, conditions, variations, properties) {
|
|
109
|
+
const subject = subjects.get(cell.subject_ref);
|
|
110
|
+
const variation = variations.get(cell.variation_ref);
|
|
111
|
+
if (!subject)
|
|
112
|
+
invalid("manifest_fact_cell_subject_unknown", cell.key);
|
|
113
|
+
if (!subject.target_refs.includes(cell.target_ref))
|
|
114
|
+
invalid("manifest_fact_cell_target_outside_subject", cell.key);
|
|
115
|
+
if (cell.target_ref !== manifest.target_key)
|
|
116
|
+
invalid("manifest_fact_cell_target_mismatch", cell.key);
|
|
117
|
+
if (!conditions.has(cell.condition_ref))
|
|
118
|
+
invalid("manifest_fact_cell_condition_unknown", cell.key);
|
|
119
|
+
if (!variation || variation.subject_ref !== cell.subject_ref)
|
|
120
|
+
invalid("manifest_fact_cell_variation_mismatch", cell.key);
|
|
121
|
+
if (!properties.has(cell.property_ref))
|
|
122
|
+
invalid("manifest_fact_cell_property_unknown", cell.key);
|
|
123
|
+
}
|
|
124
|
+
function validateFactCellDisposition(cell, coveredFacts) {
|
|
125
|
+
if (cell.disposition === "covered") {
|
|
126
|
+
if (cell.fact_ref === null)
|
|
127
|
+
invalid("manifest_covered_fact_ref_required", cell.key);
|
|
128
|
+
coveredFacts.push(cell.fact_ref);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (cell.fact_ref !== null)
|
|
132
|
+
invalid("manifest_noncovered_fact_ref_forbidden", cell.key);
|
|
133
|
+
if (cell.disposition === "decision_required" ||
|
|
134
|
+
cell.disposition === "unavailable")
|
|
135
|
+
invalid("manifest_fact_cell_unresolved", cell.key);
|
|
136
|
+
}
|
|
137
|
+
function expectedFactCellFingerprints(manifest) {
|
|
138
|
+
const expected = [];
|
|
139
|
+
for (const subject of manifest.subjects)
|
|
140
|
+
for (const condition of manifest.conditions)
|
|
141
|
+
for (const variation of manifest.variations.filter((item) => item.subject_ref === subject.key))
|
|
142
|
+
for (const property of manifest.properties)
|
|
143
|
+
expected.push(factCellFingerprint({
|
|
144
|
+
subject_ref: subject.key,
|
|
145
|
+
target_ref: manifest.target_key,
|
|
146
|
+
condition_ref: condition.key,
|
|
147
|
+
variation_ref: variation.key,
|
|
148
|
+
property_ref: property.key,
|
|
149
|
+
}));
|
|
150
|
+
return expected;
|
|
151
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { type DesignResourceObservableFactManifestV1 } from "./design-resource-fact-manifest-types.js";
|
|
2
|
+
export declare function validateManifestConditionUniverse(manifest: DesignResourceObservableFactManifestV1, census: Map<string, DesignResourceObservableFactManifestV1["inspector"]["census"][number]>, sourceItems: Map<string, string>): void;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { DESIGN_RESOURCE_STANDARD_CONDITION_AXES, } from "./design-resource-fact-manifest-types.js";
|
|
2
|
+
import { axisFingerprint, cartesian, conditionAxisValue, exactAxisPairs, invalid, nonempty, refsKnown, sameSet, unique, validateBasis, } from "./design-resource-fact-universe-helpers.js";
|
|
3
|
+
export function validateManifestConditionUniverse(manifest, census, sourceItems) {
|
|
4
|
+
const axes = manifest.axis_dispositions;
|
|
5
|
+
const byAxis = new Map(axes.map((axis) => [axis.axis, axis]));
|
|
6
|
+
for (const axis of DESIGN_RESOURCE_STANDARD_CONDITION_AXES)
|
|
7
|
+
if (!byAxis.has(axis))
|
|
8
|
+
invalid("manifest_standard_axis_missing", axis);
|
|
9
|
+
unique(axes.map((axis) => axis.axis), "manifest_axis_duplicate");
|
|
10
|
+
for (const axis of axes)
|
|
11
|
+
validateAxis(axis, manifest, census, sourceItems);
|
|
12
|
+
const fingerprints = validateConditions(manifest, axes, byAxis);
|
|
13
|
+
const excluded = validateConditionExclusions(manifest, axes, byAxis, fingerprints, census, sourceItems);
|
|
14
|
+
const expected = cartesian(axes.map((axis) => axis.values.map((value) => [axis.axis, value.key]))).map(axisFingerprint);
|
|
15
|
+
sameSet([...fingerprints.keys(), ...excluded.keys()], expected, "manifest_condition_universe_mismatch", manifest.target_key);
|
|
16
|
+
}
|
|
17
|
+
function validateAxis(axis, manifest, census, sourceItems) {
|
|
18
|
+
if (axis.target_ref !== manifest.target_key)
|
|
19
|
+
invalid("manifest_axis_target_mismatch", `${axis.key}:${axis.target_ref}:${manifest.target_key}`);
|
|
20
|
+
validateBasis(axis, sourceItems, census, `manifest_axis:${axis.key}`);
|
|
21
|
+
nonempty(axis.values, `manifest_axis_values_required:${axis.key}`);
|
|
22
|
+
unique(axis.values.map((value) => value.key), `manifest_axis_value_duplicate:${axis.key}`);
|
|
23
|
+
if (axis.disposition === "not_applicable" &&
|
|
24
|
+
(axis.values.length !== 1 || axis.values[0].key !== "not-applicable"))
|
|
25
|
+
invalid("manifest_axis_not_applicable_value_invalid", axis.key);
|
|
26
|
+
if (axis.disposition === "applicable" &&
|
|
27
|
+
axis.values.some((value) => value.key === "not-applicable"))
|
|
28
|
+
invalid("manifest_axis_applicable_value_invalid", axis.key);
|
|
29
|
+
for (const value of axis.values) {
|
|
30
|
+
if (axis.disposition === "applicable")
|
|
31
|
+
nonempty(value.census_refs, `manifest_axis_value_census_required:${axis.key}:${value.key}`);
|
|
32
|
+
refsKnown(value.census_refs, census, "manifest_axis_value_census_unknown", `${axis.key}:${value.key}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function validateConditions(manifest, axes, byAxis) {
|
|
36
|
+
const fingerprints = new Map();
|
|
37
|
+
const profileByAxisValue = new Map();
|
|
38
|
+
for (const condition of manifest.conditions) {
|
|
39
|
+
const values = axes.map((axis) => [axis.axis, conditionAxisValue(condition, axis.axis)]);
|
|
40
|
+
for (const [axis, value] of values)
|
|
41
|
+
if (!byAxis.get(axis).values.some((candidate) => candidate.key === value))
|
|
42
|
+
invalid("manifest_condition_axis_value_unknown", `${condition.key}:${axis}:${value}`);
|
|
43
|
+
const fingerprint = axisFingerprint(values);
|
|
44
|
+
if (fingerprints.has(fingerprint))
|
|
45
|
+
invalid("manifest_condition_combination_duplicate", `${fingerprints.get(fingerprint)}:${condition.key}`);
|
|
46
|
+
fingerprints.set(fingerprint, condition.key);
|
|
47
|
+
validateConditionProfiles(condition, profileByAxisValue);
|
|
48
|
+
}
|
|
49
|
+
return fingerprints;
|
|
50
|
+
}
|
|
51
|
+
function validateConditionProfiles(condition, profileByAxisValue) {
|
|
52
|
+
for (const [key, profile] of [
|
|
53
|
+
[
|
|
54
|
+
`viewport:${condition.viewport.key}`,
|
|
55
|
+
`${condition.viewport.width}:${condition.viewport.height}:${condition.viewport.unit}`,
|
|
56
|
+
],
|
|
57
|
+
[`density:${condition.density.key}`, String(condition.density.pixel_ratio)],
|
|
58
|
+
[
|
|
59
|
+
`safe_area:${condition.safe_area.key}`,
|
|
60
|
+
`${condition.safe_area.top}:${condition.safe_area.right}:${condition.safe_area.bottom}:${condition.safe_area.left}:${condition.safe_area.unit}`,
|
|
61
|
+
],
|
|
62
|
+
[
|
|
63
|
+
`text_scale:${condition.text_scale.key}`,
|
|
64
|
+
String(condition.text_scale.multiplier),
|
|
65
|
+
],
|
|
66
|
+
]) {
|
|
67
|
+
const previous = profileByAxisValue.get(key);
|
|
68
|
+
if (previous !== undefined && previous !== profile)
|
|
69
|
+
invalid("manifest_condition_profile_ambiguous", `${key}:${previous}:${profile}`);
|
|
70
|
+
profileByAxisValue.set(key, profile);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function validateConditionExclusions(manifest, axes, byAxis, fingerprints, census, sourceItems) {
|
|
74
|
+
const excluded = new Map();
|
|
75
|
+
for (const row of manifest.condition_exclusions) {
|
|
76
|
+
if (row.target_ref !== manifest.target_key)
|
|
77
|
+
invalid("manifest_condition_exclusion_target_mismatch", row.key);
|
|
78
|
+
validateBasis(row, sourceItems, census, `manifest_condition_exclusion:${row.key}`);
|
|
79
|
+
if (row.disposition === "decision_required" ||
|
|
80
|
+
row.disposition === "unavailable")
|
|
81
|
+
invalid("manifest_condition_exclusion_unresolved", row.key);
|
|
82
|
+
const values = exactAxisPairs(row.axis_values, axes.map((axis) => axis.axis), `manifest_condition_exclusion:${row.key}`);
|
|
83
|
+
for (const [axis, value] of values)
|
|
84
|
+
if (!byAxis.get(axis).values.some((candidate) => candidate.key === value))
|
|
85
|
+
invalid("manifest_condition_exclusion_value_unknown", `${row.key}:${axis}:${value}`);
|
|
86
|
+
const fingerprint = axisFingerprint(values);
|
|
87
|
+
if (fingerprints.has(fingerprint) || excluded.has(fingerprint))
|
|
88
|
+
invalid("manifest_condition_exclusion_duplicate", row.key);
|
|
89
|
+
excluded.set(fingerprint, row.key);
|
|
90
|
+
}
|
|
91
|
+
return excluded;
|
|
92
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { DesignResourceObservableFactManifestV1 } from "./design-resource-fact-manifest-types.js";
|
|
2
|
+
import type { DesignResource } from "./design-resource-handoff-file-primitives.js";
|
|
3
|
+
import type { DesignResourceHandoffV1 } from "./design-resource-handoff-types.js";
|
|
4
|
+
export declare function validateManifestFacts(manifest: DesignResourceObservableFactManifestV1, handoff: DesignResourceHandoffV1, resources: Map<string, DesignResource>, contents: Map<string, Buffer>, sourceItems: Map<string, string>): void;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { validateDesignResourceLocatedDigest, validateDesignResourceValueKind, } from "./design-resource-fact-locator-validation.js";
|
|
2
|
+
import { invalid, nonempty, refsKnown, stableJson, unique, } from "./design-resource-fact-universe-helpers.js";
|
|
3
|
+
export function validateManifestFacts(manifest, handoff, resources, contents, sourceItems) {
|
|
4
|
+
const cells = new Map(manifest.fact_cells.map((cell) => [cell.key, cell]));
|
|
5
|
+
const properties = new Map(manifest.properties.map((property) => [property.key, property]));
|
|
6
|
+
const evidence = new Map(manifest.evidence.map((item) => [item.key, item]));
|
|
7
|
+
const lineageNodes = new Map(manifest.lineage_nodes.map((item) => [item.key, item]));
|
|
8
|
+
for (const fact of manifest.facts) {
|
|
9
|
+
const property = validateFactIdentity(fact, cells, properties);
|
|
10
|
+
validateFactSourceAndEvidence(fact, evidence, sourceItems);
|
|
11
|
+
validateFactValue(fact, resources, contents);
|
|
12
|
+
validateFactLineage(fact, property.family, manifest, handoff, lineageNodes);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function validateFactIdentity(fact, cells, properties) {
|
|
16
|
+
const cell = cells.get(fact.cell_ref);
|
|
17
|
+
const property = properties.get(fact.property_ref);
|
|
18
|
+
if (!cell ||
|
|
19
|
+
cell.fact_ref !== fact.key ||
|
|
20
|
+
cell.subject_ref !== fact.subject_ref ||
|
|
21
|
+
cell.target_ref !== fact.target_ref ||
|
|
22
|
+
cell.condition_ref !== fact.condition_ref ||
|
|
23
|
+
cell.variation_ref !== fact.variation_ref ||
|
|
24
|
+
cell.property_ref !== fact.property_ref)
|
|
25
|
+
invalid("manifest_fact_cell_mismatch", fact.key);
|
|
26
|
+
if (!property ||
|
|
27
|
+
property.dimension !== fact.dimension ||
|
|
28
|
+
property.value_kind !== fact.value_kind)
|
|
29
|
+
invalid("manifest_fact_property_mismatch", fact.key);
|
|
30
|
+
return property;
|
|
31
|
+
}
|
|
32
|
+
function validateFactSourceAndEvidence(fact, evidence, sourceItems) {
|
|
33
|
+
nonempty(fact.evidence_refs, `manifest_fact_evidence_required:${fact.key}`);
|
|
34
|
+
nonempty(fact.source_item_refs, `manifest_fact_source_item_required:${fact.key}`);
|
|
35
|
+
unique(fact.evidence_refs, `manifest_fact_evidence_duplicate:${fact.key}`);
|
|
36
|
+
refsKnown(fact.evidence_refs, evidence, "manifest_fact_evidence_unknown", fact.key);
|
|
37
|
+
refsKnown(fact.source_item_refs, sourceItems, "manifest_fact_source_item_unknown", fact.key);
|
|
38
|
+
}
|
|
39
|
+
function validateFactValue(fact, resources, contents) {
|
|
40
|
+
const resolvedFactValue = validateDesignResourceLocatedDigest(fact.value, resources, contents, `manifest.fact.${fact.key}.value`);
|
|
41
|
+
validateDesignResourceValueKind(fact.value_kind, resolvedFactValue, `manifest.fact.${fact.key}.value`);
|
|
42
|
+
validateDesignResourceLocatedDigest(fact.lineage.resolved_value, resources, contents, `manifest.fact.${fact.key}.lineage.resolved_value`);
|
|
43
|
+
if (fact.value.sha256 !== fact.lineage.resolved_value.sha256 ||
|
|
44
|
+
stableJson(fact.value.locator) !==
|
|
45
|
+
stableJson(fact.lineage.resolved_value.locator))
|
|
46
|
+
invalid("manifest_fact_resolved_value_mismatch", fact.key);
|
|
47
|
+
}
|
|
48
|
+
function validateFactLineage(fact, family, manifest, handoff, nodes) {
|
|
49
|
+
if (handoff.scope.style_dependency !== "non-fidelity" &&
|
|
50
|
+
["typography", "color", "decoration", "icon"].includes(family) &&
|
|
51
|
+
fact.lineage.design_system_ref === null)
|
|
52
|
+
invalid("manifest_style_fact_design_system_lineage_required", fact.key);
|
|
53
|
+
if (fact.lineage.conflict_status === "none" &&
|
|
54
|
+
fact.lineage.conflict_resolution !== "")
|
|
55
|
+
invalid("manifest_fact_conflict_resolution_forbidden", fact.key);
|
|
56
|
+
if (fact.lineage.conflict_status === "resolved" &&
|
|
57
|
+
!fact.lineage.conflict_resolution.trim())
|
|
58
|
+
invalid("manifest_fact_conflict_resolution_required", fact.key);
|
|
59
|
+
if (fact.lineage.design_system_ref !== null &&
|
|
60
|
+
fact.lineage.design_system_ref !== manifest.design_system.id)
|
|
61
|
+
invalid("manifest_fact_design_system_lineage_mismatch", fact.key);
|
|
62
|
+
validateLineageRefs(fact, nodes);
|
|
63
|
+
validateLineageChain(fact, nodes);
|
|
64
|
+
}
|
|
65
|
+
function validateLineageRefs(fact, nodes) {
|
|
66
|
+
unique(fact.lineage.token_chain_refs, `manifest_fact_token_chain_duplicate:${fact.key}`);
|
|
67
|
+
unique(fact.lineage.override_chain_refs, `manifest_fact_override_chain_duplicate:${fact.key}`);
|
|
68
|
+
refsKnown(fact.lineage.token_chain_refs, nodes, "manifest_fact_token_lineage_unknown", fact.key);
|
|
69
|
+
refsKnown(fact.lineage.override_chain_refs, nodes, "manifest_fact_override_lineage_unknown", fact.key);
|
|
70
|
+
for (const ref of fact.lineage.token_chain_refs)
|
|
71
|
+
if (![
|
|
72
|
+
"base_token",
|
|
73
|
+
"alias_token",
|
|
74
|
+
"semantic_token",
|
|
75
|
+
"component_token",
|
|
76
|
+
].includes(nodes.get(ref).kind))
|
|
77
|
+
invalid("manifest_fact_token_lineage_kind_invalid", `${fact.key}:${ref}`);
|
|
78
|
+
for (const ref of fact.lineage.override_chain_refs)
|
|
79
|
+
if (![
|
|
80
|
+
"platform_override",
|
|
81
|
+
"mode_override",
|
|
82
|
+
"state_override",
|
|
83
|
+
"instance_override",
|
|
84
|
+
"slot_override",
|
|
85
|
+
"direct_value",
|
|
86
|
+
].includes(nodes.get(ref).kind))
|
|
87
|
+
invalid("manifest_fact_override_lineage_kind_invalid", `${fact.key}:${ref}`);
|
|
88
|
+
}
|
|
89
|
+
function validateLineageChain(fact, nodes) {
|
|
90
|
+
const chain = [
|
|
91
|
+
...fact.lineage.token_chain_refs,
|
|
92
|
+
...fact.lineage.override_chain_refs,
|
|
93
|
+
];
|
|
94
|
+
if (fact.lineage.design_system_ref === null && chain.length)
|
|
95
|
+
invalid("manifest_fact_lineage_without_design_system", fact.key);
|
|
96
|
+
if (fact.lineage.design_system_ref !== null && chain.length === 0)
|
|
97
|
+
invalid("manifest_fact_design_system_chain_required", fact.key);
|
|
98
|
+
for (let index = 1; index < chain.length; index += 1)
|
|
99
|
+
if (!nodes.get(chain[index]).predecessor_refs.includes(chain[index - 1]))
|
|
100
|
+
invalid("manifest_fact_lineage_chain_disconnected", `${fact.key}:${chain[index - 1]}:${chain[index]}`);
|
|
101
|
+
if (!chain.length)
|
|
102
|
+
return;
|
|
103
|
+
const effective = nodes.get(chain.at(-1)).value;
|
|
104
|
+
if (effective.sha256 !== fact.lineage.resolved_value.sha256 ||
|
|
105
|
+
stableJson(effective.locator) !==
|
|
106
|
+
stableJson(fact.lineage.resolved_value.locator))
|
|
107
|
+
invalid("manifest_fact_lineage_effective_value_mismatch", fact.key);
|
|
108
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type DesignResourceObservableFactManifestV1, type DesignResourceSubjectVariationV1, type DesignResourceVariationAxis } from "./design-resource-fact-manifest-types.js";
|
|
2
|
+
export declare function manifestIdentityDigest(rows: ReadonlyArray<unknown>): string;
|
|
3
|
+
export declare function manifestCollectionRows(manifest: DesignResourceObservableFactManifestV1): Map<string, ReadonlyArray<unknown>>;
|
|
4
|
+
export declare function conditionAxisValue(condition: DesignResourceObservableFactManifestV1["conditions"][number], axis: string): string;
|
|
5
|
+
export declare function variationValues(variation: DesignResourceSubjectVariationV1): Array<readonly [DesignResourceVariationAxis, string]>;
|
|
6
|
+
export declare function factCellFingerprint(cell: {
|
|
7
|
+
subject_ref: string;
|
|
8
|
+
target_ref: string;
|
|
9
|
+
condition_ref: string;
|
|
10
|
+
variation_ref: string;
|
|
11
|
+
property_ref: string;
|
|
12
|
+
}): string;
|
|
13
|
+
export declare function validateBasis(row: {
|
|
14
|
+
source_item_refs: string[];
|
|
15
|
+
basis_refs: string[];
|
|
16
|
+
}, sourceItems: Map<string, string>, census: Map<string, unknown>, label: string): void;
|
|
17
|
+
export declare function exactAxisPairs<T extends string>(pairs: Array<{
|
|
18
|
+
axis_ref: T | string;
|
|
19
|
+
value_ref: string;
|
|
20
|
+
}>, expectedAxes: readonly T[] | string[], detail: string): Array<readonly [string, string]>;
|
|
21
|
+
export declare function axisFingerprint(values: Array<readonly [string, string]>): string;
|
|
22
|
+
export declare function cartesian<T>(groups: T[][]): T[][];
|
|
23
|
+
export declare function groupBy<T>(rows: T[], key: (row: T) => string): Map<string, T[]>;
|
|
24
|
+
export declare function refsKnown<T>(refs: string[], known: Map<string, T>, code: string, detail: string): void;
|
|
25
|
+
export declare function nonempty(values: unknown[], code: string): void;
|
|
26
|
+
export declare function unique(values: string[], code: string): void;
|
|
27
|
+
export declare function sameSet(actual: string[], expected: string[], code: string, detail: string): void;
|
|
28
|
+
export declare function sameSetValue(left: readonly string[], right: readonly string[]): boolean;
|
|
29
|
+
export declare function stableJson(value: unknown): string;
|
|
30
|
+
export declare function invalid(code: string, detail: string): never;
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { DESIGN_RESOURCE_STANDARD_CONDITION_AXES, } from "./design-resource-fact-manifest-types.js";
|
|
2
|
+
import { invalidDesignResourceHandoff } from "./design-resource-handoff-validation-primitives.js";
|
|
3
|
+
import { sha256Hex } from "./strict-codec.js";
|
|
4
|
+
export function manifestIdentityDigest(rows) {
|
|
5
|
+
return sha256Hex(rows
|
|
6
|
+
.map((row) => stableJson(row))
|
|
7
|
+
.sort()
|
|
8
|
+
.join("\n"));
|
|
9
|
+
}
|
|
10
|
+
export function manifestCollectionRows(manifest) {
|
|
11
|
+
return new Map([
|
|
12
|
+
["inspector_inputs", manifest.inspector.input_resources],
|
|
13
|
+
["inspector_census", manifest.inspector.census],
|
|
14
|
+
["axis_dispositions", manifest.axis_dispositions],
|
|
15
|
+
["condition_exclusions", manifest.condition_exclusions],
|
|
16
|
+
["conditions", manifest.conditions],
|
|
17
|
+
["subjects", manifest.subjects],
|
|
18
|
+
["variation_axis_dispositions", manifest.variation_axis_dispositions],
|
|
19
|
+
["variation_exclusions", manifest.variation_exclusions],
|
|
20
|
+
["variations", manifest.variations],
|
|
21
|
+
["properties", manifest.properties],
|
|
22
|
+
["lineage_nodes", manifest.lineage_nodes],
|
|
23
|
+
["fact_cells", manifest.fact_cells],
|
|
24
|
+
["facts", manifest.facts],
|
|
25
|
+
["evidence", manifest.evidence],
|
|
26
|
+
["proof_obligations", manifest.proof_obligations],
|
|
27
|
+
["oracles", manifest.oracles],
|
|
28
|
+
["environments", manifest.environments],
|
|
29
|
+
["asset_bindings", manifest.asset_bindings],
|
|
30
|
+
["acceptance_blockers", manifest.acceptance_blockers],
|
|
31
|
+
]);
|
|
32
|
+
}
|
|
33
|
+
export function conditionAxisValue(condition, axis) {
|
|
34
|
+
const standard = {
|
|
35
|
+
platform: condition.platform,
|
|
36
|
+
os_version: condition.os_version,
|
|
37
|
+
device_profile: condition.device_profile,
|
|
38
|
+
form_factor: condition.form_factor,
|
|
39
|
+
viewport: condition.viewport.key,
|
|
40
|
+
orientation: condition.orientation,
|
|
41
|
+
density: condition.density.key,
|
|
42
|
+
safe_area: condition.safe_area.key,
|
|
43
|
+
window_state: condition.window_state,
|
|
44
|
+
fold_state: condition.fold_state,
|
|
45
|
+
display_mode: condition.display_mode,
|
|
46
|
+
color_scheme: condition.color_scheme,
|
|
47
|
+
locale: condition.locale,
|
|
48
|
+
language: condition.language,
|
|
49
|
+
script: condition.script,
|
|
50
|
+
direction: condition.direction,
|
|
51
|
+
pseudo_localization: condition.pseudo_localization,
|
|
52
|
+
content_case: condition.content_case,
|
|
53
|
+
data_case: condition.data_case,
|
|
54
|
+
text_scale: condition.text_scale.key,
|
|
55
|
+
input_method: condition.input_method,
|
|
56
|
+
assistive_technology: condition.assistive_technology,
|
|
57
|
+
motion: condition.motion,
|
|
58
|
+
transparency: condition.transparency,
|
|
59
|
+
contrast: condition.contrast,
|
|
60
|
+
bold_text: condition.bold_text,
|
|
61
|
+
button_shapes: condition.button_shapes,
|
|
62
|
+
system_ui: condition.system_ui,
|
|
63
|
+
ime: condition.ime,
|
|
64
|
+
permission: condition.permission,
|
|
65
|
+
capability: condition.capability,
|
|
66
|
+
connectivity: condition.connectivity,
|
|
67
|
+
lifecycle: condition.lifecycle,
|
|
68
|
+
};
|
|
69
|
+
if (DESIGN_RESOURCE_STANDARD_CONDITION_AXES.includes(axis))
|
|
70
|
+
return standard[axis];
|
|
71
|
+
const custom = condition.custom_axes.filter((item) => item.axis_ref === axis);
|
|
72
|
+
if (custom.length !== 1)
|
|
73
|
+
invalid("manifest_condition_custom_axis_missing_or_duplicate", `${condition.key}:${axis}`);
|
|
74
|
+
return custom[0].value_ref;
|
|
75
|
+
}
|
|
76
|
+
export function variationValues(variation) {
|
|
77
|
+
return [
|
|
78
|
+
["variant", variation.variant],
|
|
79
|
+
["state", variation.state],
|
|
80
|
+
["interaction_phase", variation.interaction_phase],
|
|
81
|
+
["presence_phase", variation.presence_phase],
|
|
82
|
+
["instance_case", variation.instance_case],
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
export function factCellFingerprint(cell) {
|
|
86
|
+
return [
|
|
87
|
+
cell.subject_ref,
|
|
88
|
+
cell.target_ref,
|
|
89
|
+
cell.condition_ref,
|
|
90
|
+
cell.variation_ref,
|
|
91
|
+
cell.property_ref,
|
|
92
|
+
].join("\0");
|
|
93
|
+
}
|
|
94
|
+
export function validateBasis(row, sourceItems, census, label) {
|
|
95
|
+
nonempty(row.source_item_refs, `${label}:source_item_refs_required`);
|
|
96
|
+
nonempty(row.basis_refs, `${label}:basis_refs_required`);
|
|
97
|
+
unique(row.source_item_refs, `${label}:source_item_ref_duplicate`);
|
|
98
|
+
unique(row.basis_refs, `${label}:basis_ref_duplicate`);
|
|
99
|
+
refsKnown(row.source_item_refs, sourceItems, "manifest_source_item_unknown", label);
|
|
100
|
+
for (const ref of row.basis_refs)
|
|
101
|
+
if (!sourceItems.has(ref) && !census.has(ref))
|
|
102
|
+
invalid("manifest_basis_ref_unknown", `${label}:${ref}`);
|
|
103
|
+
}
|
|
104
|
+
export function exactAxisPairs(pairs, expectedAxes, detail) {
|
|
105
|
+
unique(pairs.map((pair) => pair.axis_ref), `${detail}:axis_duplicate`);
|
|
106
|
+
sameSet(pairs.map((pair) => pair.axis_ref), [...expectedAxes], "manifest_combination_axes_mismatch", detail);
|
|
107
|
+
const byAxis = new Map(pairs.map((pair) => [String(pair.axis_ref), pair.value_ref]));
|
|
108
|
+
return [...expectedAxes].map((axis) => [String(axis), byAxis.get(String(axis))]);
|
|
109
|
+
}
|
|
110
|
+
export function axisFingerprint(values) {
|
|
111
|
+
return values
|
|
112
|
+
.map(([axis, value]) => `${axis}=${value}`)
|
|
113
|
+
.sort()
|
|
114
|
+
.join("\0");
|
|
115
|
+
}
|
|
116
|
+
export function cartesian(groups) {
|
|
117
|
+
let result = [[]];
|
|
118
|
+
for (const group of groups)
|
|
119
|
+
result = result.flatMap((prefix) => group.map((item) => [...prefix, item]));
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
export function groupBy(rows, key) {
|
|
123
|
+
const result = new Map();
|
|
124
|
+
for (const row of rows) {
|
|
125
|
+
const value = key(row);
|
|
126
|
+
const group = result.get(value) ?? [];
|
|
127
|
+
group.push(row);
|
|
128
|
+
result.set(value, group);
|
|
129
|
+
}
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
export function refsKnown(refs, known, code, detail) {
|
|
133
|
+
for (const ref of refs)
|
|
134
|
+
if (!known.has(ref))
|
|
135
|
+
invalid(code, `${detail}:${ref}`);
|
|
136
|
+
}
|
|
137
|
+
export function nonempty(values, code) {
|
|
138
|
+
if (!values.length)
|
|
139
|
+
invalid(code, "");
|
|
140
|
+
}
|
|
141
|
+
export function unique(values, code) {
|
|
142
|
+
if (new Set(values).size !== values.length)
|
|
143
|
+
invalid(code, values.join(","));
|
|
144
|
+
}
|
|
145
|
+
export function sameSet(actual, expected, code, detail) {
|
|
146
|
+
if (!sameSetValue(actual, expected))
|
|
147
|
+
invalid(code, `${detail}:${[...new Set(actual)].sort().join(",")}:${[...new Set(expected)].sort().join(",")}`);
|
|
148
|
+
}
|
|
149
|
+
export function sameSetValue(left, right) {
|
|
150
|
+
const actual = [...new Set(left)].sort();
|
|
151
|
+
const expected = [...new Set(right)].sort();
|
|
152
|
+
return (actual.length === expected.length &&
|
|
153
|
+
actual.every((item, index) => item === expected[index]));
|
|
154
|
+
}
|
|
155
|
+
export function stableJson(value) {
|
|
156
|
+
if (Array.isArray(value))
|
|
157
|
+
return `[${value.map((item) => stableJson(item)).join(",")}]`;
|
|
158
|
+
if (value && typeof value === "object")
|
|
159
|
+
return `{${Object.entries(value)
|
|
160
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
161
|
+
.map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`)
|
|
162
|
+
.join(",")}}`;
|
|
163
|
+
return JSON.stringify(value);
|
|
164
|
+
}
|
|
165
|
+
export function invalid(code, detail) {
|
|
166
|
+
invalidDesignResourceHandoff(code, detail);
|
|
167
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DesignResourceObservableFactManifestV1 } from "./design-resource-fact-manifest-types.js";
|
|
2
|
+
import type { DesignResource } from "./design-resource-handoff-file-primitives.js";
|
|
3
|
+
import type { DesignResourceHandoffTargetV1, DesignResourceHandoffV1 } from "./design-resource-handoff-types.js";
|
|
4
|
+
type Census = Map<string, DesignResourceObservableFactManifestV1["inspector"]["census"][number]>;
|
|
5
|
+
export declare function validateManifestLineageNodes(manifest: DesignResourceObservableFactManifestV1, census: Census, resources: Map<string, DesignResource>, contents: Map<string, Buffer>): void;
|
|
6
|
+
export declare function validateManifestInspector(manifest: DesignResourceObservableFactManifestV1, handoff: DesignResourceHandoffV1, target: DesignResourceHandoffTargetV1, resources: Map<string, DesignResource>, contents: Map<string, Buffer>, sourceItems: Map<string, string>): void;
|
|
7
|
+
export {};
|