stylegallery 0.1.0 → 0.1.2
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/AGENTS.md +4 -1
- package/DOMAINS.md +2 -6
- package/GOVERNANCE.md +10 -9
- package/README.md +29 -127
- package/consumer-reference/agent-native/v2/admission-policy.json +646 -0
- package/consumer-reference/agent-native/v2/material-registry.json +1 -0
- package/consumer-reference/agent-native/v2/schema/admission-policy.schema.json +50 -0
- package/consumer-reference/agent-native/v2/schema/material-manifest.schema.json +17 -0
- package/consumer-reference/agent-native/v2/schema/material-record.schema.json +20 -0
- package/consumer-reference/contract.md +1 -1
- package/consumer-reference/index.md +5 -3
- package/layout/index.md +124 -0
- package/log.md +57 -0
- package/package.json +183 -22
- package/scripts/agent-native/v2/experimental-extension-registry.mjs +143 -0
- package/scripts/agent-native/v2/extensions/a2a-projection.mjs +264 -0
- package/scripts/agent-native/v2/extensions/agui-projection.mjs +191 -0
- package/scripts/agent-native/v2/material-admission.mjs +295 -0
- package/scripts/agent-native/v2/material-cli-adapter.mjs +134 -0
- package/scripts/agent-native/v2/material-context.mjs +251 -0
- package/scripts/agent-native/v2/material-identity.mjs +71 -0
- package/scripts/agent-native/v2/material-mcp-adapter.mjs +253 -0
- package/scripts/agent-native/v2/material-operation-registry.mjs +123 -0
- package/scripts/agent-native/v2/material-queries.mjs +398 -0
- package/scripts/agent-native/v2/material-registry.mjs +319 -0
- package/scripts/sg-material-mcp.mjs +98 -0
- package/scripts/sg-material.mjs +27 -0
- package/consumer-reference/adapters/style-dictionary.config.mjs +0 -36
- package/consumer-reference/baselines/calibration.json +0 -260
- package/consumer-reference/baselines/manifest.json +0 -21
- package/consumer-reference/fixtures/consumer-conformance/e2e-fixture.mjs +0 -282
- package/consumer-reference/fixtures/consumer-conformance/manifest.json +0 -102
- package/consumer-reference/fixtures/consumer-conformance/runtime-proof.mjs +0 -32
- package/consumer-reference/fixtures/consumer-conformance/valid-migration-result.json +0 -18
- package/consumer-reference/fixtures/consumer-conformance/valid-migration.json +0 -142
- package/consumer-reference/fixtures/invalid-stable-ended-support.json +0 -19
- package/consumer-reference/fixtures/promotion/invalid-blocking-evidence.json +0 -26
- package/consumer-reference/fixtures/promotion/invalid-count-only.json +0 -29
- package/consumer-reference/fixtures/promotion/invalid-missing-owner-migration.json +0 -25
- package/consumer-reference/fixtures/promotion/invalid-normative-bypass-no-regression.json +0 -25
- package/consumer-reference/fixtures/promotion/invalid-related-counted-independent.json +0 -45
- package/consumer-reference/fixtures/promotion/invalid-stable-ended-support.json +0 -26
- package/consumer-reference/fixtures/promotion/manifest.json +0 -15
- package/consumer-reference/fixtures/promotion/valid-deferred-example.json +0 -67
- package/consumer-reference/fixtures/promotion/valid-normative-bypass.json +0 -67
- package/consumer-reference/fixtures/token-portability/invalid-cycle.json +0 -7
- package/consumer-reference/fixtures/token-portability/invalid-dangling-alias.json +0 -6
- package/consumer-reference/fixtures/token-portability/invalid-extends.json +0 -4
- package/consumer-reference/fixtures/token-portability/invalid-json-pointer.json +0 -7
- package/consumer-reference/fixtures/token-portability/invalid-resolver.json +0 -9
- package/consumer-reference/fixtures/token-portability/invalid-type-mismatch.json +0 -10
- package/consumer-reference/fixtures/token-portability/invalid-unknown-reserved.json +0 -6
- package/consumer-reference/fixtures/token-portability/invalid-untested-type.json +0 -6
- package/consumer-reference/fixtures/token-portability/valid-border.json +0 -14
- package/consumer-reference/fixtures/token-portability/valid-reference.json +0 -32
- package/consumer-reference/fixtures/token-portability/valid-whole-alias.json +0 -7
- package/consumer-reference/fixtures/valid-deprecated.json +0 -21
- package/consumer-reference/fixtures/valid-experimental.json +0 -19
- package/consumer-reference/generated/manifest.json +0 -40
- package/consumer-reference/generated/tokens.css +0 -12
- package/consumer-reference/policies/shared-experimental.json +0 -37
- package/consumer-reference/schema/ax-evidence.schema.json +0 -30
- package/consumer-reference/schema/baseline-manifest.schema.json +0 -55
- package/consumer-reference/schema/calibration-record.schema.json +0 -190
- package/consumer-reference/schema/capture-session.schema.json +0 -161
- package/consumer-reference/schema/component-state.schema.json +0 -150
- package/consumer-reference/schema/consumer-conformance-record.schema.json +0 -365
- package/consumer-reference/schema/dom-evidence.schema.json +0 -38
- package/consumer-reference/schema/evidence-record.schema.json +0 -81
- package/consumer-reference/schema/fixture-manifest.schema.json +0 -32
- package/consumer-reference/schema/item.schema.json +0 -188
- package/consumer-reference/schema/page-evidence-manifest.schema.json +0 -216
- package/consumer-reference/schema/page-evidence-session.schema.json +0 -119
- package/consumer-reference/schema/portable-tokens.schema.json +0 -104
- package/consumer-reference/schema/promotion-rfc.schema.json +0 -219
- package/consumer-reference/schema/runtime-evidence-manifest.schema.json +0 -33
- package/consumer-reference/schema/visual-evidence.schema.json +0 -31
- package/design-engineering/consumer-migration-readiness.md +0 -124
- package/design-engineering/interface-craft.md +0 -107
- package/design-engineering/reference-profiles/external-adaptation/index.md +0 -12
- package/design-engineering/reference-profiles/governed-local/editorial/components/button.component.json +0 -125
- package/design-engineering/reference-profiles/governed-local/editorial/evidence/button.evidence.json +0 -3504
- package/design-engineering/reference-profiles/governed-local/editorial/fixtures/button.fixture.json +0 -65
- package/design-engineering/reference-profiles/governed-local/editorial/generated/evidence-coverage.md +0 -23
- package/design-engineering/reference-profiles/governed-local/editorial/generated/keyboard-matrix.md +0 -19
- package/design-engineering/reference-profiles/governed-local/editorial/generated/state-matrix.md +0 -21
- package/design-engineering/reference-profiles/governed-local/editorial/local-foundations.json +0 -12
- package/design-engineering/reference-profiles/governed-local/editorial/states/button.states.json +0 -195
- package/design-engineering/reference-profiles/governed-local/editorial/tokens.dtcg.json +0 -17
- package/design-engineering/reference-profiles/governed-local/terminal/components/button.component.json +0 -125
- package/design-engineering/reference-profiles/governed-local/terminal/evidence/button.evidence.json +0 -3504
- package/design-engineering/reference-profiles/governed-local/terminal/fixtures/button.fixture.json +0 -65
- package/design-engineering/reference-profiles/governed-local/terminal/generated/evidence-coverage.md +0 -23
- package/design-engineering/reference-profiles/governed-local/terminal/generated/keyboard-matrix.md +0 -19
- package/design-engineering/reference-profiles/governed-local/terminal/generated/state-matrix.md +0 -21
- package/design-engineering/reference-profiles/governed-local/terminal/local-foundations.json +0 -12
- package/design-engineering/reference-profiles/governed-local/terminal/profile.json +0 -43
- package/design-engineering/reference-profiles/governed-local/terminal/states/button.states.json +0 -195
- package/design-engineering/reference-profiles/governed-local/terminal/tokens.dtcg.json +0 -17
- package/game-ui/classification.md +0 -82
- package/game-ui/reference-record.md +0 -62
- package/game-ui/screen-hierarchy.md +0 -107
- package/game-ui/unity/architecture.md +0 -166
- package/game-ui/unity/cli-loop.md +0 -84
- package/game-ui/unity/data/unity-technologies-public-repositories.json +0 -26654
- package/game-ui/unity/org-wiki.md +0 -146
- package/game-ui/unity/repository-map.md +0 -102
- package/game-ui/unity/ui-systems.md +0 -85
- package/motion/practice-reference.md +0 -145
- package/motion/review-workflow.md +0 -86
- package/motion/vocabulary.md +0 -82
- package/platform-guides/apple-interaction.md +0 -89
- package/scripts/agent-native/events.mjs +0 -113
- package/scripts/agent-native/immutable-store.mjs +0 -102
- package/scripts/artifact-metadata.mjs +0 -20
- package/scripts/audit-evidence-freshness.mjs +0 -308
- package/scripts/baseline-contract.mjs +0 -189
- package/scripts/baseline-schema-parity.mjs +0 -40
- package/scripts/build-reference-artifacts.mjs +0 -127
- package/scripts/calibration-raw-contract.mjs +0 -172
- package/scripts/capture-session-contract.mjs +0 -187
- package/scripts/component-state-artifact-fixture.mjs +0 -44
- package/scripts/component-state-contract.mjs +0 -99
- package/scripts/component-state-semantics.mjs +0 -128
- package/scripts/component-state-workflow-contract.mjs +0 -67
- package/scripts/component-state-workflow-negative-cases.mjs +0 -64
- package/scripts/consumer-conformance-contract.mjs +0 -198
- package/scripts/consumer-evidence-governance-contract.mjs +0 -210
- package/scripts/consumer-reference-case-runner.mjs +0 -93
- package/scripts/consumer-reference-schema.mjs +0 -155
- package/scripts/create-component-state-session.mjs +0 -100
- package/scripts/create-page-evidence-session.mjs +0 -139
- package/scripts/domain-document-boundaries.mjs +0 -40
- package/scripts/domain-validation-checks.mjs +0 -141
- package/scripts/evidence-artifact-contract.mjs +0 -191
- package/scripts/finalize-component-state-evidence.mjs +0 -165
- package/scripts/finalize-page-evidence.mjs +0 -197
- package/scripts/generate-consumer-reference-evidence.mjs +0 -154
- package/scripts/generate-patterns.mjs +0 -218
- package/scripts/governance-matrix-contract.mjs +0 -73
- package/scripts/governance-matrix-negative-cases.mjs +0 -114
- package/scripts/governance-policy-contract.mjs +0 -49
- package/scripts/governance-test-fixture.mjs +0 -321
- package/scripts/governance-workflow-negative-cases.mjs +0 -241
- package/scripts/governed-profile-registry.mjs +0 -125
- package/scripts/json-schema-formats.mjs +0 -31
- package/scripts/markdown-structure.mjs +0 -45
- package/scripts/page-artifact-metadata.mjs +0 -124
- package/scripts/page-evidence-contract.mjs +0 -297
- package/scripts/page-evidence-fixture.mjs +0 -271
- package/scripts/pattern-data.mjs +0 -325
- package/scripts/profile-record-contract.mjs +0 -140
- package/scripts/promotion-attestation-contract.mjs +0 -91
- package/scripts/promotion-boundary-test-contract.mjs +0 -92
- package/scripts/promotion-fixture-inventory.mjs +0 -109
- package/scripts/promotion-governance-contract.mjs +0 -28
- package/scripts/reference-artifact-path-contract.mjs +0 -28
- package/scripts/reference-profile-contract.mjs +0 -114
- package/scripts/reference-token-contract.mjs +0 -156
- package/scripts/run-consumer-page-evidence-ci.mjs +0 -170
- package/scripts/summarize-sentinel-calibration.mjs +0 -98
- package/scripts/test-agent-adapter-conformance.mjs +0 -250
- package/scripts/test-agent-conformance-receipt.mjs +0 -106
- package/scripts/test-agent-events.mjs +0 -81
- package/scripts/test-agent-execution-effects.mjs +0 -114
- package/scripts/test-agent-execution-fixtures.mjs +0 -140
- package/scripts/test-agent-execution-kernel.mjs +0 -39
- package/scripts/test-agent-execution-learning.mjs +0 -130
- package/scripts/test-agent-execution-lifecycle.mjs +0 -143
- package/scripts/test-agent-execution-safety.mjs +0 -158
- package/scripts/test-agent-execution-views.mjs +0 -117
- package/scripts/test-agent-identity-integrity-cases.mjs +0 -160
- package/scripts/test-agent-knowledge-kernel.mjs +0 -183
- package/scripts/test-agent-learning.mjs +0 -246
- package/scripts/test-agent-mcp.mjs +0 -246
- package/scripts/test-agent-native-schemas.mjs +0 -215
- package/scripts/test-agent-projections.mjs +0 -249
- package/scripts/test-agent-registry-mcp-integrity.mjs +0 -215
- package/scripts/test-agent-registry-mutations.mjs +0 -110
- package/scripts/test-audit-evidence-freshness.mjs +0 -177
- package/scripts/test-component-state-sentinel.mjs +0 -35
- package/scripts/test-component-state-source-contract.mjs +0 -83
- package/scripts/test-consumer-conformance-sentinel.mjs +0 -165
- package/scripts/test-consumer-reference-sentinel.mjs +0 -31
- package/scripts/test-generate-consumer-reference-evidence.mjs +0 -124
- package/scripts/test-json-cli-output.mjs +0 -151
- package/scripts/test-json-schema-formats.mjs +0 -40
- package/scripts/test-reference-adapters.mjs +0 -199
- package/scripts/test-renderer-purity.mjs +0 -34
- package/scripts/test-sg-cli.mjs +0 -129
- package/scripts/test-summarize-sentinel-calibration.mjs +0 -226
- package/scripts/test-validate-baseline-manifest.mjs +0 -234
- package/scripts/test-validate-component-state-artifacts.mjs +0 -243
- package/scripts/test-validate-component-state.mjs +0 -106
- package/scripts/test-validate-consumer-conformance.mjs +0 -427
- package/scripts/test-validate-consumer-reference-cli.mjs +0 -69
- package/scripts/test-validate-consumer-reference.mjs +0 -263
- package/scripts/test-validate-domains.mjs +0 -357
- package/scripts/test-validate-governance.mjs +0 -292
- package/scripts/test-validate-ia.mjs +0 -262
- package/scripts/test-validate-okf.mjs +0 -73
- package/scripts/test-validate-page-evidence.mjs +0 -302
- package/scripts/test-validate-patterns.mjs +0 -157
- package/scripts/test-validate-promotion-rfc.mjs +0 -250
- package/scripts/test-validate-reference-profiles.mjs +0 -170
- package/scripts/test-validate-unity-org-wiki.mjs +0 -57
- package/scripts/test-validate-unity-source-contracts.mjs +0 -67
- package/scripts/test-validate-vocabulary.mjs +0 -174
- package/scripts/test-validate-webpage-workflow.mjs +0 -293
- package/scripts/validate-baseline-manifest.mjs +0 -44
- package/scripts/validate-catalog.mjs +0 -65
- package/scripts/validate-component-state.mjs +0 -141
- package/scripts/validate-consumer-conformance.mjs +0 -477
- package/scripts/validate-consumer-reference.mjs +0 -288
- package/scripts/validate-domains.mjs +0 -237
- package/scripts/validate-governance.mjs +0 -248
- package/scripts/validate-ia.mjs +0 -136
- package/scripts/validate-links.mjs +0 -66
- package/scripts/validate-okf.mjs +0 -104
- package/scripts/validate-page-evidence.mjs +0 -191
- package/scripts/validate-patterns.mjs +0 -246
- package/scripts/validate-promotion-rfc.mjs +0 -224
- package/scripts/validate-reference-artifacts.mjs +0 -125
- package/scripts/validate-renderer-purity.mjs +0 -56
- package/scripts/validate-unity-org-wiki.mjs +0 -146
- package/scripts/validate-unity-source-contracts.mjs +0 -107
- package/scripts/validate-vocabulary.mjs +0 -115
- package/scripts/validate-webpage-workflow.mjs +0 -254
- package/scripts/visual-expectation-contract.mjs +0 -20
- package/scripts/workflow-action-contract.mjs +0 -163
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import fs from "node:fs";
|
|
4
|
-
import os from "node:os";
|
|
5
|
-
import path from "node:path";
|
|
6
|
-
import { spawnSync } from "node:child_process";
|
|
7
|
-
import { fileURLToPath } from "node:url";
|
|
8
|
-
|
|
9
|
-
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
10
|
-
const validator = path.join(root, "scripts", "validate-vocabulary.mjs");
|
|
11
|
-
|
|
12
|
-
const glossary = [
|
|
13
|
-
"# Controlled Vocabulary",
|
|
14
|
-
"",
|
|
15
|
-
"## Canonical Terms",
|
|
16
|
-
"",
|
|
17
|
-
"- Canonical: `domain`",
|
|
18
|
-
" - Concept: top-level knowledge ownership",
|
|
19
|
-
"- Canonical: `category`",
|
|
20
|
-
" - Concept: domain-local browse placement",
|
|
21
|
-
"- Canonical: `pattern`",
|
|
22
|
-
" - Concept: reusable spatial primitive",
|
|
23
|
-
"- Canonical: `recipe`",
|
|
24
|
-
" - Concept: screen composition",
|
|
25
|
-
"- Canonical: `gate`",
|
|
26
|
-
" - Concept: quality decision contract",
|
|
27
|
-
"- Canonical: `claim`",
|
|
28
|
-
" - Concept: review assertion",
|
|
29
|
-
"- Canonical: `evidence family`",
|
|
30
|
-
" - Concept: evidence class",
|
|
31
|
-
"- Canonical: `scroll ownership`",
|
|
32
|
-
" - Concept: scroll responsibility",
|
|
33
|
-
"- Canonical: `harmony`",
|
|
34
|
-
" - Concept: content layout fit",
|
|
35
|
-
"- Canonical: `debt`",
|
|
36
|
-
" - Concept: accepted unresolved risk",
|
|
37
|
-
"- Canonical: `consumer reference`",
|
|
38
|
-
" - Concept: optional consumer record handoff",
|
|
39
|
-
"- Canonical: `maturity`",
|
|
40
|
-
" - Concept: consumer reference lifecycle",
|
|
41
|
-
"- Canonical: `artifact mode`",
|
|
42
|
-
" - Concept: consumer reference storage role",
|
|
43
|
-
"",
|
|
44
|
-
"## Aliases",
|
|
45
|
-
"",
|
|
46
|
-
"- Alias: `primitive` -> `pattern`",
|
|
47
|
-
"",
|
|
48
|
-
"## Deprecated Terms",
|
|
49
|
-
"",
|
|
50
|
-
"- Deprecated: `component` -> `pattern`",
|
|
51
|
-
" - Reason: In Layout, component implies visual or framework ownership.",
|
|
52
|
-
"",
|
|
53
|
-
"## Local-Only Terms",
|
|
54
|
-
"",
|
|
55
|
-
"- Local-only: `OKF`",
|
|
56
|
-
"- Local-only: `consumer component`",
|
|
57
|
-
"",
|
|
58
|
-
"## Scannability Checklist",
|
|
59
|
-
"",
|
|
60
|
-
"- Use headings for decision boundaries.",
|
|
61
|
-
"",
|
|
62
|
-
"## Vale Proposal",
|
|
63
|
-
"",
|
|
64
|
-
"Prose linting should wait until the vocabulary is stable.",
|
|
65
|
-
"",
|
|
66
|
-
].join("\n");
|
|
67
|
-
|
|
68
|
-
const files = {
|
|
69
|
-
"README.md": "# layout-gallery\n\n[Controlled vocabulary](guides/vocabulary.md)\n",
|
|
70
|
-
"GUIDE.md": "# Guide\n\n[Controlled vocabulary](guides/vocabulary.md)\n",
|
|
71
|
-
"index.md": "# Index\n\n[Controlled vocabulary](guides/vocabulary.md)\n",
|
|
72
|
-
"quality/index.md": "# Quality\n\n[Controlled vocabulary](../guides/vocabulary.md)\n",
|
|
73
|
-
"guides/vocabulary.md": glossary,
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const cases = [
|
|
77
|
-
{
|
|
78
|
-
name: "missing_domain_term",
|
|
79
|
-
mutate: {
|
|
80
|
-
"guides/vocabulary.md": glossary.replace("- Canonical: `domain`\n - Concept: top-level knowledge ownership\n", ""),
|
|
81
|
-
},
|
|
82
|
-
expect: "guides/vocabulary.md: missing canonical term domain",
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
name: "missing_category_term",
|
|
86
|
-
mutate: {
|
|
87
|
-
"guides/vocabulary.md": glossary.replace("- Canonical: `category`\n - Concept: domain-local browse placement\n", ""),
|
|
88
|
-
},
|
|
89
|
-
expect: "guides/vocabulary.md: missing canonical term category",
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
name: "missing_required_term",
|
|
93
|
-
mutate: {
|
|
94
|
-
"guides/vocabulary.md": glossary.replace("- Canonical: `debt`\n - Concept: accepted unresolved risk\n", ""),
|
|
95
|
-
},
|
|
96
|
-
expect: "guides/vocabulary.md: missing canonical term debt",
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
name: "missing_consumer_reference_term",
|
|
100
|
-
mutate: {
|
|
101
|
-
"guides/vocabulary.md": glossary.replace("- Canonical: `consumer reference`\n - Concept: optional consumer record handoff\n", ""),
|
|
102
|
-
},
|
|
103
|
-
expect: "guides/vocabulary.md: missing canonical term consumer reference",
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
name: "duplicate_concept",
|
|
107
|
-
mutate: {
|
|
108
|
-
"guides/vocabulary.md": glossary.replace(
|
|
109
|
-
"- Canonical: `pattern`\n - Concept: reusable spatial primitive",
|
|
110
|
-
"- Canonical: `pattern`\n - Concept: reusable spatial primitive\n- Canonical: `layout primitive`\n - Concept: reusable spatial primitive",
|
|
111
|
-
),
|
|
112
|
-
},
|
|
113
|
-
expect: "guides/vocabulary.md: concept \"reusable spatial primitive\" has multiple canonical terms: pattern, layout primitive",
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
name: "missing_vale_boundary",
|
|
117
|
-
mutate: {
|
|
118
|
-
"guides/vocabulary.md": glossary.replace("Prose linting should wait until the vocabulary is stable.", "Enable Vale immediately."),
|
|
119
|
-
},
|
|
120
|
-
expect: "guides/vocabulary.md: missing Prose linting should wait until the vocabulary is stable.",
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
name: "paraphrased_navigation_label",
|
|
124
|
-
mutate: {
|
|
125
|
-
"README.md": files["README.md"].replace("[Controlled vocabulary]", "[Vocabulary guide]"),
|
|
126
|
-
},
|
|
127
|
-
expectWarning: "README.md: recommended link label missing [Controlled vocabulary](guides/vocabulary.md)",
|
|
128
|
-
},
|
|
129
|
-
{
|
|
130
|
-
name: "success_path",
|
|
131
|
-
expect: null,
|
|
132
|
-
},
|
|
133
|
-
];
|
|
134
|
-
|
|
135
|
-
function writeFixture(testCase) {
|
|
136
|
-
const dir = fs.mkdtempSync(path.join(os.tmpdir(), `layout-gallery-vocabulary-${testCase.name}-`));
|
|
137
|
-
const entries = { ...files, ...(testCase.mutate ?? {}) };
|
|
138
|
-
for (const [relative, content] of Object.entries(entries)) {
|
|
139
|
-
const target = path.join(dir, relative);
|
|
140
|
-
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
141
|
-
fs.writeFileSync(target, content);
|
|
142
|
-
}
|
|
143
|
-
return dir;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function runCase(testCase) {
|
|
147
|
-
const dir = writeFixture(testCase);
|
|
148
|
-
const result = spawnSync(process.execPath, [validator, "--json"], {
|
|
149
|
-
cwd: dir,
|
|
150
|
-
encoding: "utf8",
|
|
151
|
-
});
|
|
152
|
-
fs.rmSync(dir, { force: true, recursive: true });
|
|
153
|
-
const output = JSON.parse(result.stdout);
|
|
154
|
-
const passed = testCase.expectWarning
|
|
155
|
-
? output.ok && output.warnings?.includes(testCase.expectWarning)
|
|
156
|
-
: testCase.expect
|
|
157
|
-
? !output.ok && output.failures.includes(testCase.expect)
|
|
158
|
-
: output.ok;
|
|
159
|
-
return {
|
|
160
|
-
name: testCase.name,
|
|
161
|
-
ok: passed,
|
|
162
|
-
expected: testCase.expectWarning ?? testCase.expect ?? "ok:true",
|
|
163
|
-
actual: output,
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const results = cases.map(runCase);
|
|
168
|
-
const report = {
|
|
169
|
-
ok: results.every((result) => result.ok),
|
|
170
|
-
results,
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
console.log(JSON.stringify(report, null, 2));
|
|
174
|
-
process.exitCode = report.ok ? 0 : 1;
|
|
@@ -1,293 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import fs from "node:fs";
|
|
4
|
-
import os from "node:os";
|
|
5
|
-
import path from "node:path";
|
|
6
|
-
import { spawnSync } from "node:child_process";
|
|
7
|
-
import { fileURLToPath } from "node:url";
|
|
8
|
-
|
|
9
|
-
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
10
|
-
const validator = path.join(root, "scripts", "validate-webpage-workflow.mjs");
|
|
11
|
-
|
|
12
|
-
const files = {
|
|
13
|
-
"README.md": "# layout-gallery\n\n- [Webpage Generation Workflow](guides/webpage-generation-workflow.md)\n",
|
|
14
|
-
"GUIDE.md": [
|
|
15
|
-
"# Layout Planning Guide",
|
|
16
|
-
"",
|
|
17
|
-
"- [Webpage generation workflow](guides/webpage-generation-workflow.md)",
|
|
18
|
-
"- content-to-layout match",
|
|
19
|
-
"- harmony evaluation",
|
|
20
|
-
"- GPT Image reference",
|
|
21
|
-
"- implementation handoff",
|
|
22
|
-
"",
|
|
23
|
-
].join("\n"),
|
|
24
|
-
"guides/layout-brief.md": [
|
|
25
|
-
"# Layout Brief Template",
|
|
26
|
-
"",
|
|
27
|
-
"## Webpage Generation Intake",
|
|
28
|
-
"",
|
|
29
|
-
"Content-to-layout match:",
|
|
30
|
-
"Harmony evaluation:",
|
|
31
|
-
"GPT Image reference:",
|
|
32
|
-
"Required preconditions before prompt:",
|
|
33
|
-
"Image review extract-vs-ignore:",
|
|
34
|
-
"Implementation handoff:",
|
|
35
|
-
"Consumer reference: not_applicable",
|
|
36
|
-
"Consumer reference reason: This blank planning template has no consumer record.",
|
|
37
|
-
"Accepted image debt:",
|
|
38
|
-
"",
|
|
39
|
-
"## Minimum Required Fields By Use Case",
|
|
40
|
-
"",
|
|
41
|
-
"Homepage:",
|
|
42
|
-
"Dashboard:",
|
|
43
|
-
"Article:",
|
|
44
|
-
"Form:",
|
|
45
|
-
"Command surface:",
|
|
46
|
-
"",
|
|
47
|
-
"## Rejected Alternatives",
|
|
48
|
-
"",
|
|
49
|
-
"Rejected pattern or recipe:",
|
|
50
|
-
"Reason rejected:",
|
|
51
|
-
"",
|
|
52
|
-
].join("\n"),
|
|
53
|
-
"guides/decision-tree.md": [
|
|
54
|
-
"# Layout Decision Tree",
|
|
55
|
-
"",
|
|
56
|
-
"Rejected alternatives:",
|
|
57
|
-
"",
|
|
58
|
-
].join("\n"),
|
|
59
|
-
"guides/webpage-generation-workflow.md": [
|
|
60
|
-
"---",
|
|
61
|
-
"type: Planning Guide",
|
|
62
|
-
"---",
|
|
63
|
-
"",
|
|
64
|
-
"# Webpage Generation Workflow",
|
|
65
|
-
"",
|
|
66
|
-
"## Use Cases",
|
|
67
|
-
"## Content-to-Layout Match",
|
|
68
|
-
"## Harmony Evaluation",
|
|
69
|
-
"## GPT Image Reference",
|
|
70
|
-
"Required preconditions before prompt:",
|
|
71
|
-
"Extract from image:",
|
|
72
|
-
"Ignore from image:",
|
|
73
|
-
"## Implementation Handoff",
|
|
74
|
-
"Implementation debt:",
|
|
75
|
-
"Final implementation proof:",
|
|
76
|
-
"Consumer reference: not_applicable",
|
|
77
|
-
"Consumer reference reason: This generic workflow has no consumer record.",
|
|
78
|
-
"[Consumer Reference Receiver Contract](../consumer-reference/contract.md)",
|
|
79
|
-
"## Workflow Route Examples",
|
|
80
|
-
"",
|
|
81
|
-
"### Homepage Route",
|
|
82
|
-
"Content blocks -> Section jobs -> Recipe -> Pattern stack -> Scroll owner -> Constraints -> Harmony evaluation -> GPT Image reference -> Implementation handoff",
|
|
83
|
-
"",
|
|
84
|
-
"### Dashboard Route",
|
|
85
|
-
"Content blocks -> Section jobs -> Recipe -> Pattern stack -> Scroll owner -> Constraints -> Harmony evaluation -> GPT Image reference -> Implementation handoff",
|
|
86
|
-
"",
|
|
87
|
-
"### Article Route",
|
|
88
|
-
"Content blocks -> Section jobs -> Recipe -> Pattern stack -> Scroll owner -> Constraints -> Harmony evaluation -> GPT Image reference -> Implementation handoff",
|
|
89
|
-
"",
|
|
90
|
-
"### Form Route",
|
|
91
|
-
"Content blocks -> Section jobs -> Recipe -> Pattern stack -> Scroll owner -> Constraints -> Harmony evaluation -> GPT Image reference -> Implementation handoff",
|
|
92
|
-
"",
|
|
93
|
-
"### Command Surface Route",
|
|
94
|
-
"Content blocks -> Section jobs -> Recipe -> Pattern stack -> Scroll owner -> Constraints -> Harmony evaluation -> GPT Image reference -> Implementation handoff",
|
|
95
|
-
"",
|
|
96
|
-
].join("\n"),
|
|
97
|
-
"recipes/index.md": "# Layout Recipes\n\n- [Homepage](homepage.md)\n",
|
|
98
|
-
"recipes/homepage.md": [
|
|
99
|
-
"---",
|
|
100
|
-
"type: Layout Recipe",
|
|
101
|
-
"screen_type: Homepage",
|
|
102
|
-
"---",
|
|
103
|
-
"",
|
|
104
|
-
"# Homepage",
|
|
105
|
-
"",
|
|
106
|
-
"## Recommended Pattern Stack",
|
|
107
|
-
"## Content-To-Layout Matching",
|
|
108
|
-
"## GPT Image Reference",
|
|
109
|
-
"Required preconditions before prompt:",
|
|
110
|
-
"Image review extract-vs-ignore:",
|
|
111
|
-
"",
|
|
112
|
-
].join("\n"),
|
|
113
|
-
"quality/gates/index.md": "# Gate Contracts\n\n- [Harmony evaluation gate](harmony-evaluation.md)\n",
|
|
114
|
-
"quality/gates/harmony-evaluation.md": [
|
|
115
|
-
"---",
|
|
116
|
-
"type: Quality Gate",
|
|
117
|
-
"---",
|
|
118
|
-
"",
|
|
119
|
-
"# Harmony Evaluation Gate",
|
|
120
|
-
"",
|
|
121
|
-
"## Required Contract",
|
|
122
|
-
"",
|
|
123
|
-
"Content-to-layout match:",
|
|
124
|
-
"Overall harmony:",
|
|
125
|
-
"GPT Image reference:",
|
|
126
|
-
"Implementation handoff:",
|
|
127
|
-
"Rejected alternatives:",
|
|
128
|
-
"Do not generate a GPT Image reference before harmony evaluation approves the semantic order, section jobs, pattern stack, scroll owner, and constraints.",
|
|
129
|
-
"Source order, accessibility, brand correctness, and usability cannot be inferred from the image.",
|
|
130
|
-
"Final implementation proof:",
|
|
131
|
-
"",
|
|
132
|
-
].join("\n"),
|
|
133
|
-
"design-engineering/consumer-migration-readiness.md": [
|
|
134
|
-
"---",
|
|
135
|
-
"lifecycle: experimental",
|
|
136
|
-
"provenance_kind: local",
|
|
137
|
-
"---",
|
|
138
|
-
"# Consumer Migration Readiness",
|
|
139
|
-
"## Migration Dimension Contract",
|
|
140
|
-
"`behavior_inventory`",
|
|
141
|
-
"`route_parity`",
|
|
142
|
-
"`field_parity`",
|
|
143
|
-
"`action_parity`",
|
|
144
|
-
"`state_transitions`",
|
|
145
|
-
"`contract_precedence`",
|
|
146
|
-
"`direct_mutation`",
|
|
147
|
-
"`indirect_mutation`",
|
|
148
|
-
"`persistence_round_trip`",
|
|
149
|
-
"`reset_boundary`",
|
|
150
|
-
"`exact_time_boundary`",
|
|
151
|
-
"`defaults_tri_state_mapping`",
|
|
152
|
-
"`atomic_batch_behavior`",
|
|
153
|
-
"Consumer migration conformance: declared",
|
|
154
|
-
"Passing this method does not prove complete accessibility, product correctness, usability, visual quality, independent adoption, cross-browser equivalence, or owner approval.",
|
|
155
|
-
].join("\n"),
|
|
156
|
-
"consumer-reference/contract.md": [
|
|
157
|
-
"### Migration-Only Extension",
|
|
158
|
-
"This field is migration-only.",
|
|
159
|
-
"Do not add it to generic blank handoffs",
|
|
160
|
-
"Consumer migration conformance: declared",
|
|
161
|
-
].join("\n"),
|
|
162
|
-
"quality/gates/consumer-migration-evidence.md": [
|
|
163
|
-
"# Consumer Migration Evidence Gate",
|
|
164
|
-
"## Required Contract",
|
|
165
|
-
"## Blocking Conditions",
|
|
166
|
-
"thirteen migration dimensions",
|
|
167
|
-
"Decision: pass | block",
|
|
168
|
-
].join("\n"),
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
const cases = [
|
|
172
|
-
{
|
|
173
|
-
name: "missing_workflow_file",
|
|
174
|
-
omit: ["guides/webpage-generation-workflow.md"],
|
|
175
|
-
expect: "guides/webpage-generation-workflow.md: missing file",
|
|
176
|
-
},
|
|
177
|
-
{
|
|
178
|
-
name: "missing_harmony_anchor",
|
|
179
|
-
mutate: {
|
|
180
|
-
"quality/gates/harmony-evaluation.md": files["quality/gates/harmony-evaluation.md"].replace("Overall harmony:", "Overall fit:"),
|
|
181
|
-
},
|
|
182
|
-
expect: "quality/gates/harmony-evaluation.md: missing Overall harmony:",
|
|
183
|
-
},
|
|
184
|
-
{
|
|
185
|
-
name: "missing_route_examples",
|
|
186
|
-
mutate: {
|
|
187
|
-
"guides/webpage-generation-workflow.md": files["guides/webpage-generation-workflow.md"].replace("## Workflow Route Examples", "## Workflow Routes"),
|
|
188
|
-
},
|
|
189
|
-
expect: "guides/webpage-generation-workflow.md: missing ## Workflow Route Examples",
|
|
190
|
-
},
|
|
191
|
-
{
|
|
192
|
-
name: "missing_image_proof_boundary",
|
|
193
|
-
mutate: {
|
|
194
|
-
"quality/gates/harmony-evaluation.md": files["quality/gates/harmony-evaluation.md"].replace(
|
|
195
|
-
"Source order, accessibility, brand correctness, and usability cannot be inferred from the image.",
|
|
196
|
-
"Generated image alone is enough for source order and access decisions.",
|
|
197
|
-
),
|
|
198
|
-
},
|
|
199
|
-
expect: "quality/gates/harmony-evaluation.md: missing Source order, accessibility, brand correctness, and usability cannot be inferred from the image.",
|
|
200
|
-
},
|
|
201
|
-
{
|
|
202
|
-
name: "misordered_gpt_image_route",
|
|
203
|
-
mutate: {
|
|
204
|
-
"guides/webpage-generation-workflow.md": files["guides/webpage-generation-workflow.md"].replace(
|
|
205
|
-
"Content blocks -> Section jobs -> Recipe -> Pattern stack -> Scroll owner -> Constraints -> Harmony evaluation -> GPT Image reference -> Implementation handoff",
|
|
206
|
-
"Content blocks -> Section jobs -> Recipe -> Pattern stack -> GPT Image reference -> Harmony evaluation -> Scroll owner -> Constraints -> Implementation handoff",
|
|
207
|
-
),
|
|
208
|
-
},
|
|
209
|
-
expect: "guides/webpage-generation-workflow.md: route Homepage places GPT Image reference before Harmony evaluation",
|
|
210
|
-
},
|
|
211
|
-
{
|
|
212
|
-
name: "missing_rejected_alternatives",
|
|
213
|
-
mutate: {
|
|
214
|
-
"guides/layout-brief.md": files["guides/layout-brief.md"].replace("## Rejected Alternatives", "## Alternatives"),
|
|
215
|
-
},
|
|
216
|
-
expect: "guides/layout-brief.md: missing ## Rejected Alternatives",
|
|
217
|
-
},
|
|
218
|
-
{
|
|
219
|
-
name: "missing_consumer_reference_reason",
|
|
220
|
-
mutate: {
|
|
221
|
-
"guides/webpage-generation-workflow.md": files["guides/webpage-generation-workflow.md"].replace("Consumer reference reason: This generic workflow has no consumer record.", ""),
|
|
222
|
-
},
|
|
223
|
-
expect: "guides/webpage-generation-workflow.md: missing Consumer reference reason:",
|
|
224
|
-
},
|
|
225
|
-
{
|
|
226
|
-
name: "missing_migration_dimension",
|
|
227
|
-
mutate: {
|
|
228
|
-
"design-engineering/consumer-migration-readiness.md": files["design-engineering/consumer-migration-readiness.md"].replace("`atomic_batch_behavior`", "`batch_behavior`"),
|
|
229
|
-
},
|
|
230
|
-
expect: "design-engineering/consumer-migration-readiness.md: missing `atomic_batch_behavior`",
|
|
231
|
-
},
|
|
232
|
-
{
|
|
233
|
-
name: "migration_field_in_ordinary_handoff",
|
|
234
|
-
mutate: {
|
|
235
|
-
"guides/webpage-generation-workflow.md": `${files["guides/webpage-generation-workflow.md"]}\nConsumer migration conformance: declared\n`,
|
|
236
|
-
},
|
|
237
|
-
expect: "guides/webpage-generation-workflow.md: ordinary handoff must not declare consumer migration conformance",
|
|
238
|
-
},
|
|
239
|
-
{
|
|
240
|
-
name: "paraphrased_navigation_label",
|
|
241
|
-
mutate: {
|
|
242
|
-
"README.md": files["README.md"].replace("[Webpage Generation Workflow]", "[Webpage planning workflow]"),
|
|
243
|
-
},
|
|
244
|
-
expectWarning: "README.md: recommended link label missing [Webpage Generation Workflow](guides/webpage-generation-workflow.md)",
|
|
245
|
-
},
|
|
246
|
-
{
|
|
247
|
-
name: "success_path",
|
|
248
|
-
expect: null,
|
|
249
|
-
},
|
|
250
|
-
];
|
|
251
|
-
|
|
252
|
-
function writeFixture(testCase) {
|
|
253
|
-
const dir = fs.mkdtempSync(path.join(os.tmpdir(), `layout-gallery-webpage-workflow-${testCase.name}-`));
|
|
254
|
-
const omitted = new Set(testCase.omit ?? []);
|
|
255
|
-
const entries = { ...files, ...(testCase.mutate ?? {}) };
|
|
256
|
-
for (const [relative, content] of Object.entries(entries)) {
|
|
257
|
-
if (omitted.has(relative)) continue;
|
|
258
|
-
const target = path.join(dir, relative);
|
|
259
|
-
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
260
|
-
fs.writeFileSync(target, content);
|
|
261
|
-
}
|
|
262
|
-
return dir;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function runCase(testCase) {
|
|
266
|
-
const dir = writeFixture(testCase);
|
|
267
|
-
const result = spawnSync(process.execPath, [validator, "--json"], {
|
|
268
|
-
cwd: dir,
|
|
269
|
-
encoding: "utf8",
|
|
270
|
-
});
|
|
271
|
-
fs.rmSync(dir, { force: true, recursive: true });
|
|
272
|
-
const output = JSON.parse(result.stdout);
|
|
273
|
-
const passed = testCase.expectWarning
|
|
274
|
-
? output.ok && output.warnings?.includes(testCase.expectWarning)
|
|
275
|
-
: testCase.expect
|
|
276
|
-
? !output.ok && output.failures.includes(testCase.expect)
|
|
277
|
-
: output.ok;
|
|
278
|
-
return {
|
|
279
|
-
name: testCase.name,
|
|
280
|
-
ok: passed,
|
|
281
|
-
expected: testCase.expectWarning ?? testCase.expect ?? "ok:true",
|
|
282
|
-
actual: output,
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
const results = cases.map(runCase);
|
|
287
|
-
const report = {
|
|
288
|
-
ok: results.every((result) => result.ok),
|
|
289
|
-
results,
|
|
290
|
-
};
|
|
291
|
-
|
|
292
|
-
console.log(JSON.stringify(report, null, 2));
|
|
293
|
-
process.exitCode = report.ok ? 0 : 1;
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
-
import Ajv2020 from "ajv/dist/2020.js";
|
|
6
|
-
import { readJson, validateCalibration, validateManifest } from "./baseline-contract.mjs";
|
|
7
|
-
|
|
8
|
-
const repositoryRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
9
|
-
const options = { calibration: "consumer-reference/baselines/calibration.json", json: false, manifest: "consumer-reference/baselines/manifest.json" };
|
|
10
|
-
const failures = [];
|
|
11
|
-
for (let index = 2; index < process.argv.length; index += 1) {
|
|
12
|
-
const argument = process.argv[index];
|
|
13
|
-
if (argument === "--json") options.json = true;
|
|
14
|
-
else if (argument === "--manifest" || argument === "--calibration") {
|
|
15
|
-
const value = process.argv[index + 1];
|
|
16
|
-
if (!value) failures.push({ code: "argument_value_required", message: `${argument} requires a value`, path: "<cli>" });
|
|
17
|
-
else {
|
|
18
|
-
options[argument.slice(2)] = value;
|
|
19
|
-
index += 1;
|
|
20
|
-
}
|
|
21
|
-
} else failures.push({ code: "argument_unknown", message: `unsupported argument ${argument}`, path: "<cli>" });
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const manifestPath = path.resolve(repositoryRoot, options.manifest);
|
|
25
|
-
const calibrationPath = path.resolve(repositoryRoot, options.calibration);
|
|
26
|
-
const manifestSchemaPath = path.join(repositoryRoot, "consumer-reference/schema/baseline-manifest.schema.json");
|
|
27
|
-
const calibrationSchemaPath = path.join(repositoryRoot, "consumer-reference/schema/calibration-record.schema.json");
|
|
28
|
-
const manifest = readJson(manifestPath, failures);
|
|
29
|
-
const calibration = readJson(calibrationPath, failures);
|
|
30
|
-
const manifestSchema = readJson(manifestSchemaPath, failures);
|
|
31
|
-
const calibrationSchema = readJson(calibrationSchemaPath, failures);
|
|
32
|
-
const ajv = new Ajv2020({ allErrors: true, strict: false });
|
|
33
|
-
for (const [kind, value, schema, file] of [["manifest", manifest, manifestSchema, manifestPath], ["calibration", calibration, calibrationSchema, calibrationPath]]) {
|
|
34
|
-
if (value === undefined || schema === undefined) continue;
|
|
35
|
-
const validate = ajv.compile(schema);
|
|
36
|
-
if (!validate(value)) for (const error of validate.errors ?? []) failures.push({ code: `baseline_${kind}_schema_invalid`, message: `${error.instancePath || "/"} ${error.message}`, path: file });
|
|
37
|
-
}
|
|
38
|
-
if (manifest !== undefined) failures.push(...validateManifest(manifest, manifestPath, repositoryRoot));
|
|
39
|
-
if (calibration !== undefined) failures.push(...validateCalibration(calibration, calibrationPath));
|
|
40
|
-
const uniqueFailures = [...new Map(failures.map((failure) => [`${failure.code}:${failure.path}:${failure.message}`, failure])).values()];
|
|
41
|
-
const result = { failures: uniqueFailures, ok: uniqueFailures.length === 0, warnings: [] };
|
|
42
|
-
if (options.json) process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
43
|
-
else if (!result.ok) process.stderr.write(`${result.failures.map((failure) => `${failure.code}: ${failure.message}`).join("\n")}\n`);
|
|
44
|
-
if (!result.ok) process.exitCode = 1;
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import fs from "node:fs";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import { patterns } from "./pattern-data.mjs";
|
|
6
|
-
|
|
7
|
-
const args = new Set(process.argv.slice(2));
|
|
8
|
-
const json = args.has("--json");
|
|
9
|
-
const root = process.cwd();
|
|
10
|
-
const failures = [];
|
|
11
|
-
|
|
12
|
-
function slugDir(category) {
|
|
13
|
-
return category.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function read(relative) {
|
|
17
|
-
return fs.readFileSync(path.join(root, relative), "utf8");
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function requireIncludes(relative, text) {
|
|
21
|
-
if (!read(relative).includes(text)) failures.push(`${relative}: missing ${text}`);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const expectedFiles = new Set();
|
|
25
|
-
const expectedCategories = new Set();
|
|
26
|
-
|
|
27
|
-
for (const [slug, category, problem] of patterns) {
|
|
28
|
-
const dir = slugDir(category);
|
|
29
|
-
const file = `patterns/${dir}/${slug}.md`;
|
|
30
|
-
expectedFiles.add(file);
|
|
31
|
-
expectedCategories.add(category);
|
|
32
|
-
if (!fs.existsSync(path.join(root, file))) failures.push(`missing pattern file: ${file}`);
|
|
33
|
-
requireIncludes("CATALOG.md", `- [${slug}](${file}) - ${category}: ${problem}`);
|
|
34
|
-
requireIncludes(`patterns/${dir}/index.md`, `- [${slug}](${slug}.md) - ${problem}`);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
for (const category of expectedCategories) {
|
|
38
|
-
const dir = slugDir(category);
|
|
39
|
-
requireIncludes("patterns/index.md", `- [${category}](${dir}/index.md)`);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const actualFiles = fs.readdirSync(path.join(root, "patterns"), { recursive: true })
|
|
43
|
-
.filter((entry) => typeof entry === "string" && entry.endsWith(".md") && !entry.endsWith("index.md"))
|
|
44
|
-
.map((entry) => `patterns/${entry}`);
|
|
45
|
-
|
|
46
|
-
for (const file of actualFiles) {
|
|
47
|
-
if (!expectedFiles.has(file)) failures.push(`unexpected pattern file: ${file}`);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const result = {
|
|
51
|
-
actualPatternCount: actualFiles.length,
|
|
52
|
-
expectedPatternCount: expectedFiles.size,
|
|
53
|
-
failures,
|
|
54
|
-
ok: failures.length === 0,
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
if (json) {
|
|
58
|
-
console.log(JSON.stringify(result, null, 2));
|
|
59
|
-
} else if (result.ok) {
|
|
60
|
-
console.log(`ok: ${actualFiles.length} cataloged patterns`);
|
|
61
|
-
} else {
|
|
62
|
-
console.error(result.failures.join("\n"));
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
process.exitCode = result.ok ? 0 : 1;
|