@brandlab-digital/conformance 3.11.0 → 3.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/current-release.js +6 -6
- package/dist/current-release.js.map +1 -1
- package/dist/ready-cli.d.ts.map +1 -1
- package/dist/ready-cli.js +1 -0
- package/dist/ready-cli.js.map +1 -1
- package/dist/site-system/checks.d.ts +1 -1
- package/dist/site-system/checks.js +1 -1
- package/dist/site-system/checks.js.map +1 -1
- package/dist/site-system/rule-modules.d.ts.map +1 -1
- package/dist/site-system/rule-modules.js +5 -0
- package/dist/site-system/rule-modules.js.map +1 -1
- package/dist/site-system/rules/full/common.d.ts +37 -0
- package/dist/site-system/rules/full/common.d.ts.map +1 -0
- package/dist/site-system/rules/full/common.js +51 -0
- package/dist/site-system/rules/full/common.js.map +1 -0
- package/dist/site-system/rules/full/e10-phrases.d.ts +14 -0
- package/dist/site-system/rules/full/e10-phrases.d.ts.map +1 -0
- package/dist/site-system/rules/full/e10-phrases.js +69 -0
- package/dist/site-system/rules/full/e10-phrases.js.map +1 -0
- package/dist/site-system/rules/full/estate.d.ts +118 -0
- package/dist/site-system/rules/full/estate.d.ts.map +1 -0
- package/dist/site-system/rules/full/estate.js +447 -0
- package/dist/site-system/rules/full/estate.js.map +1 -0
- package/dist/site-system/rules/full/geography.d.ts +60 -0
- package/dist/site-system/rules/full/geography.d.ts.map +1 -0
- package/dist/site-system/rules/full/geography.js +111 -0
- package/dist/site-system/rules/full/geography.js.map +1 -0
- package/dist/site-system/rules/full/index.d.ts +33 -0
- package/dist/site-system/rules/full/index.d.ts.map +1 -0
- package/dist/site-system/rules/full/index.js +126 -0
- package/dist/site-system/rules/full/index.js.map +1 -0
- package/dist/site-system/rules/full/k12-manifests.d.ts +19 -0
- package/dist/site-system/rules/full/k12-manifests.d.ts.map +1 -0
- package/dist/site-system/rules/full/k12-manifests.js +130 -0
- package/dist/site-system/rules/full/k12-manifests.js.map +1 -0
- package/dist/site-system/rules/full/l10-location-copy.d.ts +15 -0
- package/dist/site-system/rules/full/l10-location-copy.d.ts.map +1 -0
- package/dist/site-system/rules/full/l10-location-copy.js +59 -0
- package/dist/site-system/rules/full/l10-location-copy.js.map +1 -0
- package/dist/site-system/rules/full/l3-neighbours.d.ts +16 -0
- package/dist/site-system/rules/full/l3-neighbours.d.ts.map +1 -0
- package/dist/site-system/rules/full/l3-neighbours.js +78 -0
- package/dist/site-system/rules/full/l3-neighbours.js.map +1 -0
- package/dist/site-system/rules/full/l4-local-copy.d.ts +27 -0
- package/dist/site-system/rules/full/l4-local-copy.d.ts.map +1 -0
- package/dist/site-system/rules/full/l4-local-copy.js +150 -0
- package/dist/site-system/rules/full/l4-local-copy.js.map +1 -0
- package/dist/site-system/rules/full/l9-data-contract.d.ts +15 -0
- package/dist/site-system/rules/full/l9-data-contract.d.ts.map +1 -0
- package/dist/site-system/rules/full/l9-data-contract.js +65 -0
- package/dist/site-system/rules/full/l9-data-contract.js.map +1 -0
- package/dist/site-system/rules/full/links.d.ts +23 -0
- package/dist/site-system/rules/full/links.d.ts.map +1 -0
- package/dist/site-system/rules/full/links.js +131 -0
- package/dist/site-system/rules/full/links.js.map +1 -0
- package/dist/site-system/rules/full/loc-index.d.ts +16 -0
- package/dist/site-system/rules/full/loc-index.d.ts.map +1 -0
- package/dist/site-system/rules/full/loc-index.js +59 -0
- package/dist/site-system/rules/full/loc-index.js.map +1 -0
- package/dist/site-system/rules/full/s4-route-files.d.ts +4 -0
- package/dist/site-system/rules/full/s4-route-files.d.ts.map +1 -0
- package/dist/site-system/rules/full/s4-route-files.js +125 -0
- package/dist/site-system/rules/full/s4-route-files.js.map +1 -0
- package/dist/site-system/rules/full/strategy.d.ts +43 -0
- package/dist/site-system/rules/full/strategy.d.ts.map +1 -0
- package/dist/site-system/rules/full/strategy.js +147 -0
- package/dist/site-system/rules/full/strategy.js.map +1 -0
- package/dist/site-system/runners.d.ts +2 -0
- package/dist/site-system/runners.d.ts.map +1 -1
- package/dist/site-system/runners.js.map +1 -1
- package/package.json +2 -2
package/dist/current-release.js
CHANGED
|
@@ -23,23 +23,23 @@ export const BRANDLAB_CURRENT_RUNTIME_RELEASE = Object.freeze({
|
|
|
23
23
|
"kind": "brandlab-runtime-release-contract",
|
|
24
24
|
"packages": {
|
|
25
25
|
"@brandlab-digital/conformance": {
|
|
26
|
-
"version": "3.
|
|
26
|
+
"version": "3.12.1"
|
|
27
27
|
},
|
|
28
28
|
"@brandlab-digital/eslint-plugin": {
|
|
29
|
-
"version": "3.
|
|
29
|
+
"version": "3.12.1"
|
|
30
30
|
},
|
|
31
31
|
"@brandlab-digital/site-core": {
|
|
32
|
-
"version": "3.
|
|
32
|
+
"version": "3.12.1"
|
|
33
33
|
},
|
|
34
34
|
"@brandlab-digital/site-next": {
|
|
35
|
-
"version": "3.
|
|
35
|
+
"version": "3.12.1"
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
|
-
"releaseVersion": "3.
|
|
38
|
+
"releaseVersion": "3.12.1",
|
|
39
39
|
"runtime": {
|
|
40
40
|
"bundler": "turbopack",
|
|
41
41
|
"cacheComponents": false,
|
|
42
|
-
"next": "16.
|
|
42
|
+
"next": "16.4.2",
|
|
43
43
|
"nextVersionPolicy": "exact",
|
|
44
44
|
"node": "24.x",
|
|
45
45
|
"packageManager": "npm@11.14.1",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"current-release.js","sourceRoot":"","sources":["../src/current-release.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,wEAAwE;AACxE,OAAO,EAEL,sCAAsC,GACvC,MAAM,uBAAuB,CAAC;AAE/B,MAAM,CAAC,MAAM,gCAAgC,GAAG,MAAM,CAAC,MAAM,CAC7D;IACE,cAAc,EAAE;QACd,uCAAuC;QACvC,8BAA8B;QAC9B,yBAAyB;QACzB,6BAA6B;QAC7B,0BAA0B;QAC1B,4BAA4B;QAC5B,kCAAkC;QAClC,wCAAwC;QACxC,yBAAyB;KAC1B;IACD,WAAW,EAAE;QACX,WAAW,EAAE,cAAc;QAC3B,cAAc,EAAE,iBAAiB;QACjC,eAAe,EAAE,mBAAmB;QACpC,SAAS,EAAE,YAAY;QACvB,KAAK,EAAE,QAAQ;KAChB;IACD,MAAM,EAAE,mCAAmC;IAC3C,UAAU,EAAE;QACV,+BAA+B,EAAE;YAC/B,SAAS,EAAE,QAAQ;SACpB;QACD,iCAAiC,EAAE;YACjC,SAAS,EAAE,QAAQ;SACpB;QACD,6BAA6B,EAAE;YAC7B,SAAS,EAAE,QAAQ;SACpB;QACD,6BAA6B,EAAE;YAC7B,SAAS,EAAE,QAAQ;SACpB;KACF;IACD,gBAAgB,EAAE,QAAQ;IAC1B,SAAS,EAAE;QACT,SAAS,EAAE,WAAW;QACtB,iBAAiB,EAAE,KAAK;QACxB,MAAM,EAAE,QAAQ;QAChB,mBAAmB,EAAE,OAAO;QAC5B,MAAM,EAAE,MAAM;QACd,gBAAgB,EAAE,aAAa;QAC/B,OAAO,EAAE,QAAQ;QACjB,UAAU,EAAE,QAAQ;QACpB,QAAQ,EAAE,KAAK;QACf,OAAO,EAAE,QAAQ;QACjB,YAAY,EAAE,OAAO;KACtB;IACD,eAAe,EAAE,sCAAsC;CACxD,CAC6C,CAAC;AAE/C,sCAAsC,CAAC,gCAAgC,CAAC,CAAC","sourcesContent":["// Generated by standards/scripts/generate-conformance-current-release.mjs.\n// Each exact package release verifies its own current runtime contract.\nimport {\n type BrandlabRuntimeReleaseContract,\n validateBrandlabRuntimeReleaseContract,\n} from \"./release-manifest.js\";\n\nexport const BRANDLAB_CURRENT_RUNTIME_RELEASE = Object.freeze(\n{\n \"capabilities\": [\n \"typed-project-business-and-route-data\",\n \"essential-search-foundations\",\n \"shared-contact-delivery\",\n \"privacy-safe-lead-analytics\",\n \"security-patched-runtime\",\n \"live-google-review-summary\",\n \"high-signal-project-verification\",\n \"packed-positive-and-negative-consumers\",\n \"changesets-oidc-release\"\n ],\n \"contracts\": {\n \"analytics\": \"analytics-v4\",\n \"architecture\": \"architecture-v7\",\n \"configuration\": \"project-config-v7\",\n \"contact\": \"contact-v4\",\n \"seo\": \"seo-v4\"\n },\n \"kind\": \"brandlab-runtime-release-contract\",\n \"packages\": {\n \"@brandlab-digital/conformance\": {\n \"version\": \"3.
|
|
1
|
+
{"version":3,"file":"current-release.js","sourceRoot":"","sources":["../src/current-release.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,wEAAwE;AACxE,OAAO,EAEL,sCAAsC,GACvC,MAAM,uBAAuB,CAAC;AAE/B,MAAM,CAAC,MAAM,gCAAgC,GAAG,MAAM,CAAC,MAAM,CAC7D;IACE,cAAc,EAAE;QACd,uCAAuC;QACvC,8BAA8B;QAC9B,yBAAyB;QACzB,6BAA6B;QAC7B,0BAA0B;QAC1B,4BAA4B;QAC5B,kCAAkC;QAClC,wCAAwC;QACxC,yBAAyB;KAC1B;IACD,WAAW,EAAE;QACX,WAAW,EAAE,cAAc;QAC3B,cAAc,EAAE,iBAAiB;QACjC,eAAe,EAAE,mBAAmB;QACpC,SAAS,EAAE,YAAY;QACvB,KAAK,EAAE,QAAQ;KAChB;IACD,MAAM,EAAE,mCAAmC;IAC3C,UAAU,EAAE;QACV,+BAA+B,EAAE;YAC/B,SAAS,EAAE,QAAQ;SACpB;QACD,iCAAiC,EAAE;YACjC,SAAS,EAAE,QAAQ;SACpB;QACD,6BAA6B,EAAE;YAC7B,SAAS,EAAE,QAAQ;SACpB;QACD,6BAA6B,EAAE;YAC7B,SAAS,EAAE,QAAQ;SACpB;KACF;IACD,gBAAgB,EAAE,QAAQ;IAC1B,SAAS,EAAE;QACT,SAAS,EAAE,WAAW;QACtB,iBAAiB,EAAE,KAAK;QACxB,MAAM,EAAE,QAAQ;QAChB,mBAAmB,EAAE,OAAO;QAC5B,MAAM,EAAE,MAAM;QACd,gBAAgB,EAAE,aAAa;QAC/B,OAAO,EAAE,QAAQ;QACjB,UAAU,EAAE,QAAQ;QACpB,QAAQ,EAAE,KAAK;QACf,OAAO,EAAE,QAAQ;QACjB,YAAY,EAAE,OAAO;KACtB;IACD,eAAe,EAAE,sCAAsC;CACxD,CAC6C,CAAC;AAE/C,sCAAsC,CAAC,gCAAgC,CAAC,CAAC","sourcesContent":["// Generated by standards/scripts/generate-conformance-current-release.mjs.\n// Each exact package release verifies its own current runtime contract.\nimport {\n type BrandlabRuntimeReleaseContract,\n validateBrandlabRuntimeReleaseContract,\n} from \"./release-manifest.js\";\n\nexport const BRANDLAB_CURRENT_RUNTIME_RELEASE = Object.freeze(\n{\n \"capabilities\": [\n \"typed-project-business-and-route-data\",\n \"essential-search-foundations\",\n \"shared-contact-delivery\",\n \"privacy-safe-lead-analytics\",\n \"security-patched-runtime\",\n \"live-google-review-summary\",\n \"high-signal-project-verification\",\n \"packed-positive-and-negative-consumers\",\n \"changesets-oidc-release\"\n ],\n \"contracts\": {\n \"analytics\": \"analytics-v4\",\n \"architecture\": \"architecture-v7\",\n \"configuration\": \"project-config-v7\",\n \"contact\": \"contact-v4\",\n \"seo\": \"seo-v4\"\n },\n \"kind\": \"brandlab-runtime-release-contract\",\n \"packages\": {\n \"@brandlab-digital/conformance\": {\n \"version\": \"3.12.1\"\n },\n \"@brandlab-digital/eslint-plugin\": {\n \"version\": \"3.12.1\"\n },\n \"@brandlab-digital/site-core\": {\n \"version\": \"3.12.1\"\n },\n \"@brandlab-digital/site-next\": {\n \"version\": \"3.12.1\"\n }\n },\n \"releaseVersion\": \"3.12.1\",\n \"runtime\": {\n \"bundler\": \"turbopack\",\n \"cacheComponents\": false,\n \"next\": \"16.4.2\",\n \"nextVersionPolicy\": \"exact\",\n \"node\": \"24.x\",\n \"packageManager\": \"npm@11.14.1\",\n \"react\": \"19.2.8\",\n \"reactDom\": \"19.2.8\",\n \"router\": \"app\",\n \"sharp\": \"0.35.5\",\n \"typescript\": \"6.0.3\"\n },\n \"schemaVersion\": \"brandlab.runtime-release-contract.v1\"\n},\n) as unknown as BrandlabRuntimeReleaseContract;\n\nvalidateBrandlabRuntimeReleaseContract(BRANDLAB_CURRENT_RUNTIME_RELEASE);\n"]}
|
package/dist/ready-cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ready-cli.d.ts","sourceRoot":"","sources":["../src/ready-cli.ts"],"names":[],"mappings":";AAiBA,OAAO,EAGL,KAAK,wBAAwB,EAC9B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAkD,KAAK,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAGhH,UAAU,kBAAkB;IAC1B,OAAO,EAAE,QAAQ,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,UAAU,kBAAkB;IAC1B,OAAO,EAAE,QAAQ,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,KAAK,eAAe,GAAG,kBAAkB,GAAG,kBAAkB,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAErF,UAAU,KAAK;IACb,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,4BAA4B;IAC3C,uEAAuE;IACvE,OAAO,CAAC,EAAE,SAAS,wBAAwB,EAAE,CAAC;IAC9C,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AA8BD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,eAAe,CAkC/E;AAiBD,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,EAAE,GAAE,KAGH,EACD,YAAY,GAAE,4BAAiC,GAC9C,OAAO,CAAC,MAAM,CAAC,CAwCjB;
|
|
1
|
+
{"version":3,"file":"ready-cli.d.ts","sourceRoot":"","sources":["../src/ready-cli.ts"],"names":[],"mappings":";AAiBA,OAAO,EAGL,KAAK,wBAAwB,EAC9B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAkD,KAAK,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAGhH,UAAU,kBAAkB;IAC1B,OAAO,EAAE,QAAQ,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,UAAU,kBAAkB;IAC1B,OAAO,EAAE,QAAQ,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,KAAK,eAAe,GAAG,kBAAkB,GAAG,kBAAkB,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAErF,UAAU,KAAK;IACb,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,4BAA4B;IAC3C,uEAAuE;IACvE,OAAO,CAAC,EAAE,SAAS,wBAAwB,EAAE,CAAC;IAC9C,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AA8BD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,eAAe,CAkC/E;AAiBD,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,EAAE,GAAE,KAGH,EACD,YAAY,GAAE,4BAAiC,GAC9C,OAAO,CAAC,MAAM,CAAC,CAwCjB;AA6KD,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAOrG"}
|
package/dist/ready-cli.js
CHANGED
package/dist/ready-cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ready-cli.js","sourceRoot":"","sources":["../src/ready-cli.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\nimport { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from \"node:fs\";\nimport { dirname, isAbsolute, join, relative, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { detectInstalledBrandlabRelease, evaluateBrandlabProject } from \"./project.js\";\nimport type { SiteSystemFinding } from \"./site-system/checks.js\";\nimport { readSiteSystemProjectConfig } from \"./site-system/config.js\";\nimport { readSiteSystemJourneyReport } from \"./site-system/playwright-report.js\";\nimport { appendSiteSystemRecord, readSiteSystemRecords } from \"./site-system/records.js\";\nimport {\n buildSiteSystemReadyReport,\n renderSiteSystemReadyMarkdown,\n SITE_SYSTEM_READY_REPORT_PATHS,\n type SiteSystemReadyReport,\n type SiteSystemVerifyResult,\n} from \"./site-system/report.js\";\nimport { SITE_SYSTEM_RENDERED_RUNNERS } from \"./site-system/rule-modules.js\";\nimport {\n isSiteSystemFinding,\n runSiteSystemRenderedRunners,\n type SiteSystemRenderedRunner,\n} from \"./site-system/runners.js\";\nimport { loadSiteSystemPages, planSiteSystemSamplePaths, type SiteSystemFetch } from \"./site-system/samples.js\";\nimport { SITE_SYSTEM_RECORDED_CHECK_IDS } from \"./site-system/steps.js\";\n\ninterface ReadyReportOptions {\n command: \"report\";\n root: string;\n playwrightReport: string;\n baseUrl?: string;\n buildDir: string;\n findings: string[];\n installedRelease?: string;\n launch: boolean;\n}\n\ninterface ReadyRecordOptions {\n command: \"record\";\n root: string;\n id: string;\n evidence?: string;\n note?: string;\n}\n\ntype ReadyCliOptions = ReadyReportOptions | ReadyRecordOptions | { command: \"help\" };\n\ninterface CliIo {\n stdout: (value: string) => void;\n stderr: (value: string) => void;\n}\n\nexport interface BrandlabReadyCliDependencies {\n /** The rule modules to run (default: SITE_SYSTEM_RENDERED_RUNNERS). */\n runners?: readonly SiteSystemRenderedRunner[];\n fetch?: SiteSystemFetch;\n now?: () => Date;\n}\n\nconst DEFAULT_PLAYWRIGHT_REPORT = \"test-results/site-system.json\";\n/** The checks a --findings file may set: K10 (the lenient harness) and the other recorded checks. */\nconst SUPPLIABLE_IDS = new Set<string>(SITE_SYSTEM_RECORDED_CHECK_IDS);\nconst DEFAULT_BUILD_DIR = \".next\";\n\nconst HELP = `Brandlab ready gate\n\nWrites docs/ready/ready-report.md and .json for the Site System tier declared in\nbrandlab.config.ts (siteSystem: { tier }), and records launch-day and human steps.\n\nUsage:\n brandlab-ready [--root <path>]\n [--playwright-report <path>] journey results (default ${DEFAULT_PLAYWRIGHT_REPORT})\n [--base-url <url>] fetch the sample pages from the running site\n [--build-dir <path>] otherwise read their HTML from the build (default ${DEFAULT_BUILD_DIR})\n [--findings <path>]... K10 or X1 results as SiteSystemFinding JSON (the lenient harness)\n [--installed-release <version>]\n [--launch] also require every launch-day and human step\n brandlab-ready record <id> --evidence <where the proof is> [--note <text>] [--root <path>]\n\nExit status:\n 0 ready at the declared tier, or nothing blocks (no tier declared, or none of its checks released)\n 1 a blocking check failed or did not run, home or the contact page could not be read, a --base-url\n sample did not answer with HTML, or brandlab.config.ts could not be read in full\n (with --launch, also a step not recorded)\n 2 the gate could not run (bad arguments, an unreadable config or records file)\n`;\n\nexport function parseBrandlabReadyArgs(argv: readonly string[]): ReadyCliOptions {\n if (argv.includes(\"--help\") || argv.includes(\"-h\")) return { command: \"help\" };\n if (argv[0] === \"record\") return parseRecordArgs(argv.slice(1));\n const parsed: ReadyReportOptions = {\n command: \"report\",\n root: process.cwd(),\n playwrightReport: DEFAULT_PLAYWRIGHT_REPORT,\n buildDir: DEFAULT_BUILD_DIR,\n findings: [],\n launch: false,\n };\n for (let index = 0; index < argv.length; index += 1) {\n const argument = argv[index];\n if (argument === \"--root\") parsed.root = resolve(requireValue(argv, ++index, argument));\n else if (argument === \"--playwright-report\") parsed.playwrightReport = requireValue(argv, ++index, argument);\n else if (argument === \"--build-dir\") parsed.buildDir = requireValue(argv, ++index, argument);\n else if (argument === \"--findings\") parsed.findings.push(requireValue(argv, ++index, argument));\n else if (argument === \"--installed-release\") parsed.installedRelease = requireValue(argv, ++index, argument);\n else if (argument === \"--launch\") parsed.launch = true;\n else if (argument === \"--base-url\") {\n const value = requireValue(argv, ++index, argument);\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw new Error(`--base-url ${value} is not a URL.`);\n }\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") throw new Error(\"--base-url must be an http or https URL.\");\n parsed.baseUrl = value;\n } else {\n throw new Error(`Unknown argument ${argument}.`);\n }\n }\n return parsed;\n}\n\nfunction parseRecordArgs(argv: readonly string[]): ReadyRecordOptions {\n const parsed: ReadyRecordOptions = { command: \"record\", root: process.cwd(), id: \"\" };\n for (let index = 0; index < argv.length; index += 1) {\n const argument = argv[index]!;\n if (argument === \"--evidence\") parsed.evidence = requireValue(argv, ++index, argument);\n else if (argument === \"--note\") parsed.note = requireValue(argv, ++index, argument);\n else if (argument === \"--root\") parsed.root = resolve(requireValue(argv, ++index, argument));\n else if (!argument.startsWith(\"--\") && !parsed.id) parsed.id = argument;\n else throw new Error(`Unknown argument ${argument}.`);\n }\n if (!parsed.id) throw new Error(\"record needs a step id, for example: brandlab-ready record X3 --evidence <PR link>.\");\n if (parsed.evidence === undefined) throw new Error(`record ${parsed.id} needs --evidence <where the proof is>.`);\n return parsed;\n}\n\nexport async function runBrandlabReadyCli(\n argv: readonly string[],\n io: CliIo = {\n stdout: (value) => process.stdout.write(value),\n stderr: (value) => process.stderr.write(value),\n },\n dependencies: BrandlabReadyCliDependencies = {},\n): Promise<number> {\n let options: ReadyCliOptions;\n try {\n options = parseBrandlabReadyArgs(argv);\n } catch (error) {\n io.stderr(`${errorMessage(error)}\\n\\n${HELP}`);\n return 2;\n }\n if (options.command === \"help\") {\n io.stdout(HELP);\n return 0;\n }\n const now = dependencies.now ?? (() => new Date());\n try {\n if (options.command === \"record\") {\n const { path, record } = appendSiteSystemRecord(options.root, {\n id: options.id,\n evidence: options.evidence ?? \"\",\n ...(options.note !== undefined ? { note: options.note } : {}),\n now: now(),\n });\n io.stdout(`Recorded ${record.id} in ${path}.\\n`);\n return 0;\n }\n const report = await createReadyReport(options, dependencies, now());\n const markdownPath = join(options.root, SITE_SYSTEM_READY_REPORT_PATHS.markdown);\n mkdirSync(dirname(markdownPath), { recursive: true });\n writeFileSync(markdownPath, renderSiteSystemReadyMarkdown(report));\n writeFileSync(join(options.root, SITE_SYSTEM_READY_REPORT_PATHS.json), `${JSON.stringify(report, null, 2)}\\n`);\n const problems = report.problems.length;\n io.stdout(\n `${report.verdict.summary}.\\n` +\n (problems > 0 ? `The report lists ${problems} problem${problems === 1 ? \"\" : \"s\"} with the inputs.\\n` : \"\") +\n `Wrote ${SITE_SYSTEM_READY_REPORT_PATHS.markdown} and ${SITE_SYSTEM_READY_REPORT_PATHS.json}.\\n`,\n );\n return report.verdict.exitCode;\n } catch (error) {\n io.stderr(`${errorMessage(error)}\\n`);\n return 2;\n }\n}\n\nasync function createReadyReport(\n options: ReadyReportOptions,\n dependencies: BrandlabReadyCliDependencies,\n now: Date,\n): Promise<SiteSystemReadyReport> {\n const root = options.root;\n const config = readSiteSystemProjectConfig(root);\n const release = options.installedRelease ?? detectInstalledBrandlabRelease(readPackageJson(root));\n if (config.siteSystem && !release) {\n throw new Error(\n \"The installed Brandlab release could not be read from package.json. Pin all four Brandlab packages to one exact version, or pass --installed-release.\",\n );\n }\n const problems: string[] = [...config.problems];\n const findings: SiteSystemFinding[] = [];\n\n // Journeys: the Playwright JSON report of the site-system spec.\n const journeyPath = resolveIn(root, options.playwrightReport);\n let journeyReport: string | null = null;\n let journeyTests = 0;\n if (!existsSync(journeyPath)) {\n problems.push(`No Playwright report at ${displayPath(root, journeyPath)}, so the journey checks did not run (run the site-system journeys with the JSON reporter first).`);\n } else {\n journeyReport = displayPath(root, journeyPath);\n const parsed = readJson(journeyPath);\n if (parsed === undefined) {\n problems.push(`${journeyReport} is not valid JSON, so the journey checks did not run.`);\n } else {\n const journeys = readSiteSystemJourneyReport(parsed);\n findings.push(...journeys.findings);\n problems.push(...journeys.problems);\n journeyTests = journeys.tests;\n }\n }\n\n // Rendered and static rule modules over the sampled pages.\n const buildDir = resolveIn(root, options.buildDir);\n const prerenderManifest = readJson(join(buildDir, \"prerender-manifest.json\"));\n const paths = planSiteSystemSamplePaths({\n representativeRoutes: config.representativeRoutes,\n samples: config.siteSystem?.samples ?? [],\n prerenderManifest,\n });\n if (!options.baseUrl && prerenderManifest === undefined) {\n problems.push(`No production build at ${displayPath(root, buildDir)}: run next build first, or pass --base-url.`);\n }\n const loaded = options.baseUrl || prerenderManifest !== undefined\n ? await loadSiteSystemPages({ paths, buildDir, baseUrl: options.baseUrl, fetch: dependencies.fetch })\n : { pages: [], missing: paths, source: \"build\" as const, problems: [] };\n problems.push(...loaded.problems);\n if (loaded.pages.length === 0) problems.push(\"No page HTML was available, so the rule modules ran on the project files only.\");\n // Every runner runs: static rules read the project, rendered rules report not-applicable without pages.\n const runners = dependencies.runners ?? SITE_SYSTEM_RENDERED_RUNNERS;\n const rendered = await runSiteSystemRenderedRunners(runners, {\n baseUrl: options.baseUrl ?? \"\",\n pages: loaded.pages,\n missing: loaded.missing,\n projectRoot: root,\n siteSystem: config.siteSystem,\n });\n findings.push(...rendered.findings);\n problems.push(...rendered.problems);\n\n // Fail closed: a config the gate cannot read in full, and (for a declared tier) pages it could not read.\n const blockers: string[] = [];\n if (!config.complete) blockers.push(\"brandlab.config.ts could not be read in full\");\n if (config.siteSystem) {\n if (loaded.source === \"base-url\" && loaded.missing.length > 0) {\n blockers.push(`${loaded.missing.length} sample page${loaded.missing.length === 1 ? \"\" : \"s\"} did not answer with HTML`);\n } else {\n if (loaded.missing.includes(\"/\")) blockers.push(\"the home page could not be read\");\n const contact = config.representativeRoutes.contact;\n if (contact && loaded.missing.includes(contact)) blockers.push(\"the contact page could not be read\");\n }\n }\n\n // Results other tools wrote as SiteSystemFinding JSON.\n for (const file of options.findings) {\n const path = resolveIn(root, file);\n const parsed = readJson(path);\n const list = Array.isArray(parsed) ? parsed : isRecord(parsed) && Array.isArray(parsed.findings) ? parsed.findings : null;\n if (!list) {\n problems.push(`${displayPath(root, path)} is missing or is not a list of findings, so it was ignored.`);\n continue;\n }\n const valid = list.filter(isSiteSystemFinding);\n if (valid.length < list.length) {\n problems.push(`${list.length - valid.length} result(s) in ${displayPath(root, path)} name an unknown check or status, so they were ignored.`);\n }\n // Supplied files carry harness and recorded results only; they cannot pass a journey or rule check.\n const refused = [...new Set(valid.filter((finding) => !SUPPLIABLE_IDS.has(finding.checkId)).map((finding) => finding.checkId))];\n if (refused.length > 0) {\n problems.push(`${displayPath(root, path)} sets ${refused.join(\", \")}, but --findings may only set ${[...SUPPLIABLE_IDS].join(\" and \")}, so those results were ignored.`);\n }\n findings.push(...valid.filter((finding) => SUPPLIABLE_IDS.has(finding.checkId)));\n }\n\n // The existing brandlab-verify families the shell tier carries.\n let verify: SiteSystemVerifyResult | null = null;\n try {\n verify = evaluateBrandlabProject({\n root,\n ...(options.installedRelease !== undefined ? { installedRelease: options.installedRelease } : {}),\n });\n } catch (error) {\n problems.push(`brandlab-verify could not run (${errorMessage(error)}), so its search, contact and analytics checks did not run.`);\n }\n\n return buildSiteSystemReadyReport({\n projectId: config.projectId,\n siteSystem: config.siteSystem,\n release,\n findings,\n verify,\n launchRecords: readSiteSystemRecords(root, \"launch\"),\n humanRecords: readSiteSystemRecords(root, \"human\"),\n exceptions: config.exceptions,\n inputs: {\n journeyReport,\n journeyTests,\n pageSource: loaded.pages.length === 0 ? \"none\" : loaded.source,\n pages: loaded.pages.map((page) => page.path),\n runners: runners.length,\n findingFiles: options.findings.map((file) => displayPath(root, resolveIn(root, file))),\n },\n problems,\n now,\n launch: options.launch,\n blockers,\n });\n}\n\nfunction readPackageJson(root: string): Parameters<typeof detectInstalledBrandlabRelease>[0] {\n const parsed = readJson(join(root, \"package.json\"));\n return isRecord(parsed) ? (parsed as Parameters<typeof detectInstalledBrandlabRelease>[0]) : null;\n}\n\n/** Parsed JSON, or undefined when the file is missing or invalid. */\nfunction readJson(path: string): unknown {\n if (!existsSync(path)) return undefined;\n try {\n return JSON.parse(readFileSync(path, \"utf8\"));\n } catch {\n return undefined;\n }\n}\n\nfunction resolveIn(root: string, path: string): string {\n return isAbsolute(path) ? path : resolve(root, path);\n}\n\nfunction displayPath(root: string, path: string): string {\n const relativePath = relative(root, path);\n return relativePath && !relativePath.startsWith(\"..\") && !isAbsolute(relativePath) ? relativePath : path;\n}\n\nfunction requireValue(argv: readonly string[], index: number, argument: string): string {\n const value = argv[index];\n if (value === undefined || value.startsWith(\"--\")) throw new Error(`${argument} requires a value.`);\n return value;\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function isBrandlabReadyCliEntrypoint(moduleUrl: string, argvPath: string | undefined): boolean {\n if (!argvPath) return false;\n try {\n return realpathSync(fileURLToPath(moduleUrl)) === realpathSync(resolve(argvPath));\n } catch {\n return false;\n }\n}\n\nif (isBrandlabReadyCliEntrypoint(import.meta.url, process.argv[1])) {\n runBrandlabReadyCli(process.argv.slice(2)).then((code) => {\n process.exitCode = code;\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ready-cli.js","sourceRoot":"","sources":["../src/ready-cli.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\nimport { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from \"node:fs\";\nimport { dirname, isAbsolute, join, relative, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { detectInstalledBrandlabRelease, evaluateBrandlabProject } from \"./project.js\";\nimport type { SiteSystemFinding } from \"./site-system/checks.js\";\nimport { readSiteSystemProjectConfig } from \"./site-system/config.js\";\nimport { readSiteSystemJourneyReport } from \"./site-system/playwright-report.js\";\nimport { appendSiteSystemRecord, readSiteSystemRecords } from \"./site-system/records.js\";\nimport {\n buildSiteSystemReadyReport,\n renderSiteSystemReadyMarkdown,\n SITE_SYSTEM_READY_REPORT_PATHS,\n type SiteSystemReadyReport,\n type SiteSystemVerifyResult,\n} from \"./site-system/report.js\";\nimport { SITE_SYSTEM_RENDERED_RUNNERS } from \"./site-system/rule-modules.js\";\nimport {\n isSiteSystemFinding,\n runSiteSystemRenderedRunners,\n type SiteSystemRenderedRunner,\n} from \"./site-system/runners.js\";\nimport { loadSiteSystemPages, planSiteSystemSamplePaths, type SiteSystemFetch } from \"./site-system/samples.js\";\nimport { SITE_SYSTEM_RECORDED_CHECK_IDS } from \"./site-system/steps.js\";\n\ninterface ReadyReportOptions {\n command: \"report\";\n root: string;\n playwrightReport: string;\n baseUrl?: string;\n buildDir: string;\n findings: string[];\n installedRelease?: string;\n launch: boolean;\n}\n\ninterface ReadyRecordOptions {\n command: \"record\";\n root: string;\n id: string;\n evidence?: string;\n note?: string;\n}\n\ntype ReadyCliOptions = ReadyReportOptions | ReadyRecordOptions | { command: \"help\" };\n\ninterface CliIo {\n stdout: (value: string) => void;\n stderr: (value: string) => void;\n}\n\nexport interface BrandlabReadyCliDependencies {\n /** The rule modules to run (default: SITE_SYSTEM_RENDERED_RUNNERS). */\n runners?: readonly SiteSystemRenderedRunner[];\n fetch?: SiteSystemFetch;\n now?: () => Date;\n}\n\nconst DEFAULT_PLAYWRIGHT_REPORT = \"test-results/site-system.json\";\n/** The checks a --findings file may set: K10 (the lenient harness) and the other recorded checks. */\nconst SUPPLIABLE_IDS = new Set<string>(SITE_SYSTEM_RECORDED_CHECK_IDS);\nconst DEFAULT_BUILD_DIR = \".next\";\n\nconst HELP = `Brandlab ready gate\n\nWrites docs/ready/ready-report.md and .json for the Site System tier declared in\nbrandlab.config.ts (siteSystem: { tier }), and records launch-day and human steps.\n\nUsage:\n brandlab-ready [--root <path>]\n [--playwright-report <path>] journey results (default ${DEFAULT_PLAYWRIGHT_REPORT})\n [--base-url <url>] fetch the sample pages from the running site\n [--build-dir <path>] otherwise read their HTML from the build (default ${DEFAULT_BUILD_DIR})\n [--findings <path>]... K10 or X1 results as SiteSystemFinding JSON (the lenient harness)\n [--installed-release <version>]\n [--launch] also require every launch-day and human step\n brandlab-ready record <id> --evidence <where the proof is> [--note <text>] [--root <path>]\n\nExit status:\n 0 ready at the declared tier, or nothing blocks (no tier declared, or none of its checks released)\n 1 a blocking check failed or did not run, home or the contact page could not be read, a --base-url\n sample did not answer with HTML, or brandlab.config.ts could not be read in full\n (with --launch, also a step not recorded)\n 2 the gate could not run (bad arguments, an unreadable config or records file)\n`;\n\nexport function parseBrandlabReadyArgs(argv: readonly string[]): ReadyCliOptions {\n if (argv.includes(\"--help\") || argv.includes(\"-h\")) return { command: \"help\" };\n if (argv[0] === \"record\") return parseRecordArgs(argv.slice(1));\n const parsed: ReadyReportOptions = {\n command: \"report\",\n root: process.cwd(),\n playwrightReport: DEFAULT_PLAYWRIGHT_REPORT,\n buildDir: DEFAULT_BUILD_DIR,\n findings: [],\n launch: false,\n };\n for (let index = 0; index < argv.length; index += 1) {\n const argument = argv[index];\n if (argument === \"--root\") parsed.root = resolve(requireValue(argv, ++index, argument));\n else if (argument === \"--playwright-report\") parsed.playwrightReport = requireValue(argv, ++index, argument);\n else if (argument === \"--build-dir\") parsed.buildDir = requireValue(argv, ++index, argument);\n else if (argument === \"--findings\") parsed.findings.push(requireValue(argv, ++index, argument));\n else if (argument === \"--installed-release\") parsed.installedRelease = requireValue(argv, ++index, argument);\n else if (argument === \"--launch\") parsed.launch = true;\n else if (argument === \"--base-url\") {\n const value = requireValue(argv, ++index, argument);\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw new Error(`--base-url ${value} is not a URL.`);\n }\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") throw new Error(\"--base-url must be an http or https URL.\");\n parsed.baseUrl = value;\n } else {\n throw new Error(`Unknown argument ${argument}.`);\n }\n }\n return parsed;\n}\n\nfunction parseRecordArgs(argv: readonly string[]): ReadyRecordOptions {\n const parsed: ReadyRecordOptions = { command: \"record\", root: process.cwd(), id: \"\" };\n for (let index = 0; index < argv.length; index += 1) {\n const argument = argv[index]!;\n if (argument === \"--evidence\") parsed.evidence = requireValue(argv, ++index, argument);\n else if (argument === \"--note\") parsed.note = requireValue(argv, ++index, argument);\n else if (argument === \"--root\") parsed.root = resolve(requireValue(argv, ++index, argument));\n else if (!argument.startsWith(\"--\") && !parsed.id) parsed.id = argument;\n else throw new Error(`Unknown argument ${argument}.`);\n }\n if (!parsed.id) throw new Error(\"record needs a step id, for example: brandlab-ready record X3 --evidence <PR link>.\");\n if (parsed.evidence === undefined) throw new Error(`record ${parsed.id} needs --evidence <where the proof is>.`);\n return parsed;\n}\n\nexport async function runBrandlabReadyCli(\n argv: readonly string[],\n io: CliIo = {\n stdout: (value) => process.stdout.write(value),\n stderr: (value) => process.stderr.write(value),\n },\n dependencies: BrandlabReadyCliDependencies = {},\n): Promise<number> {\n let options: ReadyCliOptions;\n try {\n options = parseBrandlabReadyArgs(argv);\n } catch (error) {\n io.stderr(`${errorMessage(error)}\\n\\n${HELP}`);\n return 2;\n }\n if (options.command === \"help\") {\n io.stdout(HELP);\n return 0;\n }\n const now = dependencies.now ?? (() => new Date());\n try {\n if (options.command === \"record\") {\n const { path, record } = appendSiteSystemRecord(options.root, {\n id: options.id,\n evidence: options.evidence ?? \"\",\n ...(options.note !== undefined ? { note: options.note } : {}),\n now: now(),\n });\n io.stdout(`Recorded ${record.id} in ${path}.\\n`);\n return 0;\n }\n const report = await createReadyReport(options, dependencies, now());\n const markdownPath = join(options.root, SITE_SYSTEM_READY_REPORT_PATHS.markdown);\n mkdirSync(dirname(markdownPath), { recursive: true });\n writeFileSync(markdownPath, renderSiteSystemReadyMarkdown(report));\n writeFileSync(join(options.root, SITE_SYSTEM_READY_REPORT_PATHS.json), `${JSON.stringify(report, null, 2)}\\n`);\n const problems = report.problems.length;\n io.stdout(\n `${report.verdict.summary}.\\n` +\n (problems > 0 ? `The report lists ${problems} problem${problems === 1 ? \"\" : \"s\"} with the inputs.\\n` : \"\") +\n `Wrote ${SITE_SYSTEM_READY_REPORT_PATHS.markdown} and ${SITE_SYSTEM_READY_REPORT_PATHS.json}.\\n`,\n );\n return report.verdict.exitCode;\n } catch (error) {\n io.stderr(`${errorMessage(error)}\\n`);\n return 2;\n }\n}\n\nasync function createReadyReport(\n options: ReadyReportOptions,\n dependencies: BrandlabReadyCliDependencies,\n now: Date,\n): Promise<SiteSystemReadyReport> {\n const root = options.root;\n const config = readSiteSystemProjectConfig(root);\n const release = options.installedRelease ?? detectInstalledBrandlabRelease(readPackageJson(root));\n if (config.siteSystem && !release) {\n throw new Error(\n \"The installed Brandlab release could not be read from package.json. Pin all four Brandlab packages to one exact version, or pass --installed-release.\",\n );\n }\n const problems: string[] = [...config.problems];\n const findings: SiteSystemFinding[] = [];\n\n // Journeys: the Playwright JSON report of the site-system spec.\n const journeyPath = resolveIn(root, options.playwrightReport);\n let journeyReport: string | null = null;\n let journeyTests = 0;\n if (!existsSync(journeyPath)) {\n problems.push(`No Playwright report at ${displayPath(root, journeyPath)}, so the journey checks did not run (run the site-system journeys with the JSON reporter first).`);\n } else {\n journeyReport = displayPath(root, journeyPath);\n const parsed = readJson(journeyPath);\n if (parsed === undefined) {\n problems.push(`${journeyReport} is not valid JSON, so the journey checks did not run.`);\n } else {\n const journeys = readSiteSystemJourneyReport(parsed);\n findings.push(...journeys.findings);\n problems.push(...journeys.problems);\n journeyTests = journeys.tests;\n }\n }\n\n // Rendered and static rule modules over the sampled pages.\n const buildDir = resolveIn(root, options.buildDir);\n const prerenderManifest = readJson(join(buildDir, \"prerender-manifest.json\"));\n const paths = planSiteSystemSamplePaths({\n representativeRoutes: config.representativeRoutes,\n samples: config.siteSystem?.samples ?? [],\n prerenderManifest,\n });\n if (!options.baseUrl && prerenderManifest === undefined) {\n problems.push(`No production build at ${displayPath(root, buildDir)}: run next build first, or pass --base-url.`);\n }\n const loaded = options.baseUrl || prerenderManifest !== undefined\n ? await loadSiteSystemPages({ paths, buildDir, baseUrl: options.baseUrl, fetch: dependencies.fetch })\n : { pages: [], missing: paths, source: \"build\" as const, problems: [] };\n problems.push(...loaded.problems);\n if (loaded.pages.length === 0) problems.push(\"No page HTML was available, so the rule modules ran on the project files only.\");\n // Every runner runs: static rules read the project, rendered rules report not-applicable without pages.\n const runners = dependencies.runners ?? SITE_SYSTEM_RENDERED_RUNNERS;\n const rendered = await runSiteSystemRenderedRunners(runners, {\n baseUrl: options.baseUrl ?? \"\",\n pages: loaded.pages,\n missing: loaded.missing,\n projectRoot: root,\n siteSystem: config.siteSystem,\n buildDir,\n });\n findings.push(...rendered.findings);\n problems.push(...rendered.problems);\n\n // Fail closed: a config the gate cannot read in full, and (for a declared tier) pages it could not read.\n const blockers: string[] = [];\n if (!config.complete) blockers.push(\"brandlab.config.ts could not be read in full\");\n if (config.siteSystem) {\n if (loaded.source === \"base-url\" && loaded.missing.length > 0) {\n blockers.push(`${loaded.missing.length} sample page${loaded.missing.length === 1 ? \"\" : \"s\"} did not answer with HTML`);\n } else {\n if (loaded.missing.includes(\"/\")) blockers.push(\"the home page could not be read\");\n const contact = config.representativeRoutes.contact;\n if (contact && loaded.missing.includes(contact)) blockers.push(\"the contact page could not be read\");\n }\n }\n\n // Results other tools wrote as SiteSystemFinding JSON.\n for (const file of options.findings) {\n const path = resolveIn(root, file);\n const parsed = readJson(path);\n const list = Array.isArray(parsed) ? parsed : isRecord(parsed) && Array.isArray(parsed.findings) ? parsed.findings : null;\n if (!list) {\n problems.push(`${displayPath(root, path)} is missing or is not a list of findings, so it was ignored.`);\n continue;\n }\n const valid = list.filter(isSiteSystemFinding);\n if (valid.length < list.length) {\n problems.push(`${list.length - valid.length} result(s) in ${displayPath(root, path)} name an unknown check or status, so they were ignored.`);\n }\n // Supplied files carry harness and recorded results only; they cannot pass a journey or rule check.\n const refused = [...new Set(valid.filter((finding) => !SUPPLIABLE_IDS.has(finding.checkId)).map((finding) => finding.checkId))];\n if (refused.length > 0) {\n problems.push(`${displayPath(root, path)} sets ${refused.join(\", \")}, but --findings may only set ${[...SUPPLIABLE_IDS].join(\" and \")}, so those results were ignored.`);\n }\n findings.push(...valid.filter((finding) => SUPPLIABLE_IDS.has(finding.checkId)));\n }\n\n // The existing brandlab-verify families the shell tier carries.\n let verify: SiteSystemVerifyResult | null = null;\n try {\n verify = evaluateBrandlabProject({\n root,\n ...(options.installedRelease !== undefined ? { installedRelease: options.installedRelease } : {}),\n });\n } catch (error) {\n problems.push(`brandlab-verify could not run (${errorMessage(error)}), so its search, contact and analytics checks did not run.`);\n }\n\n return buildSiteSystemReadyReport({\n projectId: config.projectId,\n siteSystem: config.siteSystem,\n release,\n findings,\n verify,\n launchRecords: readSiteSystemRecords(root, \"launch\"),\n humanRecords: readSiteSystemRecords(root, \"human\"),\n exceptions: config.exceptions,\n inputs: {\n journeyReport,\n journeyTests,\n pageSource: loaded.pages.length === 0 ? \"none\" : loaded.source,\n pages: loaded.pages.map((page) => page.path),\n runners: runners.length,\n findingFiles: options.findings.map((file) => displayPath(root, resolveIn(root, file))),\n },\n problems,\n now,\n launch: options.launch,\n blockers,\n });\n}\n\nfunction readPackageJson(root: string): Parameters<typeof detectInstalledBrandlabRelease>[0] {\n const parsed = readJson(join(root, \"package.json\"));\n return isRecord(parsed) ? (parsed as Parameters<typeof detectInstalledBrandlabRelease>[0]) : null;\n}\n\n/** Parsed JSON, or undefined when the file is missing or invalid. */\nfunction readJson(path: string): unknown {\n if (!existsSync(path)) return undefined;\n try {\n return JSON.parse(readFileSync(path, \"utf8\"));\n } catch {\n return undefined;\n }\n}\n\nfunction resolveIn(root: string, path: string): string {\n return isAbsolute(path) ? path : resolve(root, path);\n}\n\nfunction displayPath(root: string, path: string): string {\n const relativePath = relative(root, path);\n return relativePath && !relativePath.startsWith(\"..\") && !isAbsolute(relativePath) ? relativePath : path;\n}\n\nfunction requireValue(argv: readonly string[], index: number, argument: string): string {\n const value = argv[index];\n if (value === undefined || value.startsWith(\"--\")) throw new Error(`${argument} requires a value.`);\n return value;\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function isBrandlabReadyCliEntrypoint(moduleUrl: string, argvPath: string | undefined): boolean {\n if (!argvPath) return false;\n try {\n return realpathSync(fileURLToPath(moduleUrl)) === realpathSync(resolve(argvPath));\n } catch {\n return false;\n }\n}\n\nif (isBrandlabReadyCliEntrypoint(import.meta.url, process.argv[1])) {\n runBrandlabReadyCli(process.argv.slice(2)).then((code) => {\n process.exitCode = code;\n });\n}\n"]}
|
|
@@ -337,7 +337,7 @@ export declare const SITE_SYSTEM_CHECKS: readonly [{
|
|
|
337
337
|
readonly tier: "full";
|
|
338
338
|
readonly from: "3.12.0";
|
|
339
339
|
readonly kind: "rendered";
|
|
340
|
-
readonly summary: "Data contract on service-
|
|
340
|
+
readonly summary: "Data contract on service-in-suburb pages: typical prices or the cost-guide link, reviews or their fallback, the quote path (form with the suburb prefilled, phone, call bar); the nearby job card or none.";
|
|
341
341
|
}, {
|
|
342
342
|
readonly id: "L10";
|
|
343
343
|
readonly tier: "full";
|
|
@@ -69,7 +69,7 @@ export const SITE_SYSTEM_CHECKS = [
|
|
|
69
69
|
{ id: "L6", tier: "full", from: "3.12.0", kind: "static", summary: "Location pages have 6 or more inbound links from 3 or more page types." },
|
|
70
70
|
{ id: "L7", tier: "full", from: "3.12.0", kind: "static", summary: "Location pages are 3 clicks or fewer from home." },
|
|
71
71
|
{ id: "L8", tier: "full", from: "3.12.0", kind: "static", summary: "A hub per family per region." },
|
|
72
|
-
{ id: "L9", tier: "full", from: "3.12.0", kind: "rendered", summary: "Data contract on service-
|
|
72
|
+
{ id: "L9", tier: "full", from: "3.12.0", kind: "rendered", summary: "Data contract on service-in-suburb pages: typical prices or the cost-guide link, reviews or their fallback, the quote path (form with the suburb prefilled, phone, call bar); the nearby job card or none." },
|
|
73
73
|
{ id: "L10", tier: "full", from: "3.12.0", kind: "rendered", summary: 'No kilometre figures, "km from", "based in" or year stamps as local detail in location copy.' },
|
|
74
74
|
{ id: "S4", tier: "full", from: "3.12.0", kind: "static", summary: "No hand-written per-service or per-suburb files; no dynamic route with zero pages." },
|
|
75
75
|
{ id: "LOC-INDEX", tier: "full", from: "3.12.0", kind: "static", summary: "No location route is noindex or left out of the sitemap unless the recorded wave schedule dates it (Romie's 20 Oct decision: every suburb page stays indexed)." },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checks.js","sourceRoot":"","sources":["../../src/site-system/checks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAU,CAAC;AAiBvE,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,8GAA8G;IAC9G,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,qIAAqI,EAAE;IAC5M,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,qEAAqE,EAAE;IAC5I,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,wGAAwG,EAAE;IAC9K,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,gHAAgH,EAAE;IACtL,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,mIAAmI,EAAE;IACzM,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,wIAAwI,EAAE;IAC9M,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,+HAA+H,EAAE;IACrM,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,8GAA8G,EAAE;IACrL,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,sDAAsD,EAAE;IAC5H,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,4EAA4E,EAAE;IAClJ,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,iGAAiG,EAAE;IACvK,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,6FAA6F,EAAE;IACnK,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,uFAAuF,EAAE;IAC9J,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,6FAA6F,EAAE;IACnK,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,mGAAmG,EAAE;IACzK,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,sEAAsE,EAAE;IAC7I,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,8CAA8C,EAAE;IACrH,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,uGAAuG,EAAE;IAC/K,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,mEAAmE,EAAE;IACxI,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,8CAA8C,EAAE;IACrH,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,+EAA+E,EAAE;IACtJ,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,kGAAkG,EAAE;IACzK,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,sFAAsF,EAAE;IAC7J,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,4FAA4F,EAAE;IAClK,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,gGAAgG,EAAE;IACrK,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,6IAA6I,EAAE;IACpN,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,6DAA6D,EAAE;IAE1I,kHAAkH;IAClH,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,2IAA2I,EAAE;IACnN,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,mHAAmH,EAAE;IAC5L,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,iFAAiF,EAAE;IAC1J,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,uIAAuI,EAAE;IAChN,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,kIAAkI,EAAE;IAC3M,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,gEAAgE,EAAE;IAC1I,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,mHAAmH,EAAE;IAC7L,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,0FAA0F,EAAE;IACnK,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,8KAA8K,EAAE;IACxP,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,kFAAkF,EAAE;IAC5J,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,yIAAyI,EAAE;IACpN,EAAE,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,gFAAgF,EAAE;IACnK,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,mDAAmD,EAAE;IAC3H,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,0CAA0C,EAAE;IACpH,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,uGAAuG,EAAE;IACjL,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,gDAAgD,EAAE;IAExH,wFAAwF;IACxF,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,0KAA0K,EAAE;IAClP,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,oEAAoE,EAAE;IACzI,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,2IAA2I,EAAE;IACjN,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,8BAA8B,EAAE;IACnG,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,wGAAwG,EAAE;IAC/K,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,wEAAwE,EAAE;IAC7I,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,iDAAiD,EAAE;IACtH,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,8BAA8B,EAAE;IACnG,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,mIAAmI,EAAE;IAC1M,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,8FAA8F,EAAE;IACtK,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,oFAAoF,EAAE;IACzJ,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,gKAAgK,EAAE;IAE5O,2BAA2B;IAC3B,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,2IAA2I,EAAE;CACvK,CAAC;AAIhD,MAAM,SAAS,GAAmC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;AAEpF,8DAA8D;AAC9D,MAAM,UAAU,qBAAqB,CAAC,OAAe;IACnD,MAAM,CAAC,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9G,OAAO,KAAK,GAAG,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AACnD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACnC,KAAoD,EACpD,IAAmE;IAEnE,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC,QAAQ,KAAK,IAAI,IAAI,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,qBAAqB,CAAC,OAAO,CAAC,CAAC;IACvI,IAAI,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,qBAAqB,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1F,OAAO,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACvD,CAAC","sourcesContent":["/**\n * The Site System v2 ready gate: every check, the adoption tier it blocks at and the release that brings it.\n *\n * A site declares `siteSystem: { tier }` in brandlab.config.ts. Checks of that tier and the tiers below it block;\n * checks of higher tiers report without blocking. A check blocks only from the release named here, so new checks\n * arrive with version bumps and never turn the fleet red at once. Holdouts use the project's Romie-owned\n * `exceptions` record. D6 (leave reviews as they are) removes every review-exclusion clause; D7 (no call tracking)\n * means no number-swap check.\n *\n * `kind` says where a check runs:\n * - `journey`: the Playwright site-system journeys (`defineBrandlabSiteSystemTests`), in the site's e2e run;\n * - `rendered`: rules over the built site's server HTML and assets (`brandlab-ready` reads them);\n * - `static`: source and data rules (`brandlab-verify` and `brandlab-ready`);\n * - `record`: launch-day and human steps recorded with `brandlab-ready record <id> --evidence <ref>`.\n */\n\nexport const SITE_SYSTEM_TIERS = [\"shell\", \"enquiry\", \"full\"] as const;\nexport type SiteSystemTier = (typeof SITE_SYSTEM_TIERS)[number];\n\n/** The design check D4 blocks every new build and redesign, whatever its tier. */\nexport type SiteSystemCheckScope = SiteSystemTier | \"new-build\";\n\nexport type SiteSystemCheckKind = \"journey\" | \"rendered\" | \"static\" | \"record\";\n\nexport interface SiteSystemCheck {\n readonly id: string;\n readonly tier: SiteSystemCheckScope;\n /** The first release in which the check blocks at its tier. */\n readonly from: `3.${number}.0`;\n readonly kind: SiteSystemCheckKind;\n readonly summary: string;\n}\n\nexport const SITE_SYSTEM_CHECKS = [\n // shell: header, nav, call bar, placements, crawlable links, contrast and targets, call links, budgets, legal\n { id: \"N1\", tier: \"shell\", from: \"3.9.0\", kind: \"rendered\", summary: \"Required nav links, About in the first two, services before Areas, Contact last, labels from the closed list, recorded orders kept.\" },\n { id: \"N2\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"Every dropdown link and hub link is an <a href> in the server HTML.\" },\n { id: \"N3\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"Hover opens after a short delay and a diagonal path stays open; mouse-out closes; nothing sticks open.\" },\n { id: \"N4\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"A chevron click after hover keeps the panel open; a link click closes it; click, Enter and outside click work.\" },\n { id: \"N5\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"Keyboard and ARIA: aria-expanded follows the panel, Arrow keys move, Escape closes and returns focus; axe passes open and closed.\" },\n { id: \"N6\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"The header stays at the top with the phone and quote visible at every desktop width; the compact band shows them from 1024 to 1279 px.\" },\n { id: \"N8\", tier: \"shell\", from: \"3.9.0\", kind: \"journey\", summary: \"The drawer is a modal dialog that traps focus and resets; the call bar uses placement fab; back-to-top appears (from 3.11.0).\" },\n { id: \"K1\", tier: \"shell\", from: \"3.9.0\", kind: \"rendered\", summary: \"Shared components in use for the parts the tier covers (data-bl present); no literal tel: outside PhoneLink.\" },\n { id: \"K3\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"Text contrast 4.5:1 and non-text 3:1 in the browser.\" },\n { id: \"K4\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"Targets at least 24 px, and 44 px for primary actions (call, quote, menu).\" },\n { id: \"K5\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"Focus is never fully hidden by the sticky header or call bar at 390 px, in Chromium and WebKit.\" },\n { id: \"K6\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"Phone and quote in the same relative order on every page, in the header, hero and call bar.\" },\n { id: \"K7\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"Dropdown links, accordion and tab panels and full review text are in the server HTML.\" },\n { id: \"K10\", tier: \"shell\", from: \"3.8.0\", kind: \"record\", summary: \"Adoption parity in the lenient harness: no section, link or text lost against the baseline.\" },\n { id: \"C4\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"Phone taps report an allowed placement (header, footer, hero, cta, fab, contact, location, page).\" },\n { id: \"C5\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"Call-to-action labels come from the closed list or a recorded label.\" },\n { id: \"C9\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"No interstitial overlay in the first screen.\" },\n { id: \"C10\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"Every tel: href is E.164 (national digits for 13, 1300 and 1800) and matches the evidence-file phone.\" },\n { id: \"E1\", tier: \"shell\", from: \"3.8.0\", kind: \"static\", summary: \"Title patterns on new or changed URLs; recorded titles unchanged.\" },\n { id: \"E2\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"Exactly one H1 on every page, rendered once.\" },\n { id: \"E8\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"No banned phrase from any of the three layers, environmental claims included.\" },\n { id: \"T3\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"A licence line renders wherever licensed work is advertised, with the licensee where it differs.\" },\n { id: \"T4\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"No hard-coded rating or review numbers; proof claims resolve to renderable evidence.\" },\n { id: \"T11\", tier: \"shell\", from: \"3.8.0\", kind: \"static\", summary: \"No page for work over $5,000 outside the licence classes held; licence conditions carried.\" },\n { id: \"X1\", tier: \"shell\", from: \"3.8.0\", kind: \"record\", summary: \"Legacy URLs answer 200 or one redirect hop; earning-URL depth, titles and dollar figures kept.\" },\n { id: \"B1\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"Lab budgets: JavaScript, third-party requests, hero image and HTML within budget; no unrecorded chat widget, pixel, heatmap or tag manager.\" },\n { id: \"L10-hero\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: 'No kilometre figures, \"km from\" or \"based in\" in hero copy.' },\n\n // enquiry: the form, thank-you page, reviews, proof strip, footer, CTA band, contact page, prices, media, density\n { id: \"C1\", tier: \"enquiry\", from: \"3.8.0\", kind: \"journey\", summary: \"Money pages: the form in the first section; at 390 x 844 the H1, a call and a quote action in the first viewport; at 1440 x 900 the form.\" },\n { id: \"C2\", tier: \"enquiry\", from: \"3.8.0\", kind: \"rendered\", summary: 'Form layout and labels; phone and email required; no helper or reassurance lines, no \"(required)\", no job select.' },\n { id: \"E9\", tier: \"enquiry\", from: \"3.8.0\", kind: \"rendered\", summary: \"Every cost guide carries at least 8 dollar figures in a renderable price state.\" },\n { id: \"T5\", tier: \"enquiry\", from: \"3.8.0\", kind: \"rendered\", summary: \"Reviews from the feed, with Google's rating, count and link beside any selection; none on the contact page; no empty reviews section.\" },\n { id: \"K8\", tier: \"enquiry\", from: \"3.8.0\", kind: \"rendered\", summary: \"Section contract: no empty section, one H2 each, at most one band tone, neighbours differ, proof within the first five sections.\" },\n { id: \"C7\", tier: \"enquiry\", from: \"3.10.0\", kind: \"rendered\", summary: \"Thank-you page: a reply time, a tel: link and noindex, follow.\" },\n { id: \"C8\", tier: \"enquiry\", from: \"3.10.0\", kind: \"rendered\", summary: \"Forgiving form: tolerant phone input (13, 1300 and 1800 too), autocomplete tokens, no capture on the photo input.\" },\n { id: \"C11\", tier: \"enquiry\", from: \"3.10.0\", kind: \"static\", summary: \"The test marker is stripped before delivery and reporting; /api/contact is rate-limited.\" },\n { id: \"N9\", tier: \"enquiry\", from: \"3.11.0\", kind: \"rendered\", summary: 'Footer content: column 1 brand, licences, socials and contact; services, areas and company columns; © name, ABN and legal links; no CTA, \"based in\", hours or guides column.' },\n { id: \"K2\", tier: \"enquiry\", from: \"3.11.0\", kind: \"rendered\", summary: \"Every rendered shared component has a skin entry; no reference-skin class ships.\" },\n { id: \"K11\", tier: \"enquiry\", from: \"3.11.0\", kind: \"rendered\", summary: \"Density: no section with more than one H2, more than 8 cards or more than 2 calls to action; measure and section padding within limits.\" },\n { id: \"K12-contact\", tier: \"enquiry\", from: \"3.11.0\", kind: \"rendered\", summary: \"The contact page is the page header, then the contact block, and nothing else.\" },\n { id: \"T6\", tier: \"enquiry\", from: \"3.11.0\", kind: \"static\", summary: \"Every image has a media.ts entry with provenance.\" },\n { id: \"T7\", tier: \"enquiry\", from: \"3.11.0\", kind: \"rendered\", summary: \"No image is the main image of two pages.\" },\n { id: \"T8\", tier: \"enquiry\", from: \"3.11.0\", kind: \"rendered\", summary: 'Prices: GST flag set; no \"+ GST\" or \"from $X\" teasers on cards and menus; one band per job site-wide.' },\n { id: \"T9\", tier: \"enquiry\", from: \"3.11.0\", kind: \"static\", summary: \"No image in /public carries location metadata.\" },\n\n // full: page families, location estates, section manifests, links and the data contract\n { id: \"K12\", tier: \"full\", from: \"3.12.0\", kind: \"rendered\", summary: \"Section manifest: every required section rendered or skipped with a data-backed reason; conditional sections render when their data exists; canonical or recorded order.\" },\n { id: \"E5\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"No orphan indexable pages, from the route catalogue and link data.\" },\n { id: \"E10\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"Phrase-owner uniqueness in strategy data; no service-in-suburb page for the suburb page phrase; no service-region hub for the main trade.\" },\n { id: \"L3\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"Neighbours by real distance.\" },\n { id: \"L4\", tier: \"full\", from: \"3.12.0\", kind: \"rendered\", summary: \"No copy rotated by page address, no name-swapped FAQs, no other suburb's job without the nearby label.\" },\n { id: \"L6\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"Location pages have 6 or more inbound links from 3 or more page types.\" },\n { id: \"L7\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"Location pages are 3 clicks or fewer from home.\" },\n { id: \"L8\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"A hub per family per region.\" },\n { id: \"L9\", tier: \"full\", from: \"3.12.0\", kind: \"rendered\", summary: \"Data contract on service-location pages: price or cost-guide link, reviews or fallback, local facts; the nearby job card or none.\" },\n { id: \"L10\", tier: \"full\", from: \"3.12.0\", kind: \"rendered\", summary: 'No kilometre figures, \"km from\", \"based in\" or year stamps as local detail in location copy.' },\n { id: \"S4\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"No hand-written per-service or per-suburb files; no dynamic route with zero pages.\" },\n { id: \"LOC-INDEX\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"No location route is noindex or left out of the sitemap unless the recorded wave schedule dates it (Romie's 20 Oct decision: every suburb page stays indexed).\" },\n\n // new builds and redesigns\n { id: \"D4\", tier: \"new-build\", from: \"3.8.0\", kind: \"static\", summary: \"Same-trade distinctness: at least four of seven look levers differ from every listed competitor (advisory in 3.8.0, blocking from 3.9.0).\" },\n] as const satisfies readonly SiteSystemCheck[];\n\nexport type SiteSystemCheckId = (typeof SITE_SYSTEM_CHECKS)[number][\"id\"];\n\nconst TIER_RANK: Record<SiteSystemTier, number> = { shell: 0, enquiry: 1, full: 2 };\n\n/** A release as one comparable number: \"3.8.0\" < \"3.10.0\". */\nexport function siteSystemReleaseRank(version: string): number {\n const [major = 0, minor = 0, patch = 0] = version.split(/[.-]/).map((part) => Number.parseInt(part, 10) || 0);\n return major * 1_000_000 + minor * 1_000 + patch;\n}\n\n/**\n * Whether a check blocks for a site at `tier` on `release`. Checks of higher tiers, and checks newer than the\n * installed release, report without blocking. D4 blocks new builds and redesigns from 3.9.0 whatever their tier.\n */\nexport function siteSystemCheckBlocks(\n check: Pick<SiteSystemCheck, \"id\" | \"tier\" | \"from\">,\n site: { tier: SiteSystemTier; release: string; newBuild?: boolean },\n): boolean {\n if (check.tier === \"new-build\") return site.newBuild === true && siteSystemReleaseRank(site.release) >= siteSystemReleaseRank(\"3.9.0\");\n if (siteSystemReleaseRank(site.release) < siteSystemReleaseRank(check.from)) return false;\n return TIER_RANK[check.tier] <= TIER_RANK[site.tier];\n}\n\n/** One result of one check, from any runner. `brandlab-ready` merges them into the ready report. */\nexport interface SiteSystemFinding {\n readonly checkId: SiteSystemCheckId;\n readonly status: \"pass\" | \"fail\" | \"not-applicable\";\n /** The page path or file the result is about, when it is about one. */\n readonly target?: string;\n /** One plain sentence: what passed or what is wrong and where. */\n readonly message: string;\n /** A warning never blocks: the check still passes and the report shows \"pass (warning)\". */\n readonly severity?: \"warning\";\n}\n"]}
|
|
1
|
+
{"version":3,"file":"checks.js","sourceRoot":"","sources":["../../src/site-system/checks.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Site System v2 ready gate: every check, the adoption tier it blocks at and the release that brings it.\n *\n * A site declares `siteSystem: { tier }` in brandlab.config.ts. Checks of that tier and the tiers below it block;\n * checks of higher tiers report without blocking. A check blocks only from the release named here, so new checks\n * arrive with version bumps and never turn the fleet red at once. Holdouts use the project's Romie-owned\n * `exceptions` record. D6 (leave reviews as they are) removes every review-exclusion clause; D7 (no call tracking)\n * means no number-swap check.\n *\n * `kind` says where a check runs:\n * - `journey`: the Playwright site-system journeys (`defineBrandlabSiteSystemTests`), in the site's e2e run;\n * - `rendered`: rules over the built site's server HTML and assets (`brandlab-ready` reads them);\n * - `static`: source and data rules (`brandlab-verify` and `brandlab-ready`);\n * - `record`: launch-day and human steps recorded with `brandlab-ready record <id> --evidence <ref>`.\n */\n\nexport const SITE_SYSTEM_TIERS = [\"shell\", \"enquiry\", \"full\"] as const;\nexport type SiteSystemTier = (typeof SITE_SYSTEM_TIERS)[number];\n\n/** The design check D4 blocks every new build and redesign, whatever its tier. */\nexport type SiteSystemCheckScope = SiteSystemTier | \"new-build\";\n\nexport type SiteSystemCheckKind = \"journey\" | \"rendered\" | \"static\" | \"record\";\n\nexport interface SiteSystemCheck {\n readonly id: string;\n readonly tier: SiteSystemCheckScope;\n /** The first release in which the check blocks at its tier. */\n readonly from: `3.${number}.0`;\n readonly kind: SiteSystemCheckKind;\n readonly summary: string;\n}\n\nexport const SITE_SYSTEM_CHECKS = [\n // shell: header, nav, call bar, placements, crawlable links, contrast and targets, call links, budgets, legal\n { id: \"N1\", tier: \"shell\", from: \"3.9.0\", kind: \"rendered\", summary: \"Required nav links, About in the first two, services before Areas, Contact last, labels from the closed list, recorded orders kept.\" },\n { id: \"N2\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"Every dropdown link and hub link is an <a href> in the server HTML.\" },\n { id: \"N3\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"Hover opens after a short delay and a diagonal path stays open; mouse-out closes; nothing sticks open.\" },\n { id: \"N4\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"A chevron click after hover keeps the panel open; a link click closes it; click, Enter and outside click work.\" },\n { id: \"N5\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"Keyboard and ARIA: aria-expanded follows the panel, Arrow keys move, Escape closes and returns focus; axe passes open and closed.\" },\n { id: \"N6\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"The header stays at the top with the phone and quote visible at every desktop width; the compact band shows them from 1024 to 1279 px.\" },\n { id: \"N8\", tier: \"shell\", from: \"3.9.0\", kind: \"journey\", summary: \"The drawer is a modal dialog that traps focus and resets; the call bar uses placement fab; back-to-top appears (from 3.11.0).\" },\n { id: \"K1\", tier: \"shell\", from: \"3.9.0\", kind: \"rendered\", summary: \"Shared components in use for the parts the tier covers (data-bl present); no literal tel: outside PhoneLink.\" },\n { id: \"K3\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"Text contrast 4.5:1 and non-text 3:1 in the browser.\" },\n { id: \"K4\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"Targets at least 24 px, and 44 px for primary actions (call, quote, menu).\" },\n { id: \"K5\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"Focus is never fully hidden by the sticky header or call bar at 390 px, in Chromium and WebKit.\" },\n { id: \"K6\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"Phone and quote in the same relative order on every page, in the header, hero and call bar.\" },\n { id: \"K7\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"Dropdown links, accordion and tab panels and full review text are in the server HTML.\" },\n { id: \"K10\", tier: \"shell\", from: \"3.8.0\", kind: \"record\", summary: \"Adoption parity in the lenient harness: no section, link or text lost against the baseline.\" },\n { id: \"C4\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"Phone taps report an allowed placement (header, footer, hero, cta, fab, contact, location, page).\" },\n { id: \"C5\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"Call-to-action labels come from the closed list or a recorded label.\" },\n { id: \"C9\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"No interstitial overlay in the first screen.\" },\n { id: \"C10\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"Every tel: href is E.164 (national digits for 13, 1300 and 1800) and matches the evidence-file phone.\" },\n { id: \"E1\", tier: \"shell\", from: \"3.8.0\", kind: \"static\", summary: \"Title patterns on new or changed URLs; recorded titles unchanged.\" },\n { id: \"E2\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"Exactly one H1 on every page, rendered once.\" },\n { id: \"E8\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"No banned phrase from any of the three layers, environmental claims included.\" },\n { id: \"T3\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"A licence line renders wherever licensed work is advertised, with the licensee where it differs.\" },\n { id: \"T4\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"No hard-coded rating or review numbers; proof claims resolve to renderable evidence.\" },\n { id: \"T11\", tier: \"shell\", from: \"3.8.0\", kind: \"static\", summary: \"No page for work over $5,000 outside the licence classes held; licence conditions carried.\" },\n { id: \"X1\", tier: \"shell\", from: \"3.8.0\", kind: \"record\", summary: \"Legacy URLs answer 200 or one redirect hop; earning-URL depth, titles and dollar figures kept.\" },\n { id: \"B1\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"Lab budgets: JavaScript, third-party requests, hero image and HTML within budget; no unrecorded chat widget, pixel, heatmap or tag manager.\" },\n { id: \"L10-hero\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: 'No kilometre figures, \"km from\" or \"based in\" in hero copy.' },\n\n // enquiry: the form, thank-you page, reviews, proof strip, footer, CTA band, contact page, prices, media, density\n { id: \"C1\", tier: \"enquiry\", from: \"3.8.0\", kind: \"journey\", summary: \"Money pages: the form in the first section; at 390 x 844 the H1, a call and a quote action in the first viewport; at 1440 x 900 the form.\" },\n { id: \"C2\", tier: \"enquiry\", from: \"3.8.0\", kind: \"rendered\", summary: 'Form layout and labels; phone and email required; no helper or reassurance lines, no \"(required)\", no job select.' },\n { id: \"E9\", tier: \"enquiry\", from: \"3.8.0\", kind: \"rendered\", summary: \"Every cost guide carries at least 8 dollar figures in a renderable price state.\" },\n { id: \"T5\", tier: \"enquiry\", from: \"3.8.0\", kind: \"rendered\", summary: \"Reviews from the feed, with Google's rating, count and link beside any selection; none on the contact page; no empty reviews section.\" },\n { id: \"K8\", tier: \"enquiry\", from: \"3.8.0\", kind: \"rendered\", summary: \"Section contract: no empty section, one H2 each, at most one band tone, neighbours differ, proof within the first five sections.\" },\n { id: \"C7\", tier: \"enquiry\", from: \"3.10.0\", kind: \"rendered\", summary: \"Thank-you page: a reply time, a tel: link and noindex, follow.\" },\n { id: \"C8\", tier: \"enquiry\", from: \"3.10.0\", kind: \"rendered\", summary: \"Forgiving form: tolerant phone input (13, 1300 and 1800 too), autocomplete tokens, no capture on the photo input.\" },\n { id: \"C11\", tier: \"enquiry\", from: \"3.10.0\", kind: \"static\", summary: \"The test marker is stripped before delivery and reporting; /api/contact is rate-limited.\" },\n { id: \"N9\", tier: \"enquiry\", from: \"3.11.0\", kind: \"rendered\", summary: 'Footer content: column 1 brand, licences, socials and contact; services, areas and company columns; © name, ABN and legal links; no CTA, \"based in\", hours or guides column.' },\n { id: \"K2\", tier: \"enquiry\", from: \"3.11.0\", kind: \"rendered\", summary: \"Every rendered shared component has a skin entry; no reference-skin class ships.\" },\n { id: \"K11\", tier: \"enquiry\", from: \"3.11.0\", kind: \"rendered\", summary: \"Density: no section with more than one H2, more than 8 cards or more than 2 calls to action; measure and section padding within limits.\" },\n { id: \"K12-contact\", tier: \"enquiry\", from: \"3.11.0\", kind: \"rendered\", summary: \"The contact page is the page header, then the contact block, and nothing else.\" },\n { id: \"T6\", tier: \"enquiry\", from: \"3.11.0\", kind: \"static\", summary: \"Every image has a media.ts entry with provenance.\" },\n { id: \"T7\", tier: \"enquiry\", from: \"3.11.0\", kind: \"rendered\", summary: \"No image is the main image of two pages.\" },\n { id: \"T8\", tier: \"enquiry\", from: \"3.11.0\", kind: \"rendered\", summary: 'Prices: GST flag set; no \"+ GST\" or \"from $X\" teasers on cards and menus; one band per job site-wide.' },\n { id: \"T9\", tier: \"enquiry\", from: \"3.11.0\", kind: \"static\", summary: \"No image in /public carries location metadata.\" },\n\n // full: page families, location estates, section manifests, links and the data contract\n { id: \"K12\", tier: \"full\", from: \"3.12.0\", kind: \"rendered\", summary: \"Section manifest: every required section rendered or skipped with a data-backed reason; conditional sections render when their data exists; canonical or recorded order.\" },\n { id: \"E5\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"No orphan indexable pages, from the route catalogue and link data.\" },\n { id: \"E10\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"Phrase-owner uniqueness in strategy data; no service-in-suburb page for the suburb page phrase; no service-region hub for the main trade.\" },\n { id: \"L3\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"Neighbours by real distance.\" },\n { id: \"L4\", tier: \"full\", from: \"3.12.0\", kind: \"rendered\", summary: \"No copy rotated by page address, no name-swapped FAQs, no other suburb's job without the nearby label.\" },\n { id: \"L6\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"Location pages have 6 or more inbound links from 3 or more page types.\" },\n { id: \"L7\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"Location pages are 3 clicks or fewer from home.\" },\n { id: \"L8\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"A hub per family per region.\" },\n { id: \"L9\", tier: \"full\", from: \"3.12.0\", kind: \"rendered\", summary: \"Data contract on service-in-suburb pages: typical prices or the cost-guide link, reviews or their fallback, the quote path (form with the suburb prefilled, phone, call bar); the nearby job card or none.\" },\n { id: \"L10\", tier: \"full\", from: \"3.12.0\", kind: \"rendered\", summary: 'No kilometre figures, \"km from\", \"based in\" or year stamps as local detail in location copy.' },\n { id: \"S4\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"No hand-written per-service or per-suburb files; no dynamic route with zero pages.\" },\n { id: \"LOC-INDEX\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"No location route is noindex or left out of the sitemap unless the recorded wave schedule dates it (Romie's 20 Oct decision: every suburb page stays indexed).\" },\n\n // new builds and redesigns\n { id: \"D4\", tier: \"new-build\", from: \"3.8.0\", kind: \"static\", summary: \"Same-trade distinctness: at least four of seven look levers differ from every listed competitor (advisory in 3.8.0, blocking from 3.9.0).\" },\n] as const satisfies readonly SiteSystemCheck[];\n\nexport type SiteSystemCheckId = (typeof SITE_SYSTEM_CHECKS)[number][\"id\"];\n\nconst TIER_RANK: Record<SiteSystemTier, number> = { shell: 0, enquiry: 1, full: 2 };\n\n/** A release as one comparable number: \"3.8.0\" < \"3.10.0\". */\nexport function siteSystemReleaseRank(version: string): number {\n const [major = 0, minor = 0, patch = 0] = version.split(/[.-]/).map((part) => Number.parseInt(part, 10) || 0);\n return major * 1_000_000 + minor * 1_000 + patch;\n}\n\n/**\n * Whether a check blocks for a site at `tier` on `release`. Checks of higher tiers, and checks newer than the\n * installed release, report without blocking. D4 blocks new builds and redesigns from 3.9.0 whatever their tier.\n */\nexport function siteSystemCheckBlocks(\n check: Pick<SiteSystemCheck, \"id\" | \"tier\" | \"from\">,\n site: { tier: SiteSystemTier; release: string; newBuild?: boolean },\n): boolean {\n if (check.tier === \"new-build\") return site.newBuild === true && siteSystemReleaseRank(site.release) >= siteSystemReleaseRank(\"3.9.0\");\n if (siteSystemReleaseRank(site.release) < siteSystemReleaseRank(check.from)) return false;\n return TIER_RANK[check.tier] <= TIER_RANK[site.tier];\n}\n\n/** One result of one check, from any runner. `brandlab-ready` merges them into the ready report. */\nexport interface SiteSystemFinding {\n readonly checkId: SiteSystemCheckId;\n readonly status: \"pass\" | \"fail\" | \"not-applicable\";\n /** The page path or file the result is about, when it is about one. */\n readonly target?: string;\n /** One plain sentence: what passed or what is wrong and where. */\n readonly message: string;\n /** A warning never blocks: the check still passes and the report shows \"pass (warning)\". */\n readonly severity?: \"warning\";\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule-modules.d.ts","sourceRoot":"","sources":["../../src/site-system/rule-modules.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"rule-modules.d.ts","sourceRoot":"","sources":["../../src/site-system/rule-modules.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AA8B7D,eAAO,MAAM,4BAA4B,EAAE,SAAS,wBAAwB,EAS3E,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { runDesignRules } from "./rules/design/index.js";
|
|
2
2
|
import { runEnquiryRenderedRules } from "./rules/enquiry/index.js";
|
|
3
3
|
import { runFormRules } from "./rules/form/index.js";
|
|
4
|
+
import { runFullTierRules } from "./rules/full/index.js";
|
|
4
5
|
import { runLibraryRules } from "./rules/library/index.js";
|
|
5
6
|
import { runNavigationRules } from "./rules/navigation/index.js";
|
|
6
7
|
import { runSectionRules } from "./rules/sections/index.js";
|
|
@@ -21,6 +22,9 @@ const formRules = function formRules(input) {
|
|
|
21
22
|
const sectionRules = function sectionRules(input) {
|
|
22
23
|
return runSectionRules(input);
|
|
23
24
|
};
|
|
25
|
+
const fullTierRules = function fullTierRules(input) {
|
|
26
|
+
return runFullTierRules(input);
|
|
27
|
+
};
|
|
24
28
|
export const SITE_SYSTEM_RENDERED_RUNNERS = [
|
|
25
29
|
shellRules,
|
|
26
30
|
enquiryRules,
|
|
@@ -29,5 +33,6 @@ export const SITE_SYSTEM_RENDERED_RUNNERS = [
|
|
|
29
33
|
libraryRules,
|
|
30
34
|
formRules,
|
|
31
35
|
sectionRules,
|
|
36
|
+
fullTierRules,
|
|
32
37
|
];
|
|
33
38
|
//# sourceMappingURL=rule-modules.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule-modules.js","sourceRoot":"","sources":["../../src/site-system/rule-modules.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,+DAA+D;AAC/D,MAAM,UAAU,GAA6B,SAAS,UAAU,CAAC,KAAK;IACpE,OAAO,qBAAqB,CAAC,KAAK,CAAC,CAAC;AACtC,CAAC,CAAC;AACF,MAAM,YAAY,GAA6B,SAAS,YAAY,CAAC,KAAK;IACxE,OAAO,uBAAuB,CAAC,KAAK,CAAC,CAAC;AACxC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"rule-modules.js","sourceRoot":"","sources":["../../src/site-system/rule-modules.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,+DAA+D;AAC/D,MAAM,UAAU,GAA6B,SAAS,UAAU,CAAC,KAAK;IACpE,OAAO,qBAAqB,CAAC,KAAK,CAAC,CAAC;AACtC,CAAC,CAAC;AACF,MAAM,YAAY,GAA6B,SAAS,YAAY,CAAC,KAAK;IACxE,OAAO,uBAAuB,CAAC,KAAK,CAAC,CAAC;AACxC,CAAC,CAAC;AACF,MAAM,YAAY,GAA6B,SAAS,YAAY,CAAC,KAAK;IACxE,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;AAChC,CAAC,CAAC;AACF,MAAM,SAAS,GAA6B,SAAS,SAAS,CAAC,KAAK;IAClE,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC;AAC7B,CAAC,CAAC;AACF,MAAM,YAAY,GAA6B,SAAS,YAAY,CAAC,KAAK;IACxE,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;AAChC,CAAC,CAAC;AACF,MAAM,aAAa,GAA6B,SAAS,aAAa,CAAC,KAAK;IAC1E,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,4BAA4B,GAAwC;IAC/E,UAAU;IACV,YAAY;IACZ,cAAc;IACd,kBAAkB;IAClB,YAAY;IACZ,SAAS;IACT,YAAY;IACZ,aAAa;CACd,CAAC","sourcesContent":["/**\n * The rule modules `brandlab-ready` runs. Each module under ./rules/ exports a SiteSystemRenderedRunner: plug it in\n * here with one import line and one list entry. Rule modules import from ./runners.js and ./checks.js, never from\n * this file or ./index.js, so the list adds no import cycle.\n */\nimport type { SiteSystemRenderedRunner } from \"./runners.js\";\nimport { runDesignRules } from \"./rules/design/index.js\";\nimport { runEnquiryRenderedRules } from \"./rules/enquiry/index.js\";\nimport { runFormRules } from \"./rules/form/index.js\";\nimport { runFullTierRules } from \"./rules/full/index.js\";\nimport { runLibraryRules } from \"./rules/library/index.js\";\nimport { runNavigationRules } from \"./rules/navigation/index.js\";\nimport { runSectionRules } from \"./rules/sections/index.js\";\nimport { runShellRenderedRules } from \"./rules/shell/index.js\";\n\n// Named wrappers, so a runner that throws is reported by name.\nconst shellRules: SiteSystemRenderedRunner = function shellRules(input) {\n return runShellRenderedRules(input);\n};\nconst enquiryRules: SiteSystemRenderedRunner = function enquiryRules(input) {\n return runEnquiryRenderedRules(input);\n};\nconst libraryRules: SiteSystemRenderedRunner = function libraryRules(input) {\n return runLibraryRules(input);\n};\nconst formRules: SiteSystemRenderedRunner = function formRules(input) {\n return runFormRules(input);\n};\nconst sectionRules: SiteSystemRenderedRunner = function sectionRules(input) {\n return runSectionRules(input);\n};\nconst fullTierRules: SiteSystemRenderedRunner = function fullTierRules(input) {\n return runFullTierRules(input);\n};\n\nexport const SITE_SYSTEM_RENDERED_RUNNERS: readonly SiteSystemRenderedRunner[] = [\n shellRules,\n enquiryRules,\n runDesignRules,\n runNavigationRules,\n libraryRules,\n formRules,\n sectionRules,\n fullTierRules,\n];\n"]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { SiteSystemCheckId, SiteSystemFinding } from "../../checks.js";
|
|
2
|
+
import type { Estate } from "./estate.js";
|
|
3
|
+
import type { FullGeography } from "./geography.js";
|
|
4
|
+
import type { FullStrategy } from "./strategy.js";
|
|
5
|
+
export { fail, notApplicable, pass, plural } from "../enquiry/common.js";
|
|
6
|
+
/** Everything a full-tier rule reads. */
|
|
7
|
+
export interface FullContext {
|
|
8
|
+
readonly estate: Estate;
|
|
9
|
+
/** Null when the site-core geography could not be loaded; `geographyProblem` says why. */
|
|
10
|
+
readonly geography: FullGeography | null;
|
|
11
|
+
readonly geographyProblem: string;
|
|
12
|
+
readonly strategy: FullStrategy;
|
|
13
|
+
readonly projectRoot: string;
|
|
14
|
+
/** Today in Sydney, YYYY-MM-DD: the day waves are judged on. */
|
|
15
|
+
readonly today: string;
|
|
16
|
+
/** A family's canonical sections and cap (site-core `defaultSectionOrder`), or a string saying why they are unknown. */
|
|
17
|
+
readonly defaultOrder: ((family: string, trade?: string) => {
|
|
18
|
+
readonly cap: number;
|
|
19
|
+
readonly entries: readonly {
|
|
20
|
+
readonly id: string;
|
|
21
|
+
readonly requirement: string;
|
|
22
|
+
}[];
|
|
23
|
+
} | undefined) | string;
|
|
24
|
+
}
|
|
25
|
+
/** The most failures one check lists one by one; the rest are counted in a last finding. */
|
|
26
|
+
export declare const FULL_LISTED_FAILURES = 25;
|
|
27
|
+
/** The failures (at most `FULL_LISTED_FAILURES`, then a count of the rest), or one pass. */
|
|
28
|
+
export declare function outcome(checkId: SiteSystemCheckId, failures: readonly SiteSystemFinding[], passMessage: string): SiteSystemFinding[];
|
|
29
|
+
/** A finding that never blocks: the check passes and the report shows the warning. */
|
|
30
|
+
export declare function warning(checkId: SiteSystemCheckId, target: string, message: string): SiteSystemFinding;
|
|
31
|
+
/** The estate-wide checks need the whole build, not a sample: without it they fail, so the gate never passes unchecked. */
|
|
32
|
+
export declare function needsBuild(checkId: SiteSystemCheckId, estate: Estate): SiteSystemFinding | null;
|
|
33
|
+
/** "a, b and c". */
|
|
34
|
+
export declare function listOf(items: readonly string[], limit?: number): string;
|
|
35
|
+
/** "the suburb page /locations/ryde" style labels for a family. */
|
|
36
|
+
export declare const FAMILY_LABELS: Readonly<Record<string, string>>;
|
|
37
|
+
//# sourceMappingURL=common.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../../src/site-system/rules/full/common.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAE5E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEzE,yCAAyC;AACzC,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,0FAA0F;IAC1F,QAAQ,CAAC,SAAS,EAAE,aAAa,GAAG,IAAI,CAAC;IACzC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,gEAAgE;IAChE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,wHAAwH;IACxH,QAAQ,CAAC,YAAY,EACjB,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,SAAS;YAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;KAAE,GAAG,SAAS,CAAC,GAC9J,MAAM,CAAC;CACZ;AAED,4FAA4F;AAC5F,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAEvC,4FAA4F;AAC5F,wBAAgB,OAAO,CAAC,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,SAAS,iBAAiB,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAkBpI;AAED,sFAAsF;AACtF,wBAAgB,OAAO,CAAC,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAEtG;AAED,2HAA2H;AAC3H,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAG/F;AAED,oBAAoB;AACpB,wBAAgB,MAAM,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,SAAI,GAAG,MAAM,CAKlE;AAED,mEAAmE;AACnE,eAAO,MAAM,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAI1D,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { fail, pass } from "../enquiry/common.js";
|
|
2
|
+
export { fail, notApplicable, pass, plural } from "../enquiry/common.js";
|
|
3
|
+
/** The most failures one check lists one by one; the rest are counted in a last finding. */
|
|
4
|
+
export const FULL_LISTED_FAILURES = 25;
|
|
5
|
+
/** The failures (at most `FULL_LISTED_FAILURES`, then a count of the rest), or one pass. */
|
|
6
|
+
export function outcome(checkId, failures, passMessage) {
|
|
7
|
+
const failed = failures.filter((finding) => finding.status === "fail");
|
|
8
|
+
const allWarnings = failures.filter((finding) => finding.status !== "fail");
|
|
9
|
+
const warnings = allWarnings.length <= FULL_LISTED_FAILURES
|
|
10
|
+
? allWarnings
|
|
11
|
+
: [
|
|
12
|
+
...allWarnings.slice(0, FULL_LISTED_FAILURES),
|
|
13
|
+
{ checkId, status: "pass", severity: "warning", message: `${allWarnings.length - FULL_LISTED_FAILURES} more warnings of the same kind.` },
|
|
14
|
+
];
|
|
15
|
+
if (failed.length === 0)
|
|
16
|
+
return [...warnings, pass(checkId, passMessage)];
|
|
17
|
+
if (failed.length <= FULL_LISTED_FAILURES)
|
|
18
|
+
return [...failed, ...warnings];
|
|
19
|
+
const rest = failed.slice(FULL_LISTED_FAILURES);
|
|
20
|
+
const examples = [...new Set(rest.flatMap((finding) => finding.target ?? []))].slice(0, 3);
|
|
21
|
+
return [
|
|
22
|
+
...failed.slice(0, FULL_LISTED_FAILURES),
|
|
23
|
+
fail(checkId, undefined, `${rest.length} more ${rest.length === 1 ? "problem" : "problems"} of the same kind${examples.length > 0 ? `, for example on ${examples.join(", ")}` : ""}.`),
|
|
24
|
+
...warnings,
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
/** A finding that never blocks: the check passes and the report shows the warning. */
|
|
28
|
+
export function warning(checkId, target, message) {
|
|
29
|
+
return { checkId, status: "pass", target, message, severity: "warning" };
|
|
30
|
+
}
|
|
31
|
+
/** The estate-wide checks need the whole build, not a sample: without it they fail, so the gate never passes unchecked. */
|
|
32
|
+
export function needsBuild(checkId, estate) {
|
|
33
|
+
if (estate.complete)
|
|
34
|
+
return null;
|
|
35
|
+
return fail(checkId, undefined, "The production build could not be read (no .next/prerender-manifest.json), so the whole estate could not be checked; run next build first.");
|
|
36
|
+
}
|
|
37
|
+
/** "a, b and c". */
|
|
38
|
+
export function listOf(items, limit = 4) {
|
|
39
|
+
const shown = items.slice(0, limit);
|
|
40
|
+
const more = items.length - shown.length;
|
|
41
|
+
if (more > 0)
|
|
42
|
+
return `${shown.join(", ")} and ${more} more`;
|
|
43
|
+
return shown.length <= 1 ? shown.join("") : `${shown.slice(0, -1).join(", ")} and ${shown.at(-1)}`;
|
|
44
|
+
}
|
|
45
|
+
/** "the suburb page /locations/ryde" style labels for a family. */
|
|
46
|
+
export const FAMILY_LABELS = {
|
|
47
|
+
suburb: "suburb page",
|
|
48
|
+
"service-in-suburb": "service-in-suburb page",
|
|
49
|
+
region: "region page",
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=common.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"common.js","sourceRoot":"","sources":["../../../../src/site-system/rules/full/common.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SiteSystemCheckId, SiteSystemFinding } from \"../../checks.js\";\nimport { fail, pass } from \"../enquiry/common.js\";\nimport type { Estate } from \"./estate.js\";\nimport type { FullGeography } from \"./geography.js\";\nimport type { FullStrategy } from \"./strategy.js\";\n\nexport { fail, notApplicable, pass, plural } from \"../enquiry/common.js\";\n\n/** Everything a full-tier rule reads. */\nexport interface FullContext {\n readonly estate: Estate;\n /** Null when the site-core geography could not be loaded; `geographyProblem` says why. */\n readonly geography: FullGeography | null;\n readonly geographyProblem: string;\n readonly strategy: FullStrategy;\n readonly projectRoot: string;\n /** Today in Sydney, YYYY-MM-DD: the day waves are judged on. */\n readonly today: string;\n /** A family's canonical sections and cap (site-core `defaultSectionOrder`), or a string saying why they are unknown. */\n readonly defaultOrder:\n | ((family: string, trade?: string) => { readonly cap: number; readonly entries: readonly { readonly id: string; readonly requirement: string }[] } | undefined)\n | string;\n}\n\n/** The most failures one check lists one by one; the rest are counted in a last finding. */\nexport const FULL_LISTED_FAILURES = 25;\n\n/** The failures (at most `FULL_LISTED_FAILURES`, then a count of the rest), or one pass. */\nexport function outcome(checkId: SiteSystemCheckId, failures: readonly SiteSystemFinding[], passMessage: string): SiteSystemFinding[] {\n const failed = failures.filter((finding) => finding.status === \"fail\");\n const allWarnings = failures.filter((finding) => finding.status !== \"fail\");\n const warnings = allWarnings.length <= FULL_LISTED_FAILURES\n ? allWarnings\n : [\n ...allWarnings.slice(0, FULL_LISTED_FAILURES),\n { checkId, status: \"pass\" as const, severity: \"warning\" as const, message: `${allWarnings.length - FULL_LISTED_FAILURES} more warnings of the same kind.` },\n ];\n if (failed.length === 0) return [...warnings, pass(checkId, passMessage)];\n if (failed.length <= FULL_LISTED_FAILURES) return [...failed, ...warnings];\n const rest = failed.slice(FULL_LISTED_FAILURES);\n const examples = [...new Set(rest.flatMap((finding) => finding.target ?? []))].slice(0, 3);\n return [\n ...failed.slice(0, FULL_LISTED_FAILURES),\n fail(checkId, undefined, `${rest.length} more ${rest.length === 1 ? \"problem\" : \"problems\"} of the same kind${examples.length > 0 ? `, for example on ${examples.join(\", \")}` : \"\"}.`),\n ...warnings,\n ];\n}\n\n/** A finding that never blocks: the check passes and the report shows the warning. */\nexport function warning(checkId: SiteSystemCheckId, target: string, message: string): SiteSystemFinding {\n return { checkId, status: \"pass\", target, message, severity: \"warning\" };\n}\n\n/** The estate-wide checks need the whole build, not a sample: without it they fail, so the gate never passes unchecked. */\nexport function needsBuild(checkId: SiteSystemCheckId, estate: Estate): SiteSystemFinding | null {\n if (estate.complete) return null;\n return fail(checkId, undefined, \"The production build could not be read (no .next/prerender-manifest.json), so the whole estate could not be checked; run next build first.\");\n}\n\n/** \"a, b and c\". */\nexport function listOf(items: readonly string[], limit = 4): string {\n const shown = items.slice(0, limit);\n const more = items.length - shown.length;\n if (more > 0) return `${shown.join(\", \")} and ${more} more`;\n return shown.length <= 1 ? shown.join(\"\") : `${shown.slice(0, -1).join(\", \")} and ${shown.at(-1)}`;\n}\n\n/** \"the suburb page /locations/ryde\" style labels for a family. */\nexport const FAMILY_LABELS: Readonly<Record<string, string>> = {\n suburb: \"suburb page\",\n \"service-in-suburb\": \"service-in-suburb page\",\n region: \"region page\",\n};\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* E10, phrase ownership (Site System v2 §4.2, §4.4 step 3, §5.3). strategy.ts records the main trade and one owning
|
|
3
|
+
* page per primary phrase; no phrase has two owners and every owner is an indexable page. The suburb page owns
|
|
4
|
+
* "{main trade} {suburb}" and the region page "{main trade} {region}", so no service-in-suburb page and no
|
|
5
|
+
* service-region hub carries the main trade as its own phrase (read from its H1 with the place taken out).
|
|
6
|
+
*/
|
|
7
|
+
import type { SiteSystemFinding } from "../../checks.js";
|
|
8
|
+
import { type FullContext } from "./common.js";
|
|
9
|
+
/** A heading's phrase without its place: "Blocked drains in Ryde" reads "blocked drain". */
|
|
10
|
+
export declare function headingPhrase(heading: string, mask: (text: string) => string): string;
|
|
11
|
+
/** The service slug in a stem, as a phrase: `/services/plumber/{place}` and `/plumber-{place}` read "plumber". */
|
|
12
|
+
export declare function stemPhrase(stem: string): string;
|
|
13
|
+
export declare function checkE10(context: FullContext): SiteSystemFinding[];
|
|
14
|
+
//# sourceMappingURL=e10-phrases.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e10-phrases.d.ts","sourceRoot":"","sources":["../../../../src/site-system/rules/full/e10-phrases.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAyB,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAQtE,4FAA4F;AAC5F,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,MAAM,CAErF;AAED,kHAAkH;AAClH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG/C;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,iBAAiB,EAAE,CAmDlE"}
|