@brandlab-digital/conformance 3.13.0 → 3.14.0
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/README.md +9 -0
- package/dist/analytics-e2e.d.ts +10 -16
- package/dist/analytics-e2e.d.ts.map +1 -1
- package/dist/analytics-e2e.js +61 -3
- package/dist/analytics-e2e.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +4 -1
- package/dist/cli.js.map +1 -1
- package/dist/current-release.js +5 -5
- package/dist/current-release.js.map +1 -1
- package/dist/estate.d.ts +28 -0
- package/dist/estate.d.ts.map +1 -1
- package/dist/estate.js +35 -12
- package/dist/estate.js.map +1 -1
- package/dist/project.d.ts +20 -0
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +92 -2
- package/dist/project.js.map +1 -1
- package/dist/ready-cli.d.ts.map +1 -1
- package/dist/ready-cli.js +8 -3
- package/dist/ready-cli.js.map +1 -1
- package/dist/rule-registry.d.ts +5 -0
- package/dist/rule-registry.d.ts.map +1 -1
- package/dist/rule-registry.js +1 -0
- package/dist/rule-registry.js.map +1 -1
- package/dist/site-system/checks.d.ts +26 -1
- package/dist/site-system/checks.d.ts.map +1 -1
- package/dist/site-system/checks.js +3 -0
- package/dist/site-system/checks.js.map +1 -1
- package/dist/site-system/report.d.ts.map +1 -1
- package/dist/site-system/report.js +19 -5
- package/dist/site-system/report.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/delivery/h13-inbox.d.ts +23 -0
- package/dist/site-system/rules/delivery/h13-inbox.d.ts.map +1 -0
- package/dist/site-system/rules/delivery/h13-inbox.js +208 -0
- package/dist/site-system/rules/delivery/h13-inbox.js.map +1 -0
- package/dist/site-system/rules/delivery/index.d.ts +12 -0
- package/dist/site-system/rules/delivery/index.d.ts.map +1 -0
- package/dist/site-system/rules/delivery/index.js +7 -0
- package/dist/site-system/rules/delivery/index.js.map +1 -0
- package/dist/site-system/rules/full/e1-pattern.d.ts +4 -0
- package/dist/site-system/rules/full/e1-pattern.d.ts.map +1 -0
- package/dist/site-system/rules/full/e1-pattern.js +47 -0
- package/dist/site-system/rules/full/e1-pattern.js.map +1 -0
- package/dist/site-system/rules/full/estate.d.ts +16 -1
- package/dist/site-system/rules/full/estate.d.ts.map +1 -1
- package/dist/site-system/rules/full/estate.js +23 -4
- package/dist/site-system/rules/full/estate.js.map +1 -1
- package/dist/site-system/rules/full/geography.d.ts +8 -2
- package/dist/site-system/rules/full/geography.d.ts.map +1 -1
- package/dist/site-system/rules/full/geography.js +6 -2
- package/dist/site-system/rules/full/geography.js.map +1 -1
- package/dist/site-system/rules/full/index.d.ts +2 -2
- package/dist/site-system/rules/full/index.d.ts.map +1 -1
- package/dist/site-system/rules/full/index.js +15 -4
- package/dist/site-system/rules/full/index.js.map +1 -1
- package/dist/site-system/rules/full/k12-slots.d.ts +4 -0
- package/dist/site-system/rules/full/k12-slots.d.ts.map +1 -0
- package/dist/site-system/rules/full/k12-slots.js +40 -0
- package/dist/site-system/rules/full/k12-slots.js.map +1 -0
- package/dist/site-system/rules/full/loc-index.d.ts +5 -0
- package/dist/site-system/rules/full/loc-index.d.ts.map +1 -1
- package/dist/site-system/rules/full/loc-index.js +43 -2
- package/dist/site-system/rules/full/loc-index.js.map +1 -1
- package/dist/site-system/rules/full/strategy.d.ts +4 -0
- package/dist/site-system/rules/full/strategy.d.ts.map +1 -1
- package/dist/site-system/rules/full/strategy.js +19 -3
- package/dist/site-system/rules/full/strategy.js.map +1 -1
- package/dist/site-system/rules/sections/k2-skin-coverage.d.ts +2 -2
- package/dist/site-system/rules/sections/k2-skin-coverage.d.ts.map +1 -1
- package/dist/site-system/rules/sections/k2-skin-coverage.js +6 -2
- package/dist/site-system/rules/sections/k2-skin-coverage.js.map +1 -1
- package/dist/site-system/runners.js +1 -1
- package/dist/site-system/runners.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e1-pattern.d.ts","sourceRoot":"","sources":["../../../../src/site-system/rules/full/e1-pattern.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,OAAO,EAAoD,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAUjG,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,iBAAiB,EAAE,CAqBxE"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* E1-pattern (3.14.0): the title pattern half of E1 on every built location page (Site System v2 §5.2; correction
|
|
3
|
+
* #27). A suburb, region or service-in-suburb page's H1 is "{Service} {Place}": the short exact phrase ending with the
|
|
4
|
+
* place, with no "in" and no "the"; its title starts with that H1, at most 60 characters with at most two pipes. The
|
|
5
|
+
* place is the one the page's path names. Pages whose titles the site recorded (`docs/recorded-titles.json`) keep them
|
|
6
|
+
* word for word under E1 and are not judged here. site-core's `buildPageTitle` writes titles that pass.
|
|
7
|
+
*/
|
|
8
|
+
import { locationHeadingProblem } from "@brandlab-digital/site-core/page-titles";
|
|
9
|
+
import { readRecordedTitles } from "../enquiry/e1-recorded-titles.js";
|
|
10
|
+
import { fail, needsBuild, notApplicable, outcome, plural } from "./common.js";
|
|
11
|
+
import { isLocationFamily } from "./estate.js";
|
|
12
|
+
/** The names a page's place may be written as: a suburb's name, or a region's name, search name and alternates. */
|
|
13
|
+
function placeNames(slug, context) {
|
|
14
|
+
const suburb = context.geography?.suburbs.get(slug);
|
|
15
|
+
if (suburb)
|
|
16
|
+
return [suburb.name];
|
|
17
|
+
return [...(context.geography?.regions.get(slug)?.names ?? [])];
|
|
18
|
+
}
|
|
19
|
+
export function checkE1Pattern(context) {
|
|
20
|
+
const skip = needsBuild("E1-pattern", context.estate);
|
|
21
|
+
if (skip)
|
|
22
|
+
return [skip];
|
|
23
|
+
if (!context.geography)
|
|
24
|
+
return [fail("E1-pattern", undefined, `The places location pages are for could not be read (${context.geographyProblem}).`)];
|
|
25
|
+
const recorded = readRecordedTitles(context.projectRoot);
|
|
26
|
+
const kept = recorded instanceof Map ? recorded : new Map();
|
|
27
|
+
const failures = [];
|
|
28
|
+
let checked = 0;
|
|
29
|
+
for (const page of context.estate.pages) {
|
|
30
|
+
if (!isLocationFamily(page.family) || !page.place || kept.has(page.path))
|
|
31
|
+
continue;
|
|
32
|
+
const names = placeNames(page.place.slug, context);
|
|
33
|
+
if (names.length === 0)
|
|
34
|
+
continue;
|
|
35
|
+
checked += 1;
|
|
36
|
+
const title = page.title ?? "";
|
|
37
|
+
// The name the H1 ends with when there is one; otherwise the place's main name.
|
|
38
|
+
const name = names.find((candidate) => page.h1.trim().toLowerCase().endsWith(candidate.toLowerCase())) ?? names[0];
|
|
39
|
+
const problem = page.h1.trim() ? locationHeadingProblem({ h1: page.h1, title, place: name }) : "the page has no H1.";
|
|
40
|
+
if (problem)
|
|
41
|
+
failures.push(fail("E1-pattern", page.path, `${page.path}: ${problem}`));
|
|
42
|
+
}
|
|
43
|
+
if (checked === 0)
|
|
44
|
+
return [notApplicable("E1-pattern", "The build has no location page outside the recorded titles.")];
|
|
45
|
+
return outcome("E1-pattern", failures, `${plural(checked, "location page")} carry "{Service} {Place}" as their H1, and their titles lead with it.`);
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=e1-pattern.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e1-pattern.js","sourceRoot":"","sources":["../../../../src/site-system/rules/full/e1-pattern.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * E1-pattern (3.14.0): the title pattern half of E1 on every built location page (Site System v2 §5.2; correction\n * #27). A suburb, region or service-in-suburb page's H1 is \"{Service} {Place}\": the short exact phrase ending with the\n * place, with no \"in\" and no \"the\"; its title starts with that H1, at most 60 characters with at most two pipes. The\n * place is the one the page's path names. Pages whose titles the site recorded (`docs/recorded-titles.json`) keep them\n * word for word under E1 and are not judged here. site-core's `buildPageTitle` writes titles that pass.\n */\nimport { locationHeadingProblem } from \"@brandlab-digital/site-core/page-titles\";\nimport type { SiteSystemFinding } from \"../../checks.js\";\nimport { readRecordedTitles } from \"../enquiry/e1-recorded-titles.js\";\nimport { fail, needsBuild, notApplicable, outcome, plural, type FullContext } from \"./common.js\";\nimport { isLocationFamily } from \"./estate.js\";\n\n/** The names a page's place may be written as: a suburb's name, or a region's name, search name and alternates. */\nfunction placeNames(slug: string, context: FullContext): string[] {\n const suburb = context.geography?.suburbs.get(slug);\n if (suburb) return [suburb.name];\n return [...(context.geography?.regions.get(slug)?.names ?? [])];\n}\n\nexport function checkE1Pattern(context: FullContext): SiteSystemFinding[] {\n const skip = needsBuild(\"E1-pattern\", context.estate);\n if (skip) return [skip];\n if (!context.geography) return [fail(\"E1-pattern\", undefined, `The places location pages are for could not be read (${context.geographyProblem}).`)];\n const recorded = readRecordedTitles(context.projectRoot);\n const kept = recorded instanceof Map ? recorded : new Map<string, string>();\n const failures: SiteSystemFinding[] = [];\n let checked = 0;\n for (const page of context.estate.pages) {\n if (!isLocationFamily(page.family) || !page.place || kept.has(page.path)) continue;\n const names = placeNames(page.place.slug, context);\n if (names.length === 0) continue;\n checked += 1;\n const title = page.title ?? \"\";\n // The name the H1 ends with when there is one; otherwise the place's main name.\n const name = names.find((candidate) => page.h1.trim().toLowerCase().endsWith(candidate.toLowerCase())) ?? names[0]!;\n const problem = page.h1.trim() ? locationHeadingProblem({ h1: page.h1, title, place: name }) : \"the page has no H1.\";\n if (problem) failures.push(fail(\"E1-pattern\", page.path, `${page.path}: ${problem}`));\n }\n if (checked === 0) return [notApplicable(\"E1-pattern\", \"The build has no location page outside the recorded titles.\")];\n return outcome(\"E1-pattern\", failures, `${plural(checked, \"location page\")} carry \"{Service} {Place}\" as their H1, and their titles lead with it.`);\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SiteSystemPage } from "../../samples.js";
|
|
2
|
-
import { type FullGeography, type PathPlace } from "./geography.js";
|
|
2
|
+
import { type FullGeography, type PathAliases, type PathPlace } from "./geography.js";
|
|
3
3
|
/** The section manifest as SectionSequence writes it (site-core `BrandlabSectionManifest`). */
|
|
4
4
|
export interface ManifestData {
|
|
5
5
|
readonly version: number;
|
|
@@ -85,7 +85,20 @@ export interface EstatePage {
|
|
|
85
85
|
readonly manifest: ManifestState;
|
|
86
86
|
/** Top-level `data-bl-section` ids, in document order. */
|
|
87
87
|
readonly sections: readonly string[];
|
|
88
|
+
/**
|
|
89
|
+
* Per top-level section (3.14.0): the `data-bl-slot` values inside it and the `slot:reason` pairs of its
|
|
90
|
+
* `data-bl-slot-skip` attribute.
|
|
91
|
+
*/
|
|
92
|
+
readonly slots?: ReadonlyMap<string, {
|
|
93
|
+
readonly present: readonly string[];
|
|
94
|
+
readonly skipped: readonly {
|
|
95
|
+
readonly slot: string;
|
|
96
|
+
readonly reason: string;
|
|
97
|
+
}[];
|
|
98
|
+
}>;
|
|
88
99
|
readonly h1: string;
|
|
100
|
+
/** The page's `<title>` text (3.14.0); absent when it has none. */
|
|
101
|
+
readonly title?: string;
|
|
89
102
|
readonly place: PathPlace | undefined;
|
|
90
103
|
family: string | undefined;
|
|
91
104
|
familySource: "manifest" | "sitemap" | "route" | "stem" | "path" | undefined;
|
|
@@ -116,6 +129,8 @@ export declare function readEstate(input: {
|
|
|
116
129
|
readonly geography: FullGeography | null;
|
|
117
130
|
/** Families known from elsewhere, by path (the representative service route). */
|
|
118
131
|
readonly seeds?: Readonly<Record<string, string>>;
|
|
132
|
+
/** The estate plan's public slugs (3.14.0). */
|
|
133
|
+
readonly aliases?: PathAliases;
|
|
119
134
|
}): Estate;
|
|
120
135
|
/** An internal link's normalised path, or null for other sites, anchors on the same page, mail and phone links. */
|
|
121
136
|
export declare function internalPath(href: string, from: string, hosts: ReadonlySet<string>): string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"estate.d.ts","sourceRoot":"","sources":["../../../../src/site-system/rules/full/estate.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAIvD,OAAO,EAAe,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"estate.d.ts","sourceRoot":"","sources":["../../../../src/site-system/rules/full/estate.ts"],"names":[],"mappings":"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"}
|
|
@@ -96,7 +96,7 @@ export function readEstate(input) {
|
|
|
96
96
|
// A relative canonical names no host.
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
|
-
const { summary, hrefs } = summarise({ path, html, ...(source.srcRoute ? { srcRoute: source.srcRoute } : {}), ...(source.headers ? { headers: source.headers } : {}), ...(source.revalidate !== undefined ? { revalidate: source.revalidate } : {}) }, sitemapOf, input.geography);
|
|
99
|
+
const { summary, hrefs } = summarise({ path, html, ...(source.srcRoute ? { srcRoute: source.srcRoute } : {}), ...(source.headers ? { headers: source.headers } : {}), ...(source.revalidate !== undefined ? { revalidate: source.revalidate } : {}) }, sitemapOf, input.geography, input.aliases);
|
|
100
100
|
read.push({ summary, hrefs, groups: extractLinkGroups(html), source });
|
|
101
101
|
}
|
|
102
102
|
const pages = [];
|
|
@@ -125,7 +125,7 @@ export function readEstate(input) {
|
|
|
125
125
|
const locationRoutes = new Set(pages.flatMap((page) => (isLocationFamily(page.family) && page.srcRoute && isGenerated(page.srcRoute) ? [page.srcRoute] : [])));
|
|
126
126
|
const locationStems = new Set(pages.flatMap((page) => (isLocationFamily(page.family) && page.place ? [page.place.stem] : [])));
|
|
127
127
|
const missingHtml = missing.map((item) => {
|
|
128
|
-
const stem = input.geography ? placeOfPath(item.path, input.geography)?.stem : undefined;
|
|
128
|
+
const stem = input.geography ? placeOfPath(item.path, input.geography, input.aliases)?.stem : undefined;
|
|
129
129
|
return { path: item.path, location: (item.srcRoute !== undefined && locationRoutes.has(item.srcRoute)) || (stem !== undefined && locationStems.has(stem)) };
|
|
130
130
|
});
|
|
131
131
|
return {
|
|
@@ -139,7 +139,7 @@ export function readEstate(input) {
|
|
|
139
139
|
missingHtml,
|
|
140
140
|
};
|
|
141
141
|
}
|
|
142
|
-
function summarise(item, sitemapOf, geography) {
|
|
142
|
+
function summarise(item, sitemapOf, geography, aliases) {
|
|
143
143
|
const root = parseHtml(item.html);
|
|
144
144
|
const elements = descendants(root);
|
|
145
145
|
const robots = elements
|
|
@@ -150,7 +150,7 @@ function summarise(item, sitemapOf, geography) {
|
|
|
150
150
|
const indexable = !/noindex/i.test(`${robots} ${typeof header === "string" ? header : ""}`);
|
|
151
151
|
const hrefs = elements.filter((element) => element.tag === "a").map((element) => attr(element, "href") ?? "");
|
|
152
152
|
const h1Element = elements.find((element) => element.tag === "h1");
|
|
153
|
-
const place = geography ? placeOfPath(item.path, geography) : undefined;
|
|
153
|
+
const place = geography ? placeOfPath(item.path, geography, aliases) : undefined;
|
|
154
154
|
const page = {
|
|
155
155
|
path: item.path,
|
|
156
156
|
srcRoute: item.srcRoute,
|
|
@@ -162,7 +162,9 @@ function summarise(item, sitemapOf, geography) {
|
|
|
162
162
|
linkGroups: [],
|
|
163
163
|
manifest: readManifest(elements),
|
|
164
164
|
sections: topLevelSections(root).map(sectionId),
|
|
165
|
+
slots: sectionSlots(root),
|
|
165
166
|
h1: h1Element ? textOf(h1Element) : "",
|
|
167
|
+
...(titleOf(elements) !== undefined ? { title: titleOf(elements) } : {}),
|
|
166
168
|
place,
|
|
167
169
|
family: undefined,
|
|
168
170
|
familySource: undefined,
|
|
@@ -176,6 +178,23 @@ function summarise(item, sitemapOf, geography) {
|
|
|
176
178
|
}
|
|
177
179
|
return { summary: page, hrefs };
|
|
178
180
|
}
|
|
181
|
+
function sectionSlots(root) {
|
|
182
|
+
const slots = new Map();
|
|
183
|
+
for (const section of topLevelSections(root)) {
|
|
184
|
+
const present = descendants(section).flatMap((element) => attr(element, "data-bl-slot") ?? []);
|
|
185
|
+
const skipped = (attr(section, "data-bl-slot-skip") ?? "").split(/\s+/).flatMap((pair) => {
|
|
186
|
+
const [slot, reason] = pair.split(":");
|
|
187
|
+
return slot && reason ? [{ slot, reason }] : [];
|
|
188
|
+
});
|
|
189
|
+
if (present.length > 0 || skipped.length > 0)
|
|
190
|
+
slots.set(sectionId(section), { present, skipped });
|
|
191
|
+
}
|
|
192
|
+
return slots;
|
|
193
|
+
}
|
|
194
|
+
function titleOf(elements) {
|
|
195
|
+
const title = elements.find((element) => element.tag === "title");
|
|
196
|
+
return title ? normaliseText(textOf(title)) : undefined;
|
|
197
|
+
}
|
|
179
198
|
function readManifest(elements) {
|
|
180
199
|
const scripts = elements.filter((element) => element.tag === "script" && attr(element, "data-bl-manifest") !== undefined);
|
|
181
200
|
if (scripts.length === 0)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"estate.js","sourceRoot":"","sources":["../../../../src/site-system/rules/full/estate.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The estate the full tier reads: every page of the production build (the route catalogue as Next built it, from\n * `.next/prerender-manifest.json` and each page's prerendered HTML), the sitemap files in the build, and per page its\n * indexing, internal links, section manifest and the copy the location rules compare. Nothing is crawled: a site\n * checked with only a base URL and no build has just its sampled pages, and the estate-wide checks say so.\n *\n * A page's family is the one its section manifest names. A page without a manifest takes its family from the\n * sitemap file that lists it (`service-locations-*.xml`, `locations-*.xml`) or from the other pages of its stem (the\n * path with its place replaced: `/services/decking/{place}`), so a location page missing its manifest is still\n * found; a page built from the same dynamic route as a page with a manifest takes that page's family; the\n * representative service route is a service page; home is `/`. Other pages without a manifest have no known family.\n */\nimport { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { join, relative } from \"node:path\";\nimport { extractLinkGroups } from \"../../../page-standard.js\";\nimport type { SiteSystemPage } from \"../../samples.js\";\nimport { resolveStreamedHtml } from \"../../streamed-html.js\";\nimport { normalisePath, sectionId, topLevelSections } from \"../enquiry/common.js\";\nimport { attr, descendants, isHiddenFromPeople, normaliseText, parseHtml, readableLines, textOf, type HtmlElement, type HtmlNode } from \"../enquiry/html.js\";\nimport { placeOfPath, type FullGeography, type PathPlace } from \"./geography.js\";\n\n/** The section manifest as SectionSequence writes it (site-core `BrandlabSectionManifest`). */\nexport interface ManifestData {\n readonly version: number;\n readonly family: string;\n readonly page?: string;\n readonly cap: number;\n readonly order: \"default\" | \"recorded\";\n readonly planned: readonly { readonly id: string; readonly requirement: string }[];\n readonly rendered: readonly { readonly id: string; readonly section: string; readonly requirement: string; readonly tone?: string }[];\n readonly skipped: readonly { readonly id: string; readonly section: string; readonly requirement: string; readonly reason: string }[];\n readonly counted: number;\n readonly flags: readonly string[];\n}\n\nexport type ManifestState =\n | { readonly kind: \"none\" }\n | { readonly kind: \"invalid\"; readonly reason: string }\n | { readonly kind: \"many\"; readonly count: number }\n | { readonly kind: \"one\"; readonly manifest: ManifestData };\n\nexport const LOCATION_FAMILIES = [\"suburb\", \"service-in-suburb\", \"region\"] as const;\nexport type LocationFamily = (typeof LOCATION_FAMILIES)[number];\n\nexport function isLocationFamily(family: string | undefined): family is LocationFamily {\n return (LOCATION_FAMILIES as readonly string[]).includes(family ?? \"\");\n}\n\n/** The copy and parts of a location page the L4, L9 and L10 rules read. */\nexport interface LocationCopy {\n /** Readable lines of the page content, with the section they sit in (\"page\" outside any section). */\n readonly lines: readonly { readonly section: string; readonly text: string }[];\n readonly faqs: readonly { readonly question: string; readonly answer: string }[];\n /** The job cards of the nearby-jobs section; null when the page has none. */\n readonly jobs: readonly string[] | null;\n /** The price-guide section's text; null when the page has none. */\n readonly prices: string | null;\n readonly reviews: { readonly written: number; readonly googleLink: boolean; readonly rating: boolean } | null;\n readonly quoteForm: { readonly suburbField: boolean; readonly suburbValue: string } | null;\n readonly telLink: boolean;\n readonly callBar: boolean;\n}\n\nexport interface EstatePage {\n readonly path: string;\n /** The app route Next built the page from (`/locations/[suburb]`), when known. */\n readonly srcRoute: string | undefined;\n /** The page's timed refresh in seconds as Next built it (`initialRevalidateSeconds`); false for never; absent when unknown. */\n readonly revalidate?: number | false;\n readonly indexable: boolean;\n readonly inSitemap: boolean;\n /** The sitemap file that lists the page, without its number and extension (`service-locations`). */\n readonly sitemapFile: string | undefined;\n /** Internal paths the page links to, once each. */\n readonly links: readonly string[];\n /** The main content's link groups (lists), as internal paths, for the neighbour order. */\n readonly linkGroups: readonly (readonly string[])[];\n readonly manifest: ManifestState;\n /** Top-level `data-bl-section` ids, in document order. */\n readonly sections: readonly string[];\n readonly h1: string;\n readonly place: PathPlace | undefined;\n family: string | undefined;\n familySource: \"manifest\" | \"sitemap\" | \"route\" | \"stem\" | \"path\" | undefined;\n copy: LocationCopy | undefined;\n}\n\nexport interface Estate {\n readonly pages: readonly EstatePage[];\n readonly byPath: ReadonlyMap<string, EstatePage>;\n /** True when the pages are the whole production build, not just a sample. */\n readonly complete: boolean;\n /** Paths listed in the build's sitemap files; null when the build holds no sitemap. */\n readonly sitemap: ReadonlySet<string> | null;\n /** Dynamic app routes in the build and how many pages each produced. */\n readonly dynamicRoutes: ReadonlyMap<string, number>;\n /** The timed refresh of pages a dynamic route renders on demand (`fallbackRevalidate`), for routes with a fallback. */\n readonly fallbackRevalidate: ReadonlyMap<string, number | false>;\n readonly buildDir: string;\n /** Routes the prerender manifest lists with no HTML in the build; `location` when the route is a location page's. */\n readonly missingHtml: readonly { readonly path: string; readonly location: boolean }[];\n}\n\nconst INTERNAL_ROUTES = new Set([\"/_not-found\", \"/_global-error\", \"/404\", \"/500\"]);\n\n/** Reads the estate: the whole build when `buildDir` holds one, otherwise the sampled pages. */\nexport function readEstate(input: {\n readonly pages: readonly SiteSystemPage[];\n readonly buildDir: string;\n readonly geography: FullGeography | null;\n /** Families known from elsewhere, by path (the representative service route). */\n readonly seeds?: Readonly<Record<string, string>>;\n}): Estate {\n const missing: { path: string; srcRoute: string | undefined }[] = [];\n const manifest = readJson(join(input.buildDir, \"prerender-manifest.json\"));\n const sources = new Map<string, { html: string | (() => string); srcRoute?: string; headers?: Record<string, unknown>; revalidate?: number | false }>();\n const dynamicRoutes = new Map<string, number>();\n const fallbackRevalidate = new Map<string, number | false>();\n let complete = false;\n\n if (isRecord(manifest) && isRecord(manifest.routes)) {\n complete = true;\n const appDir = join(input.buildDir, \"server\", \"app\");\n for (const [route, entry] of isRecord(manifest.dynamicRoutes) ? Object.entries(manifest.dynamicRoutes) : []) {\n dynamicRoutes.set(route, 0);\n const fallback = isRecord(entry) ? entry.fallbackRevalidate : undefined;\n if (isRecord(entry) && entry.fallback !== false && (typeof fallback === \"number\" || fallback === false)) fallbackRevalidate.set(route, fallback);\n }\n for (const [rawPath, entry] of Object.entries(manifest.routes)) {\n if (!isRecord(entry) || !rawPath.startsWith(\"/\")) continue;\n const srcRoute = typeof entry.srcRoute === \"string\" ? entry.srcRoute : undefined;\n if (srcRoute && dynamicRoutes.has(srcRoute)) dynamicRoutes.set(srcRoute, (dynamicRoutes.get(srcRoute) ?? 0) + 1);\n if (entry.routeType !== undefined ? entry.routeType !== \"page\" : /\\.[a-z0-9]+$/i.test(rawPath)) continue;\n const path = normalisePath(rawPath);\n if (INTERNAL_ROUTES.has(path) || INTERNAL_ROUTES.has(srcRoute ?? \"\")) continue;\n const file = join(appDir, `${path === \"/\" ? \"/index\" : path}.html`);\n if (!existsSync(file)) {\n missing.push({ path, srcRoute });\n continue;\n }\n const meta = readJson(join(appDir, `${path === \"/\" ? \"/index\" : path}.meta`));\n const revalidate = entry.initialRevalidateSeconds;\n sources.set(path, {\n html: () => readFileSync(file, \"utf8\"),\n ...(srcRoute ? { srcRoute } : {}),\n ...(typeof revalidate === \"number\" || revalidate === false ? { revalidate } : {}),\n ...(isRecord(meta) && isRecord(meta.headers) ? { headers: meta.headers } : {}),\n });\n }\n }\n // Sampled pages fill in what the build does not have (a base-URL run without a build).\n for (const page of input.pages) {\n const path = normalisePath(page.path);\n if (!sources.has(path)) sources.set(path, { html: page.html });\n }\n\n const sitemapFiles = complete ? readSitemaps(join(input.buildDir, \"server\", \"app\")) : [];\n const sitemapOf = new Map<string, string>();\n for (const file of sitemapFiles) for (const path of file.paths) if (!sitemapOf.has(path)) sitemapOf.set(path, file.name);\n\n // First pass: one summary per page, links kept as written until every canonical host is known.\n const hosts = new Set<string>([\"localhost\"]);\n const read: { summary: EstatePage; hrefs: string[]; groups: string[][]; source: { html: string | (() => string) } }[] = [];\n for (const [path, source] of sources) {\n const html = resolveStreamedHtml(typeof source.html === \"string\" ? source.html : source.html());\n for (const match of html.matchAll(/<link\\b[^>]*\\brel=[\"']canonical[\"'][^>]*>/gi)) {\n const href = /\\bhref=[\"']([^\"']+)[\"']/i.exec(match[0])?.[1];\n try {\n if (href) {\n // A self-link may use the www or the bare host, whichever the canonical does not.\n const host = new URL(href).host;\n hosts.add(host);\n hosts.add(host.startsWith(\"www.\") ? host.slice(4) : `www.${host}`);\n }\n } catch {\n // A relative canonical names no host.\n }\n }\n const { summary, hrefs } = summarise(\n { path, html, ...(source.srcRoute ? { srcRoute: source.srcRoute } : {}), ...(source.headers ? { headers: source.headers } : {}), ...(source.revalidate !== undefined ? { revalidate: source.revalidate } : {}) },\n sitemapOf,\n input.geography,\n );\n read.push({ summary, hrefs, groups: extractLinkGroups(html), source });\n }\n const pages: EstatePage[] = [];\n for (const { summary, hrefs, groups } of read) {\n const links = new Set<string>();\n for (const href of hrefs) {\n const path = internalPath(href, summary.path, hosts);\n if (path && path !== summary.path) links.add(path);\n }\n pages.push({\n ...summary,\n links: [...links],\n linkGroups: groups.map((group) => group.flatMap((href) => internalPath(href, summary.path, hosts) ?? [])).filter((group) => group.length > 0),\n });\n }\n const byPath = new Map(pages.map((page) => [page.path, page]));\n inferFamilies(pages, input.seeds ?? {});\n // Second pass: the copy of location pages found without a manifest.\n for (const [index, page] of pages.entries()) {\n if (!isLocationFamily(page.family) || page.copy) continue;\n const source = read[index]!.source;\n page.copy = locationCopy(parseHtml(resolveStreamedHtml(typeof source.html === \"string\" ? source.html : source.html())));\n }\n const locationRoutes = new Set(pages.flatMap((page) => (isLocationFamily(page.family) && page.srcRoute && isGenerated(page.srcRoute) ? [page.srcRoute] : [])));\n const locationStems = new Set(pages.flatMap((page) => (isLocationFamily(page.family) && page.place ? [page.place.stem] : [])));\n const missingHtml = missing.map((item) => {\n const stem = input.geography ? placeOfPath(item.path, input.geography)?.stem : undefined;\n return { path: item.path, location: (item.srcRoute !== undefined && locationRoutes.has(item.srcRoute)) || (stem !== undefined && locationStems.has(stem)) };\n });\n return {\n pages,\n byPath,\n complete,\n sitemap: complete && sitemapFiles.length > 0 ? new Set(sitemapOf.keys()) : null,\n dynamicRoutes,\n fallbackRevalidate,\n buildDir: input.buildDir,\n missingHtml,\n };\n}\n\nfunction summarise(\n item: { path: string; html: string; srcRoute?: string; headers?: Record<string, unknown>; revalidate?: number | false },\n sitemapOf: ReadonlyMap<string, string>,\n geography: FullGeography | null,\n): { summary: EstatePage; hrefs: string[] } {\n const root = parseHtml(item.html);\n const elements = descendants(root);\n const robots = elements\n .filter((element) => element.tag === \"meta\" && /^(robots|googlebot)$/i.test(attr(element, \"name\") ?? \"\"))\n .map((element) => attr(element, \"content\") ?? \"\")\n .join(\" \");\n const header = item.headers?.[\"x-robots-tag\"];\n const indexable = !/noindex/i.test(`${robots} ${typeof header === \"string\" ? header : \"\"}`);\n\n const hrefs = elements.filter((element) => element.tag === \"a\").map((element) => attr(element, \"href\") ?? \"\");\n const h1Element = elements.find((element) => element.tag === \"h1\");\n const place = geography ? placeOfPath(item.path, geography) : undefined;\n const page: EstatePage = {\n path: item.path,\n srcRoute: item.srcRoute,\n ...(item.revalidate !== undefined ? { revalidate: item.revalidate } : {}),\n indexable,\n inSitemap: sitemapOf.has(item.path),\n sitemapFile: sitemapOf.get(item.path),\n links: [],\n linkGroups: [],\n manifest: readManifest(elements),\n sections: topLevelSections(root).map(sectionId),\n h1: h1Element ? textOf(h1Element) : \"\",\n place,\n family: undefined,\n familySource: undefined,\n copy: undefined,\n };\n if (page.manifest.kind === \"one\") {\n page.family = page.manifest.manifest.family;\n page.familySource = \"manifest\";\n if (isLocationFamily(page.family)) page.copy = locationCopy(root);\n }\n return { summary: page, hrefs };\n}\n\nfunction readManifest(elements: readonly HtmlElement[]): ManifestState {\n const scripts = elements.filter((element) => element.tag === \"script\" && attr(element, \"data-bl-manifest\") !== undefined);\n if (scripts.length === 0) return { kind: \"none\" };\n if (scripts.length > 1) return { kind: \"many\", count: scripts.length };\n const text = scripts[0]!.children.map((child) => (child.type === \"text\" ? child.text : \"\")).join(\"\");\n let value: unknown;\n try {\n value = JSON.parse(text);\n } catch {\n return { kind: \"invalid\", reason: \"is not valid JSON\" };\n }\n if (!isRecord(value) || typeof value.family !== \"string\" || !Array.isArray(value.planned) || !Array.isArray(value.rendered) || !Array.isArray(value.skipped)) {\n return { kind: \"invalid\", reason: \"lacks its family, planned, rendered or skipped lists\" };\n }\n const entries = (list: unknown[]) => list.every((entry) => isRecord(entry) && typeof entry.id === \"string\" && typeof entry.requirement === \"string\");\n if (!entries(value.planned) || !entries(value.rendered) || !entries(value.skipped)) {\n return { kind: \"invalid\", reason: \"has an entry without an id or requirement\" };\n }\n return {\n kind: \"one\",\n manifest: {\n version: typeof value.version === \"number\" ? value.version : 0,\n family: value.family,\n ...(typeof value.page === \"string\" ? { page: value.page } : {}),\n cap: typeof value.cap === \"number\" ? value.cap : Number.POSITIVE_INFINITY,\n order: value.order === \"recorded\" ? \"recorded\" : \"default\",\n planned: value.planned as ManifestData[\"planned\"],\n rendered: (value.rendered as Record<string, string>[]).map((entry) => ({\n id: entry.id!,\n section: typeof entry.section === \"string\" ? entry.section : entry.id!,\n requirement: entry.requirement!,\n })),\n skipped: (value.skipped as Record<string, string>[]).map((entry) => ({\n id: entry.id!,\n section: typeof entry.section === \"string\" ? entry.section : entry.id!,\n requirement: entry.requirement!,\n reason: typeof entry.reason === \"string\" ? entry.reason : \"\",\n })),\n counted: typeof value.counted === \"number\" ? value.counted : 0,\n flags: Array.isArray(value.flags) ? value.flags.filter((flag): flag is string => typeof flag === \"string\") : [],\n },\n };\n}\n\nconst SUBURB_STEM = /^\\/(?:locations?|areas?|suburbs?|service-areas?|areas-we-(?:service|serve)|regions?|where-we-work)\\/\\{place\\}$/;\n\n/** A dynamic route that builds one family (not a catch-all, which serves many). */\nfunction isGenerated(route: string): boolean {\n return route.includes(\"[\") && !route.includes(\"[...\") && !route.includes(\"[[...\");\n}\n\n/**\n * Families for pages without a manifest: the sitemap file, then the family of the other pages of their dynamic route,\n * the seeds (the representative service route), the family of their stem, then `/` as home.\n */\nfunction inferFamilies(pages: readonly EstatePage[], seeds: Readonly<Record<string, string>>): void {\n for (const page of pages) {\n if (page.family !== undefined || !page.sitemapFile) continue;\n const file = page.sitemapFile;\n if (/service-?locations?/.test(file)) page.family = page.place?.kind === \"region\" ? \"region\" : \"service-in-suburb\";\n else if (/locations?|areas?|suburbs?/.test(file)) page.family = page.place?.kind === \"region\" ? \"region\" : \"suburb\";\n if (page.family !== undefined) page.familySource = \"sitemap\";\n }\n // A dynamic route can build hubs and suburb pages alike, so pages match on the route and on the kind of place.\n const routeKey = (page: EstatePage) => `${page.srcRoute}|${page.place?.kind ?? \"\"}`;\n const counts = new Map<string, Map<string, number>>();\n for (const page of pages) {\n if (page.familySource !== \"manifest\" || !page.srcRoute || !isGenerated(page.srcRoute)) continue;\n const families = counts.get(routeKey(page)) ?? new Map<string, number>();\n families.set(page.family!, (families.get(page.family!) ?? 0) + 1);\n counts.set(routeKey(page), families);\n }\n const routeFamilies = new Map([...counts].map(([key, families]) => [key, [...families].sort((left, right) => right[1] - left[1])[0]![0]]));\n for (const page of pages) {\n if (page.family !== undefined) continue;\n const family = (page.srcRoute ? routeFamilies.get(routeKey(page)) : undefined) ?? seeds[page.path];\n if (family) {\n page.family = family;\n page.familySource = \"route\";\n }\n }\n // The other pages of a seeded page's dynamic route share its family.\n for (const page of pages) {\n if (page.family !== undefined || !page.srcRoute || !isGenerated(page.srcRoute)) continue;\n const seeded = pages.find((other) => other.familySource === \"route\" && other.srcRoute === page.srcRoute);\n if (seeded) {\n page.family = seeded.family;\n page.familySource = \"route\";\n }\n }\n const stems = new Map<string, string>();\n for (const page of pages) {\n if (!page.place || (page.family !== \"suburb\" && page.family !== \"service-in-suburb\")) continue;\n if (!stems.has(page.place.stem)) stems.set(page.place.stem, page.family);\n }\n // A stem that three or more suburbs share is a family of location pages even when nothing names it: suburb pages\n // under an areas folder (`/locations/{place}`), service-in-suburb pages otherwise.\n const unnamed = new Map<string, number>();\n for (const page of pages) {\n if (page.family === undefined && page.place?.kind === \"suburb\") unnamed.set(page.place.stem, (unnamed.get(page.place.stem) ?? 0) + 1);\n }\n for (const [stem, count] of unnamed) {\n if (count >= 3 && !stems.has(stem)) stems.set(stem, SUBURB_STEM.test(stem) ? \"suburb\" : \"service-in-suburb\");\n }\n for (const page of pages) {\n if (page.family !== undefined) continue;\n if (page.path === \"/\") {\n page.family = \"home\";\n page.familySource = \"path\";\n continue;\n }\n const family = page.place ? stems.get(page.place.stem) : undefined;\n if (!family || !page.place) continue;\n page.family = page.place.kind === \"region\" ? \"region\" : family;\n page.familySource = \"stem\";\n }\n}\n\n/** The page content a person reads, without the header, footer, navigation, call bar or drawer. */\nfunction contentRoot(root: HtmlElement): HtmlElement {\n return descendants(root).find((element) => element.tag === \"main\") ?? descendants(root).find((element) => element.tag === \"body\") ?? root;\n}\n\nconst CHROME = (element: HtmlElement) =>\n [\"header\", \"footer\", \"nav\"].includes(element.tag) || [\"header\", \"footer\", \"callbar\", \"drawer\", \"utility\"].includes(attr(element, \"data-bl\") ?? \"\");\n\nfunction linesOutsideChrome(element: HtmlElement): string[] {\n // readableLines has no skip, so chrome is cut from a shallow copy of the tree.\n const prune = (node: HtmlElement): HtmlElement => ({\n ...node,\n children: node.children.flatMap((child): HtmlNode[] => (child.type === \"element\" ? (CHROME(child) ? [] : [prune(child)]) : [child])),\n });\n return readableLines(prune(element)).map((line) => line.text);\n}\n\nfunction locationCopy(root: HtmlElement): LocationCopy {\n const elements = descendants(root);\n const sections = topLevelSections(root);\n const lines = sections.length > 0\n ? sections.flatMap((section) => readableLines(section).map((line) => ({ section: sectionId(section), text: line.text })))\n : linesOutsideChrome(contentRoot(root)).map((text) => ({ section: \"page\", text }));\n const sectionOf = (id: string) => elements.find((element) => attr(element, \"data-bl-section\") === id);\n\n // The FAQs section, or on a page without sections the disclosures that ask a question.\n const faqSection = sectionOf(\"faqs\");\n const faqScope = faqSection ?? contentRoot(root);\n const faqs: { question: string; answer: string }[] = [];\n for (const details of descendants(faqScope).filter((element) => element.tag === \"details\")) {\n const summary = details.children.find((child): child is HtmlElement => child.type === \"element\" && child.tag === \"summary\");\n if (!summary) continue;\n const question = textOf(summary);\n const answer = normaliseText(textOf(details, true, (element) => element === summary));\n if (question && (faqSection || question.endsWith(\"?\"))) faqs.push({ question, answer });\n }\n if (faqs.length === 0) {\n for (const term of descendants(faqScope).filter((element) => element.tag === \"dt\")) {\n const siblings = term.parent?.children.filter((child): child is HtmlElement => child.type === \"element\") ?? [];\n const definition = siblings[siblings.indexOf(term) + 1];\n const question = textOf(term);\n if (definition?.tag === \"dd\" && (faqSection || question.endsWith(\"?\"))) faqs.push({ question, answer: textOf(definition, true) });\n }\n }\n\n const jobsSection = sectionOf(\"nearby-jobs\");\n let jobs: string[] | null = null;\n if (jobsSection) {\n const cards = descendants(jobsSection).filter(\n (element) => (element.tag === \"li\" || element.tag === \"article\") && !descendants(element).some((inner) => inner.tag === \"li\" || inner.tag === \"article\"),\n );\n const headings = new Set(descendants(jobsSection).filter((element) => /^h[1-6]$/.test(element.tag)).map((element) => textOf(element)));\n jobs = cards.length > 0\n ? cards.map((card) => textOf(card, true)).filter(Boolean)\n : readableLines(jobsSection).map((line) => line.text).filter((text) => !headings.has(text));\n }\n\n const pricesSection = sectionOf(\"price-guide\");\n const reviewsSection = sectionOf(\"reviews\");\n const reviews = reviewsSection\n ? {\n written: descendants(reviewsSection).filter((element) => element.tag === \"blockquote\").length,\n googleLink: descendants(reviewsSection).some((element) => element.tag === \"a\" && /(?:^|\\.)google\\.|g\\.page|goo\\.gl/i.test(attr(element, \"href\") ?? \"\")),\n rating:\n descendants(reviewsSection).some((element) => attr(element, \"data-bl\") === \"rating-chip\") ||\n /\\b[1-5](?:\\.\\d)?\\s*(?:out of 5|stars?|★)|\\b[1-5]\\.\\d\\b/i.test(textOf(reviewsSection, true)),\n }\n : null;\n\n const forms = elements.filter((element) => element.tag === \"form\" && !isHiddenFromPeople(element));\n const form = forms.find((element) => attr(element, \"data-bl\") === \"quote-form\") ?? forms[0];\n let quoteForm: LocationCopy[\"quoteForm\"] = null;\n if (form) {\n const field = descendants(form).find(\n (element) =>\n element.tag === \"input\" &&\n (attr(element, \"autocomplete\") === \"address-level2\" || /suburb|location/i.test(`${attr(element, \"name\") ?? \"\"} ${attr(element, \"id\") ?? \"\"}`)),\n );\n quoteForm = { suburbField: field !== undefined, suburbValue: normaliseText(field ? (attr(field, \"value\") ?? \"\") : \"\") };\n }\n\n return {\n lines,\n faqs,\n jobs,\n prices: pricesSection ? textOf(pricesSection, true) : null,\n reviews,\n quoteForm,\n telLink: elements.some((element) => element.tag === \"a\" && /^tel:/i.test(attr(element, \"href\") ?? \"\")),\n callBar: elements.some((element) => attr(element, \"data-bl\") === \"callbar\"),\n };\n}\n\n/** An internal link's normalised path, or null for other sites, anchors on the same page, mail and phone links. */\nexport function internalPath(href: string, from: string, hosts: ReadonlySet<string>): string | null {\n const value = href.trim();\n if (!value || value.startsWith(\"#\") || /^(?:mailto|tel|sms|javascript|data):/i.test(value)) return null;\n let url: URL;\n try {\n url = new URL(value, `http://localhost${from}`);\n } catch {\n return null;\n }\n if (!/^https?:$/.test(url.protocol) || !hosts.has(url.host) && !hosts.has(url.hostname)) return null;\n let path: string;\n try {\n path = decodeURIComponent(url.pathname);\n } catch {\n path = url.pathname;\n }\n return normalisePath(path);\n}\n\ninterface SitemapFile {\n readonly name: string;\n readonly paths: readonly string[];\n}\n\n/** The URL sets in the build's prerendered sitemap files (`*.xml.body`); sitemap indexes are skipped. */\nfunction readSitemaps(appDir: string): SitemapFile[] {\n if (!existsSync(appDir)) return [];\n const files: SitemapFile[] = [];\n const visit = (directory: string) => {\n for (const entry of readdirSync(directory, { withFileTypes: true })) {\n const full = join(directory, entry.name);\n if (entry.isDirectory()) visit(full);\n else if (entry.name.endsWith(\".xml.body\")) {\n const xml = readFileSync(full, \"utf8\");\n if (!/<urlset\\b/i.test(xml)) continue;\n const paths: string[] = [];\n for (const match of xml.matchAll(/<loc>\\s*([^<\\s]+)\\s*<\\/loc>/gi)) {\n try {\n paths.push(normalisePath(new URL(match[1]!.replace(/&/g, \"&\")).pathname));\n } catch {\n // A loc that is not a URL lists no page.\n }\n }\n const name = relative(appDir, full).replace(/\\.xml\\.body$/, \"\").split(\"/\").pop()!.replace(/-\\d+$/, \"\");\n files.push({ name, paths });\n }\n }\n };\n visit(appDir);\n return files;\n}\n\nfunction readJson(file: string): unknown {\n if (!existsSync(file)) return undefined;\n try {\n return JSON.parse(readFileSync(file, \"utf8\"));\n } catch {\n return undefined;\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"estate.js","sourceRoot":"","sources":["../../../../src/site-system/rules/full/estate.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The estate the full tier reads: every page of the production build (the route catalogue as Next built it, from\n * `.next/prerender-manifest.json` and each page's prerendered HTML), the sitemap files in the build, and per page its\n * indexing, internal links, section manifest and the copy the location rules compare. Nothing is crawled: a site\n * checked with only a base URL and no build has just its sampled pages, and the estate-wide checks say so.\n *\n * A page's family is the one its section manifest names. A page without a manifest takes its family from the\n * sitemap file that lists it (`service-locations-*.xml`, `locations-*.xml`) or from the other pages of its stem (the\n * path with its place replaced: `/services/decking/{place}`), so a location page missing its manifest is still\n * found; a page built from the same dynamic route as a page with a manifest takes that page's family; the\n * representative service route is a service page; home is `/`. Other pages without a manifest have no known family.\n */\nimport { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { join, relative } from \"node:path\";\nimport { extractLinkGroups } from \"../../../page-standard.js\";\nimport type { SiteSystemPage } from \"../../samples.js\";\nimport { resolveStreamedHtml } from \"../../streamed-html.js\";\nimport { normalisePath, sectionId, topLevelSections } from \"../enquiry/common.js\";\nimport { attr, descendants, isHiddenFromPeople, normaliseText, parseHtml, readableLines, textOf, type HtmlElement, type HtmlNode } from \"../enquiry/html.js\";\nimport { placeOfPath, type FullGeography, type PathAliases, type PathPlace } from \"./geography.js\";\n\n/** The section manifest as SectionSequence writes it (site-core `BrandlabSectionManifest`). */\nexport interface ManifestData {\n readonly version: number;\n readonly family: string;\n readonly page?: string;\n readonly cap: number;\n readonly order: \"default\" | \"recorded\";\n readonly planned: readonly { readonly id: string; readonly requirement: string }[];\n readonly rendered: readonly { readonly id: string; readonly section: string; readonly requirement: string; readonly tone?: string }[];\n readonly skipped: readonly { readonly id: string; readonly section: string; readonly requirement: string; readonly reason: string }[];\n readonly counted: number;\n readonly flags: readonly string[];\n}\n\nexport type ManifestState =\n | { readonly kind: \"none\" }\n | { readonly kind: \"invalid\"; readonly reason: string }\n | { readonly kind: \"many\"; readonly count: number }\n | { readonly kind: \"one\"; readonly manifest: ManifestData };\n\nexport const LOCATION_FAMILIES = [\"suburb\", \"service-in-suburb\", \"region\"] as const;\nexport type LocationFamily = (typeof LOCATION_FAMILIES)[number];\n\nexport function isLocationFamily(family: string | undefined): family is LocationFamily {\n return (LOCATION_FAMILIES as readonly string[]).includes(family ?? \"\");\n}\n\n/** The copy and parts of a location page the L4, L9 and L10 rules read. */\nexport interface LocationCopy {\n /** Readable lines of the page content, with the section they sit in (\"page\" outside any section). */\n readonly lines: readonly { readonly section: string; readonly text: string }[];\n readonly faqs: readonly { readonly question: string; readonly answer: string }[];\n /** The job cards of the nearby-jobs section; null when the page has none. */\n readonly jobs: readonly string[] | null;\n /** The price-guide section's text; null when the page has none. */\n readonly prices: string | null;\n readonly reviews: { readonly written: number; readonly googleLink: boolean; readonly rating: boolean } | null;\n readonly quoteForm: { readonly suburbField: boolean; readonly suburbValue: string } | null;\n readonly telLink: boolean;\n readonly callBar: boolean;\n}\n\nexport interface EstatePage {\n readonly path: string;\n /** The app route Next built the page from (`/locations/[suburb]`), when known. */\n readonly srcRoute: string | undefined;\n /** The page's timed refresh in seconds as Next built it (`initialRevalidateSeconds`); false for never; absent when unknown. */\n readonly revalidate?: number | false;\n readonly indexable: boolean;\n readonly inSitemap: boolean;\n /** The sitemap file that lists the page, without its number and extension (`service-locations`). */\n readonly sitemapFile: string | undefined;\n /** Internal paths the page links to, once each. */\n readonly links: readonly string[];\n /** The main content's link groups (lists), as internal paths, for the neighbour order. */\n readonly linkGroups: readonly (readonly string[])[];\n readonly manifest: ManifestState;\n /** Top-level `data-bl-section` ids, in document order. */\n readonly sections: readonly string[];\n /**\n * Per top-level section (3.14.0): the `data-bl-slot` values inside it and the `slot:reason` pairs of its\n * `data-bl-slot-skip` attribute.\n */\n readonly slots?: ReadonlyMap<string, { readonly present: readonly string[]; readonly skipped: readonly { readonly slot: string; readonly reason: string }[] }>;\n readonly h1: string;\n /** The page's `<title>` text (3.14.0); absent when it has none. */\n readonly title?: string;\n readonly place: PathPlace | undefined;\n family: string | undefined;\n familySource: \"manifest\" | \"sitemap\" | \"route\" | \"stem\" | \"path\" | undefined;\n copy: LocationCopy | undefined;\n}\n\nexport interface Estate {\n readonly pages: readonly EstatePage[];\n readonly byPath: ReadonlyMap<string, EstatePage>;\n /** True when the pages are the whole production build, not just a sample. */\n readonly complete: boolean;\n /** Paths listed in the build's sitemap files; null when the build holds no sitemap. */\n readonly sitemap: ReadonlySet<string> | null;\n /** Dynamic app routes in the build and how many pages each produced. */\n readonly dynamicRoutes: ReadonlyMap<string, number>;\n /** The timed refresh of pages a dynamic route renders on demand (`fallbackRevalidate`), for routes with a fallback. */\n readonly fallbackRevalidate: ReadonlyMap<string, number | false>;\n readonly buildDir: string;\n /** Routes the prerender manifest lists with no HTML in the build; `location` when the route is a location page's. */\n readonly missingHtml: readonly { readonly path: string; readonly location: boolean }[];\n}\n\nconst INTERNAL_ROUTES = new Set([\"/_not-found\", \"/_global-error\", \"/404\", \"/500\"]);\n\n/** Reads the estate: the whole build when `buildDir` holds one, otherwise the sampled pages. */\nexport function readEstate(input: {\n readonly pages: readonly SiteSystemPage[];\n readonly buildDir: string;\n readonly geography: FullGeography | null;\n /** Families known from elsewhere, by path (the representative service route). */\n readonly seeds?: Readonly<Record<string, string>>;\n /** The estate plan's public slugs (3.14.0). */\n readonly aliases?: PathAliases;\n}): Estate {\n const missing: { path: string; srcRoute: string | undefined }[] = [];\n const manifest = readJson(join(input.buildDir, \"prerender-manifest.json\"));\n const sources = new Map<string, { html: string | (() => string); srcRoute?: string; headers?: Record<string, unknown>; revalidate?: number | false }>();\n const dynamicRoutes = new Map<string, number>();\n const fallbackRevalidate = new Map<string, number | false>();\n let complete = false;\n\n if (isRecord(manifest) && isRecord(manifest.routes)) {\n complete = true;\n const appDir = join(input.buildDir, \"server\", \"app\");\n for (const [route, entry] of isRecord(manifest.dynamicRoutes) ? Object.entries(manifest.dynamicRoutes) : []) {\n dynamicRoutes.set(route, 0);\n const fallback = isRecord(entry) ? entry.fallbackRevalidate : undefined;\n if (isRecord(entry) && entry.fallback !== false && (typeof fallback === \"number\" || fallback === false)) fallbackRevalidate.set(route, fallback);\n }\n for (const [rawPath, entry] of Object.entries(manifest.routes)) {\n if (!isRecord(entry) || !rawPath.startsWith(\"/\")) continue;\n const srcRoute = typeof entry.srcRoute === \"string\" ? entry.srcRoute : undefined;\n if (srcRoute && dynamicRoutes.has(srcRoute)) dynamicRoutes.set(srcRoute, (dynamicRoutes.get(srcRoute) ?? 0) + 1);\n if (entry.routeType !== undefined ? entry.routeType !== \"page\" : /\\.[a-z0-9]+$/i.test(rawPath)) continue;\n const path = normalisePath(rawPath);\n if (INTERNAL_ROUTES.has(path) || INTERNAL_ROUTES.has(srcRoute ?? \"\")) continue;\n const file = join(appDir, `${path === \"/\" ? \"/index\" : path}.html`);\n if (!existsSync(file)) {\n missing.push({ path, srcRoute });\n continue;\n }\n const meta = readJson(join(appDir, `${path === \"/\" ? \"/index\" : path}.meta`));\n const revalidate = entry.initialRevalidateSeconds;\n sources.set(path, {\n html: () => readFileSync(file, \"utf8\"),\n ...(srcRoute ? { srcRoute } : {}),\n ...(typeof revalidate === \"number\" || revalidate === false ? { revalidate } : {}),\n ...(isRecord(meta) && isRecord(meta.headers) ? { headers: meta.headers } : {}),\n });\n }\n }\n // Sampled pages fill in what the build does not have (a base-URL run without a build).\n for (const page of input.pages) {\n const path = normalisePath(page.path);\n if (!sources.has(path)) sources.set(path, { html: page.html });\n }\n\n const sitemapFiles = complete ? readSitemaps(join(input.buildDir, \"server\", \"app\")) : [];\n const sitemapOf = new Map<string, string>();\n for (const file of sitemapFiles) for (const path of file.paths) if (!sitemapOf.has(path)) sitemapOf.set(path, file.name);\n\n // First pass: one summary per page, links kept as written until every canonical host is known.\n const hosts = new Set<string>([\"localhost\"]);\n const read: { summary: EstatePage; hrefs: string[]; groups: string[][]; source: { html: string | (() => string) } }[] = [];\n for (const [path, source] of sources) {\n const html = resolveStreamedHtml(typeof source.html === \"string\" ? source.html : source.html());\n for (const match of html.matchAll(/<link\\b[^>]*\\brel=[\"']canonical[\"'][^>]*>/gi)) {\n const href = /\\bhref=[\"']([^\"']+)[\"']/i.exec(match[0])?.[1];\n try {\n if (href) {\n // A self-link may use the www or the bare host, whichever the canonical does not.\n const host = new URL(href).host;\n hosts.add(host);\n hosts.add(host.startsWith(\"www.\") ? host.slice(4) : `www.${host}`);\n }\n } catch {\n // A relative canonical names no host.\n }\n }\n const { summary, hrefs } = summarise(\n { path, html, ...(source.srcRoute ? { srcRoute: source.srcRoute } : {}), ...(source.headers ? { headers: source.headers } : {}), ...(source.revalidate !== undefined ? { revalidate: source.revalidate } : {}) },\n sitemapOf,\n input.geography,\n input.aliases,\n );\n read.push({ summary, hrefs, groups: extractLinkGroups(html), source });\n }\n const pages: EstatePage[] = [];\n for (const { summary, hrefs, groups } of read) {\n const links = new Set<string>();\n for (const href of hrefs) {\n const path = internalPath(href, summary.path, hosts);\n if (path && path !== summary.path) links.add(path);\n }\n pages.push({\n ...summary,\n links: [...links],\n linkGroups: groups.map((group) => group.flatMap((href) => internalPath(href, summary.path, hosts) ?? [])).filter((group) => group.length > 0),\n });\n }\n const byPath = new Map(pages.map((page) => [page.path, page]));\n inferFamilies(pages, input.seeds ?? {});\n // Second pass: the copy of location pages found without a manifest.\n for (const [index, page] of pages.entries()) {\n if (!isLocationFamily(page.family) || page.copy) continue;\n const source = read[index]!.source;\n page.copy = locationCopy(parseHtml(resolveStreamedHtml(typeof source.html === \"string\" ? source.html : source.html())));\n }\n const locationRoutes = new Set(pages.flatMap((page) => (isLocationFamily(page.family) && page.srcRoute && isGenerated(page.srcRoute) ? [page.srcRoute] : [])));\n const locationStems = new Set(pages.flatMap((page) => (isLocationFamily(page.family) && page.place ? [page.place.stem] : [])));\n const missingHtml = missing.map((item) => {\n const stem = input.geography ? placeOfPath(item.path, input.geography, input.aliases)?.stem : undefined;\n return { path: item.path, location: (item.srcRoute !== undefined && locationRoutes.has(item.srcRoute)) || (stem !== undefined && locationStems.has(stem)) };\n });\n return {\n pages,\n byPath,\n complete,\n sitemap: complete && sitemapFiles.length > 0 ? new Set(sitemapOf.keys()) : null,\n dynamicRoutes,\n fallbackRevalidate,\n buildDir: input.buildDir,\n missingHtml,\n };\n}\n\nfunction summarise(\n item: { path: string; html: string; srcRoute?: string; headers?: Record<string, unknown>; revalidate?: number | false },\n sitemapOf: ReadonlyMap<string, string>,\n geography: FullGeography | null,\n aliases?: PathAliases,\n): { summary: EstatePage; hrefs: string[] } {\n const root = parseHtml(item.html);\n const elements = descendants(root);\n const robots = elements\n .filter((element) => element.tag === \"meta\" && /^(robots|googlebot)$/i.test(attr(element, \"name\") ?? \"\"))\n .map((element) => attr(element, \"content\") ?? \"\")\n .join(\" \");\n const header = item.headers?.[\"x-robots-tag\"];\n const indexable = !/noindex/i.test(`${robots} ${typeof header === \"string\" ? header : \"\"}`);\n\n const hrefs = elements.filter((element) => element.tag === \"a\").map((element) => attr(element, \"href\") ?? \"\");\n const h1Element = elements.find((element) => element.tag === \"h1\");\n const place = geography ? placeOfPath(item.path, geography, aliases) : undefined;\n const page: EstatePage = {\n path: item.path,\n srcRoute: item.srcRoute,\n ...(item.revalidate !== undefined ? { revalidate: item.revalidate } : {}),\n indexable,\n inSitemap: sitemapOf.has(item.path),\n sitemapFile: sitemapOf.get(item.path),\n links: [],\n linkGroups: [],\n manifest: readManifest(elements),\n sections: topLevelSections(root).map(sectionId),\n slots: sectionSlots(root),\n h1: h1Element ? textOf(h1Element) : \"\",\n ...(titleOf(elements) !== undefined ? { title: titleOf(elements)! } : {}),\n place,\n family: undefined,\n familySource: undefined,\n copy: undefined,\n };\n if (page.manifest.kind === \"one\") {\n page.family = page.manifest.manifest.family;\n page.familySource = \"manifest\";\n if (isLocationFamily(page.family)) page.copy = locationCopy(root);\n }\n return { summary: page, hrefs };\n}\n\nfunction sectionSlots(root: HtmlElement): EstatePage[\"slots\"] {\n const slots = new Map<string, { present: string[]; skipped: { slot: string; reason: string }[] }>();\n for (const section of topLevelSections(root)) {\n const present = descendants(section).flatMap((element) => attr(element, \"data-bl-slot\") ?? []);\n const skipped = (attr(section, \"data-bl-slot-skip\") ?? \"\").split(/\\s+/).flatMap((pair) => {\n const [slot, reason] = pair.split(\":\");\n return slot && reason ? [{ slot, reason }] : [];\n });\n if (present.length > 0 || skipped.length > 0) slots.set(sectionId(section), { present, skipped });\n }\n return slots;\n}\n\nfunction titleOf(elements: readonly HtmlElement[]): string | undefined {\n const title = elements.find((element) => element.tag === \"title\");\n return title ? normaliseText(textOf(title)) : undefined;\n}\n\nfunction readManifest(elements: readonly HtmlElement[]): ManifestState {\n const scripts = elements.filter((element) => element.tag === \"script\" && attr(element, \"data-bl-manifest\") !== undefined);\n if (scripts.length === 0) return { kind: \"none\" };\n if (scripts.length > 1) return { kind: \"many\", count: scripts.length };\n const text = scripts[0]!.children.map((child) => (child.type === \"text\" ? child.text : \"\")).join(\"\");\n let value: unknown;\n try {\n value = JSON.parse(text);\n } catch {\n return { kind: \"invalid\", reason: \"is not valid JSON\" };\n }\n if (!isRecord(value) || typeof value.family !== \"string\" || !Array.isArray(value.planned) || !Array.isArray(value.rendered) || !Array.isArray(value.skipped)) {\n return { kind: \"invalid\", reason: \"lacks its family, planned, rendered or skipped lists\" };\n }\n const entries = (list: unknown[]) => list.every((entry) => isRecord(entry) && typeof entry.id === \"string\" && typeof entry.requirement === \"string\");\n if (!entries(value.planned) || !entries(value.rendered) || !entries(value.skipped)) {\n return { kind: \"invalid\", reason: \"has an entry without an id or requirement\" };\n }\n return {\n kind: \"one\",\n manifest: {\n version: typeof value.version === \"number\" ? value.version : 0,\n family: value.family,\n ...(typeof value.page === \"string\" ? { page: value.page } : {}),\n cap: typeof value.cap === \"number\" ? value.cap : Number.POSITIVE_INFINITY,\n order: value.order === \"recorded\" ? \"recorded\" : \"default\",\n planned: value.planned as ManifestData[\"planned\"],\n rendered: (value.rendered as Record<string, string>[]).map((entry) => ({\n id: entry.id!,\n section: typeof entry.section === \"string\" ? entry.section : entry.id!,\n requirement: entry.requirement!,\n })),\n skipped: (value.skipped as Record<string, string>[]).map((entry) => ({\n id: entry.id!,\n section: typeof entry.section === \"string\" ? entry.section : entry.id!,\n requirement: entry.requirement!,\n reason: typeof entry.reason === \"string\" ? entry.reason : \"\",\n })),\n counted: typeof value.counted === \"number\" ? value.counted : 0,\n flags: Array.isArray(value.flags) ? value.flags.filter((flag): flag is string => typeof flag === \"string\") : [],\n },\n };\n}\n\nconst SUBURB_STEM = /^\\/(?:locations?|areas?|suburbs?|service-areas?|areas-we-(?:service|serve)|regions?|where-we-work)\\/\\{place\\}$/;\n\n/** A dynamic route that builds one family (not a catch-all, which serves many). */\nfunction isGenerated(route: string): boolean {\n return route.includes(\"[\") && !route.includes(\"[...\") && !route.includes(\"[[...\");\n}\n\n/**\n * Families for pages without a manifest: the sitemap file, then the family of the other pages of their dynamic route,\n * the seeds (the representative service route), the family of their stem, then `/` as home.\n */\nfunction inferFamilies(pages: readonly EstatePage[], seeds: Readonly<Record<string, string>>): void {\n for (const page of pages) {\n if (page.family !== undefined || !page.sitemapFile) continue;\n const file = page.sitemapFile;\n if (/service-?locations?/.test(file)) page.family = page.place?.kind === \"region\" ? \"region\" : \"service-in-suburb\";\n else if (/locations?|areas?|suburbs?/.test(file)) page.family = page.place?.kind === \"region\" ? \"region\" : \"suburb\";\n if (page.family !== undefined) page.familySource = \"sitemap\";\n }\n // A dynamic route can build hubs and suburb pages alike, so pages match on the route and on the kind of place.\n const routeKey = (page: EstatePage) => `${page.srcRoute}|${page.place?.kind ?? \"\"}`;\n const counts = new Map<string, Map<string, number>>();\n for (const page of pages) {\n if (page.familySource !== \"manifest\" || !page.srcRoute || !isGenerated(page.srcRoute)) continue;\n const families = counts.get(routeKey(page)) ?? new Map<string, number>();\n families.set(page.family!, (families.get(page.family!) ?? 0) + 1);\n counts.set(routeKey(page), families);\n }\n const routeFamilies = new Map([...counts].map(([key, families]) => [key, [...families].sort((left, right) => right[1] - left[1])[0]![0]]));\n for (const page of pages) {\n if (page.family !== undefined) continue;\n const family = (page.srcRoute ? routeFamilies.get(routeKey(page)) : undefined) ?? seeds[page.path];\n if (family) {\n page.family = family;\n page.familySource = \"route\";\n }\n }\n // The other pages of a seeded page's dynamic route share its family.\n for (const page of pages) {\n if (page.family !== undefined || !page.srcRoute || !isGenerated(page.srcRoute)) continue;\n const seeded = pages.find((other) => other.familySource === \"route\" && other.srcRoute === page.srcRoute);\n if (seeded) {\n page.family = seeded.family;\n page.familySource = \"route\";\n }\n }\n const stems = new Map<string, string>();\n for (const page of pages) {\n if (!page.place || (page.family !== \"suburb\" && page.family !== \"service-in-suburb\")) continue;\n if (!stems.has(page.place.stem)) stems.set(page.place.stem, page.family);\n }\n // A stem that three or more suburbs share is a family of location pages even when nothing names it: suburb pages\n // under an areas folder (`/locations/{place}`), service-in-suburb pages otherwise.\n const unnamed = new Map<string, number>();\n for (const page of pages) {\n if (page.family === undefined && page.place?.kind === \"suburb\") unnamed.set(page.place.stem, (unnamed.get(page.place.stem) ?? 0) + 1);\n }\n for (const [stem, count] of unnamed) {\n if (count >= 3 && !stems.has(stem)) stems.set(stem, SUBURB_STEM.test(stem) ? \"suburb\" : \"service-in-suburb\");\n }\n for (const page of pages) {\n if (page.family !== undefined) continue;\n if (page.path === \"/\") {\n page.family = \"home\";\n page.familySource = \"path\";\n continue;\n }\n const family = page.place ? stems.get(page.place.stem) : undefined;\n if (!family || !page.place) continue;\n page.family = page.place.kind === \"region\" ? \"region\" : family;\n page.familySource = \"stem\";\n }\n}\n\n/** The page content a person reads, without the header, footer, navigation, call bar or drawer. */\nfunction contentRoot(root: HtmlElement): HtmlElement {\n return descendants(root).find((element) => element.tag === \"main\") ?? descendants(root).find((element) => element.tag === \"body\") ?? root;\n}\n\nconst CHROME = (element: HtmlElement) =>\n [\"header\", \"footer\", \"nav\"].includes(element.tag) || [\"header\", \"footer\", \"callbar\", \"drawer\", \"utility\"].includes(attr(element, \"data-bl\") ?? \"\");\n\nfunction linesOutsideChrome(element: HtmlElement): string[] {\n // readableLines has no skip, so chrome is cut from a shallow copy of the tree.\n const prune = (node: HtmlElement): HtmlElement => ({\n ...node,\n children: node.children.flatMap((child): HtmlNode[] => (child.type === \"element\" ? (CHROME(child) ? [] : [prune(child)]) : [child])),\n });\n return readableLines(prune(element)).map((line) => line.text);\n}\n\nfunction locationCopy(root: HtmlElement): LocationCopy {\n const elements = descendants(root);\n const sections = topLevelSections(root);\n const lines = sections.length > 0\n ? sections.flatMap((section) => readableLines(section).map((line) => ({ section: sectionId(section), text: line.text })))\n : linesOutsideChrome(contentRoot(root)).map((text) => ({ section: \"page\", text }));\n const sectionOf = (id: string) => elements.find((element) => attr(element, \"data-bl-section\") === id);\n\n // The FAQs section, or on a page without sections the disclosures that ask a question.\n const faqSection = sectionOf(\"faqs\");\n const faqScope = faqSection ?? contentRoot(root);\n const faqs: { question: string; answer: string }[] = [];\n for (const details of descendants(faqScope).filter((element) => element.tag === \"details\")) {\n const summary = details.children.find((child): child is HtmlElement => child.type === \"element\" && child.tag === \"summary\");\n if (!summary) continue;\n const question = textOf(summary);\n const answer = normaliseText(textOf(details, true, (element) => element === summary));\n if (question && (faqSection || question.endsWith(\"?\"))) faqs.push({ question, answer });\n }\n if (faqs.length === 0) {\n for (const term of descendants(faqScope).filter((element) => element.tag === \"dt\")) {\n const siblings = term.parent?.children.filter((child): child is HtmlElement => child.type === \"element\") ?? [];\n const definition = siblings[siblings.indexOf(term) + 1];\n const question = textOf(term);\n if (definition?.tag === \"dd\" && (faqSection || question.endsWith(\"?\"))) faqs.push({ question, answer: textOf(definition, true) });\n }\n }\n\n const jobsSection = sectionOf(\"nearby-jobs\");\n let jobs: string[] | null = null;\n if (jobsSection) {\n const cards = descendants(jobsSection).filter(\n (element) => (element.tag === \"li\" || element.tag === \"article\") && !descendants(element).some((inner) => inner.tag === \"li\" || inner.tag === \"article\"),\n );\n const headings = new Set(descendants(jobsSection).filter((element) => /^h[1-6]$/.test(element.tag)).map((element) => textOf(element)));\n jobs = cards.length > 0\n ? cards.map((card) => textOf(card, true)).filter(Boolean)\n : readableLines(jobsSection).map((line) => line.text).filter((text) => !headings.has(text));\n }\n\n const pricesSection = sectionOf(\"price-guide\");\n const reviewsSection = sectionOf(\"reviews\");\n const reviews = reviewsSection\n ? {\n written: descendants(reviewsSection).filter((element) => element.tag === \"blockquote\").length,\n googleLink: descendants(reviewsSection).some((element) => element.tag === \"a\" && /(?:^|\\.)google\\.|g\\.page|goo\\.gl/i.test(attr(element, \"href\") ?? \"\")),\n rating:\n descendants(reviewsSection).some((element) => attr(element, \"data-bl\") === \"rating-chip\") ||\n /\\b[1-5](?:\\.\\d)?\\s*(?:out of 5|stars?|★)|\\b[1-5]\\.\\d\\b/i.test(textOf(reviewsSection, true)),\n }\n : null;\n\n const forms = elements.filter((element) => element.tag === \"form\" && !isHiddenFromPeople(element));\n const form = forms.find((element) => attr(element, \"data-bl\") === \"quote-form\") ?? forms[0];\n let quoteForm: LocationCopy[\"quoteForm\"] = null;\n if (form) {\n const field = descendants(form).find(\n (element) =>\n element.tag === \"input\" &&\n (attr(element, \"autocomplete\") === \"address-level2\" || /suburb|location/i.test(`${attr(element, \"name\") ?? \"\"} ${attr(element, \"id\") ?? \"\"}`)),\n );\n quoteForm = { suburbField: field !== undefined, suburbValue: normaliseText(field ? (attr(field, \"value\") ?? \"\") : \"\") };\n }\n\n return {\n lines,\n faqs,\n jobs,\n prices: pricesSection ? textOf(pricesSection, true) : null,\n reviews,\n quoteForm,\n telLink: elements.some((element) => element.tag === \"a\" && /^tel:/i.test(attr(element, \"href\") ?? \"\")),\n callBar: elements.some((element) => attr(element, \"data-bl\") === \"callbar\"),\n };\n}\n\n/** An internal link's normalised path, or null for other sites, anchors on the same page, mail and phone links. */\nexport function internalPath(href: string, from: string, hosts: ReadonlySet<string>): string | null {\n const value = href.trim();\n if (!value || value.startsWith(\"#\") || /^(?:mailto|tel|sms|javascript|data):/i.test(value)) return null;\n let url: URL;\n try {\n url = new URL(value, `http://localhost${from}`);\n } catch {\n return null;\n }\n if (!/^https?:$/.test(url.protocol) || !hosts.has(url.host) && !hosts.has(url.hostname)) return null;\n let path: string;\n try {\n path = decodeURIComponent(url.pathname);\n } catch {\n path = url.pathname;\n }\n return normalisePath(path);\n}\n\ninterface SitemapFile {\n readonly name: string;\n readonly paths: readonly string[];\n}\n\n/** The URL sets in the build's prerendered sitemap files (`*.xml.body`); sitemap indexes are skipped. */\nfunction readSitemaps(appDir: string): SitemapFile[] {\n if (!existsSync(appDir)) return [];\n const files: SitemapFile[] = [];\n const visit = (directory: string) => {\n for (const entry of readdirSync(directory, { withFileTypes: true })) {\n const full = join(directory, entry.name);\n if (entry.isDirectory()) visit(full);\n else if (entry.name.endsWith(\".xml.body\")) {\n const xml = readFileSync(full, \"utf8\");\n if (!/<urlset\\b/i.test(xml)) continue;\n const paths: string[] = [];\n for (const match of xml.matchAll(/<loc>\\s*([^<\\s]+)\\s*<\\/loc>/gi)) {\n try {\n paths.push(normalisePath(new URL(match[1]!.replace(/&/g, \"&\")).pathname));\n } catch {\n // A loc that is not a URL lists no page.\n }\n }\n const name = relative(appDir, full).replace(/\\.xml\\.body$/, \"\").split(\"/\").pop()!.replace(/-\\d+$/, \"\");\n files.push({ name, paths });\n }\n }\n };\n visit(appDir);\n return files;\n}\n\nfunction readJson(file: string): unknown {\n if (!existsSync(file)) return undefined;\n try {\n return JSON.parse(readFileSync(file, \"utf8\"));\n } catch {\n return undefined;\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n"]}
|
|
@@ -50,11 +50,17 @@ export interface PathPlace {
|
|
|
50
50
|
/** The path with the place replaced by `{place}`: pages sharing a stem are one family's pages. */
|
|
51
51
|
readonly stem: string;
|
|
52
52
|
}
|
|
53
|
+
/** Public slugs that differ from the registry's (strategy.ts `estate.slugs`, 3.14.0): public slug → registry slug. */
|
|
54
|
+
export interface PathAliases {
|
|
55
|
+
readonly regions: ReadonlyMap<string, string>;
|
|
56
|
+
readonly suburbs: ReadonlyMap<string, string>;
|
|
57
|
+
}
|
|
53
58
|
/**
|
|
54
59
|
* The place a path names: its last segment, or the end of its last segment after a hyphen (`/tree-removal-ryde`),
|
|
55
|
-
* when that is a registry suburb or region (`{region}-area` included)
|
|
60
|
+
* when that is a registry suburb or region (`{region}-area` included), or a public slug the estate plan renames
|
|
61
|
+
* (`ryde` for the region `ryde-area`, `ryde-suburb` for the suburb `ryde`), read first. The longest match wins.
|
|
56
62
|
*/
|
|
57
|
-
export declare function placeOfPath(path: string, geography: FullGeography): PathPlace | undefined;
|
|
63
|
+
export declare function placeOfPath(path: string, geography: FullGeography, aliases?: PathAliases): PathPlace | undefined;
|
|
58
64
|
/** A place's display name, for messages and for matching it in copy. */
|
|
59
65
|
export declare function placeName(slug: string, geography: FullGeography): string;
|
|
60
66
|
//# sourceMappingURL=geography.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geography.d.ts","sourceRoot":"","sources":["../../../../src/site-system/rules/full/geography.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAmB,KAAK,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAExG,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,wCAAwC;IACxC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAC3D,wCAAwC;IACxC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAC3D,wGAAwG;IACxG,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,mEAAmE;IACnE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,sGAAsG;IACtG,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;CAC/C;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,mBAAmB,GAAG;QAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAA;KAAE,CAAC,EAAE,CAAC;IACxF,QAAQ,CAAC,OAAO,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;IAClH,QAAQ,CAAC,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CACxC;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,aAAa,CAoC5E;AAaD,iEAAiE;AACjE,wBAAgB,iBAAiB,IAAI,OAAO,CAAC,aAAa,CAAC,CAmB1D;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACnC,kGAAkG;IAClG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED
|
|
1
|
+
{"version":3,"file":"geography.d.ts","sourceRoot":"","sources":["../../../../src/site-system/rules/full/geography.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAmB,KAAK,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAExG,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,wCAAwC;IACxC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAC3D,wCAAwC;IACxC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAC3D,wGAAwG;IACxG,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,mEAAmE;IACnE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,sGAAsG;IACtG,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;CAC/C;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,mBAAmB,GAAG;QAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAA;KAAE,CAAC,EAAE,CAAC;IACxF,QAAQ,CAAC,OAAO,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;IAClH,QAAQ,CAAC,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CACxC;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,aAAa,CAoC5E;AAaD,iEAAiE;AACjE,wBAAgB,iBAAiB,IAAI,OAAO,CAAC,aAAa,CAAC,CAmB1D;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACnC,kGAAkG;IAClG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,sHAAsH;AACtH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9C,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/C;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,SAAS,GAAG,SAAS,CAsBhH;AAMD,wEAAwE;AACxE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,GAAG,MAAM,CAExE"}
|
|
@@ -72,14 +72,18 @@ export function loadFullGeography() {
|
|
|
72
72
|
}
|
|
73
73
|
/**
|
|
74
74
|
* The place a path names: its last segment, or the end of its last segment after a hyphen (`/tree-removal-ryde`),
|
|
75
|
-
* when that is a registry suburb or region (`{region}-area` included)
|
|
75
|
+
* when that is a registry suburb or region (`{region}-area` included), or a public slug the estate plan renames
|
|
76
|
+
* (`ryde` for the region `ryde-area`, `ryde-suburb` for the suburb `ryde`), read first. The longest match wins.
|
|
76
77
|
*/
|
|
77
|
-
export function placeOfPath(path, geography) {
|
|
78
|
+
export function placeOfPath(path, geography, aliases) {
|
|
78
79
|
const segments = path.split("/");
|
|
79
80
|
const last = segments.pop() ?? "";
|
|
80
81
|
if (!last)
|
|
81
82
|
return undefined;
|
|
82
83
|
const parent = segments.join("/");
|
|
84
|
+
const alias = aliases?.suburbs.get(last) ?? aliases?.regions.get(last);
|
|
85
|
+
if (alias !== undefined)
|
|
86
|
+
return { slug: alias, kind: aliases?.suburbs.has(last) ? "suburb" : "region", stem: `${parent}/{place}` };
|
|
83
87
|
const kindOf = (slug) => {
|
|
84
88
|
if (geography.suburbs.has(slug))
|
|
85
89
|
return "suburb";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geography.js","sourceRoot":"","sources":["../../../../src/site-system/rules/full/geography.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The places the full tier reasons about: registry suburbs with their region and centre, and the regions. They come\n * from the site's installed site-core geography at run time (the conformance package compiles without site-core), or\n * from `defineFullGeography` in a test.\n */\nimport { createPlaceMask, type SuburbCentre, type SuburbCentreLookup } from \"../../../page-standard.js\";\n\nexport interface FullGeographySuburb {\n readonly slug: string;\n readonly name: string;\n /** The registry region the suburb belongs to. */\n readonly region: string;\n /** The suburb's council, when known. */\n readonly council?: string;\n}\n\nexport interface FullGeographyRegion {\n readonly slug: string;\n readonly name: string;\n /** Every name the region goes by (name, search name and alternates). */\n readonly names: readonly string[];\n}\n\nexport interface FullGeography {\n readonly centreOf: SuburbCentreLookup;\n readonly suburbs: ReadonlyMap<string, FullGeographySuburb>;\n /** Regions and sub-regions, by slug. */\n readonly regions: ReadonlyMap<string, FullGeographyRegion>;\n /** Masks every place name and postcode in lowercase text, so name-swapped copy compares as the same. */\n readonly mask: (text: string) => string;\n /** Lowercase place names (suburbs and regions) and their slugs. */\n readonly names: ReadonlyMap<string, string>;\n /** The slugs of the places a piece of copy names, longest name first (\"North Ryde\" before \"Ryde\"). */\n readonly placesIn: (text: string) => string[];\n}\n\nexport interface FullGeographyInput {\n readonly suburbs: readonly (FullGeographySuburb & { readonly centre?: SuburbCentre })[];\n readonly regions: readonly { readonly slug: string; readonly name: string; readonly names?: readonly string[] }[];\n readonly centreOf?: SuburbCentreLookup;\n}\n\nexport function defineFullGeography(input: FullGeographyInput): FullGeography {\n const suburbs = new Map<string, FullGeographySuburb>();\n const centres = new Map<string, SuburbCentre>();\n for (const suburb of input.suburbs) {\n if (suburbs.has(suburb.slug)) continue;\n suburbs.set(suburb.slug, { slug: suburb.slug, name: suburb.name, region: suburb.region, ...(suburb.council ? { council: suburb.council } : {}) });\n if (suburb.centre) centres.set(suburb.slug, suburb.centre);\n }\n const regions = new Map<string, FullGeographyRegion>();\n for (const region of input.regions) {\n if (!regions.has(region.slug)) regions.set(region.slug, { slug: region.slug, name: region.name, names: [...new Set([region.name, ...(region.names ?? [])])] });\n }\n const names = new Map<string, string>();\n for (const suburb of suburbs.values()) names.set(suburb.name.toLowerCase(), suburb.slug);\n for (const region of regions.values()) for (const name of region.names) if (!names.has(name.toLowerCase())) names.set(name.toLowerCase(), region.slug);\n const alternation = [...names.keys()]\n .filter((name) => name.length >= 3)\n .sort((left, right) => right.length - left.length)\n .map((name) => name.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\").replace(/\\s+/g, \"\\\\s+\"));\n const pattern = alternation.length > 0 ? new RegExp(`\\\\b(?:${alternation.join(\"|\")})\\\\b`, \"gi\") : null;\n return {\n centreOf: input.centreOf ?? ((slug) => centres.get(slug)),\n suburbs,\n regions,\n mask: createPlaceMask([...names.keys()]),\n names,\n placesIn: (text) => {\n if (!pattern) return [];\n const found = new Set<string>();\n for (const match of text.matchAll(pattern)) {\n const slug = names.get(match[0].toLowerCase().replace(/\\s+/g, \" \"));\n if (slug) found.add(slug);\n }\n return [...found];\n },\n };\n}\n\ninterface RegistryLike {\n suburbs: readonly { slug: string; name: string; regionSlug: string; councilSlug: string }[];\n nonSuburbLocalities: readonly { slug: string; name: string; regionSlug: string; councilSlug: string }[];\n regions: readonly { slug: string; name: string; seoName: string; alternateNames?: readonly string[] }[];\n subRegions: readonly { slug: string; name: string }[];\n}\n\n// A variable specifier, so the package compiles without site-core; it resolves to the site's installed copy.\nconst GEOGRAPHY_MODULE: string = \"@brandlab-digital/site-core/geography\";\nlet loaded: Promise<FullGeography> | undefined;\n\n/** The site's installed site-core geography (3.4.0 or later). */\nexport function loadFullGeography(): Promise<FullGeography> {\n loaded ??= (import(GEOGRAPHY_MODULE) as Promise<{\n getSuburbCentre?: SuburbCentreLookup;\n sydneyGeography: RegistryLike;\n centralCoastGeography: RegistryLike;\n }>).then((module) => {\n if (typeof module.getSuburbCentre !== \"function\") throw new Error(\"the installed site-core geography has no suburb centres (3.4.0 or later is needed)\");\n const registries = [module.sydneyGeography, module.centralCoastGeography];\n return defineFullGeography({\n suburbs: registries.flatMap((registry) =>\n [...registry.suburbs, ...registry.nonSuburbLocalities].map((place) => ({ slug: place.slug, name: place.name, region: place.regionSlug, council: place.councilSlug }))),\n regions: registries.flatMap((registry) => [\n ...registry.regions.map((region) => ({ slug: region.slug, name: region.name, names: [region.seoName, ...(region.alternateNames ?? [])] })),\n ...registry.subRegions.map((region) => ({ slug: region.slug, name: region.name })),\n ]),\n centreOf: module.getSuburbCentre,\n });\n });\n return loaded;\n}\n\nexport interface PathPlace {\n readonly slug: string;\n readonly kind: \"suburb\" | \"region\";\n /** The path with the place replaced by `{place}`: pages sharing a stem are one family's pages. */\n readonly stem: string;\n}\n\n/**\n * The place a path names: its last segment, or the end of its last segment after a hyphen (`/tree-removal-ryde`),\n * when that is a registry suburb or region (`{region}-area` included). The longest match wins.\n */\nexport function placeOfPath(path: string, geography: FullGeography): PathPlace | undefined {\n const segments = path.split(\"/\");\n const last = segments.pop() ?? \"\";\n if (!last) return undefined;\n const parent = segments.join(\"/\");\n const kindOf = (slug: string): PathPlace[\"kind\"] | undefined => {\n if (geography.suburbs.has(slug)) return \"suburb\";\n if (geography.regions.has(slug)) return \"region\";\n if (slug.endsWith(\"-area\") && geography.regions.has(slug.slice(0, -5))) return \"region\";\n return undefined;\n };\n const whole = kindOf(last);\n if (whole) return { slug: regionSlug(last, geography), kind: whole, stem: `${parent}/{place}` };\n const parts = last.split(\"-\");\n for (let start = 1; start < parts.length; start += 1) {\n const slug = parts.slice(start).join(\"-\");\n const kind = kindOf(slug);\n if (kind) return { slug: regionSlug(slug, geography), kind, stem: `${parent}/${parts.slice(0, start).join(\"-\")}-{place}` };\n }\n return undefined;\n}\n\nfunction regionSlug(slug: string, geography: FullGeography): string {\n return !geography.suburbs.has(slug) && !geography.regions.has(slug) && slug.endsWith(\"-area\") ? slug.slice(0, -5) : slug;\n}\n\n/** A place's display name, for messages and for matching it in copy. */\nexport function placeName(slug: string, geography: FullGeography): string {\n return geography.suburbs.get(slug)?.name ?? geography.regions.get(slug)?.name ?? slug;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"geography.js","sourceRoot":"","sources":["../../../../src/site-system/rules/full/geography.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The places the full tier reasons about: registry suburbs with their region and centre, and the regions. They come\n * from the site's installed site-core geography at run time (the conformance package compiles without site-core), or\n * from `defineFullGeography` in a test.\n */\nimport { createPlaceMask, type SuburbCentre, type SuburbCentreLookup } from \"../../../page-standard.js\";\n\nexport interface FullGeographySuburb {\n readonly slug: string;\n readonly name: string;\n /** The registry region the suburb belongs to. */\n readonly region: string;\n /** The suburb's council, when known. */\n readonly council?: string;\n}\n\nexport interface FullGeographyRegion {\n readonly slug: string;\n readonly name: string;\n /** Every name the region goes by (name, search name and alternates). */\n readonly names: readonly string[];\n}\n\nexport interface FullGeography {\n readonly centreOf: SuburbCentreLookup;\n readonly suburbs: ReadonlyMap<string, FullGeographySuburb>;\n /** Regions and sub-regions, by slug. */\n readonly regions: ReadonlyMap<string, FullGeographyRegion>;\n /** Masks every place name and postcode in lowercase text, so name-swapped copy compares as the same. */\n readonly mask: (text: string) => string;\n /** Lowercase place names (suburbs and regions) and their slugs. */\n readonly names: ReadonlyMap<string, string>;\n /** The slugs of the places a piece of copy names, longest name first (\"North Ryde\" before \"Ryde\"). */\n readonly placesIn: (text: string) => string[];\n}\n\nexport interface FullGeographyInput {\n readonly suburbs: readonly (FullGeographySuburb & { readonly centre?: SuburbCentre })[];\n readonly regions: readonly { readonly slug: string; readonly name: string; readonly names?: readonly string[] }[];\n readonly centreOf?: SuburbCentreLookup;\n}\n\nexport function defineFullGeography(input: FullGeographyInput): FullGeography {\n const suburbs = new Map<string, FullGeographySuburb>();\n const centres = new Map<string, SuburbCentre>();\n for (const suburb of input.suburbs) {\n if (suburbs.has(suburb.slug)) continue;\n suburbs.set(suburb.slug, { slug: suburb.slug, name: suburb.name, region: suburb.region, ...(suburb.council ? { council: suburb.council } : {}) });\n if (suburb.centre) centres.set(suburb.slug, suburb.centre);\n }\n const regions = new Map<string, FullGeographyRegion>();\n for (const region of input.regions) {\n if (!regions.has(region.slug)) regions.set(region.slug, { slug: region.slug, name: region.name, names: [...new Set([region.name, ...(region.names ?? [])])] });\n }\n const names = new Map<string, string>();\n for (const suburb of suburbs.values()) names.set(suburb.name.toLowerCase(), suburb.slug);\n for (const region of regions.values()) for (const name of region.names) if (!names.has(name.toLowerCase())) names.set(name.toLowerCase(), region.slug);\n const alternation = [...names.keys()]\n .filter((name) => name.length >= 3)\n .sort((left, right) => right.length - left.length)\n .map((name) => name.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\").replace(/\\s+/g, \"\\\\s+\"));\n const pattern = alternation.length > 0 ? new RegExp(`\\\\b(?:${alternation.join(\"|\")})\\\\b`, \"gi\") : null;\n return {\n centreOf: input.centreOf ?? ((slug) => centres.get(slug)),\n suburbs,\n regions,\n mask: createPlaceMask([...names.keys()]),\n names,\n placesIn: (text) => {\n if (!pattern) return [];\n const found = new Set<string>();\n for (const match of text.matchAll(pattern)) {\n const slug = names.get(match[0].toLowerCase().replace(/\\s+/g, \" \"));\n if (slug) found.add(slug);\n }\n return [...found];\n },\n };\n}\n\ninterface RegistryLike {\n suburbs: readonly { slug: string; name: string; regionSlug: string; councilSlug: string }[];\n nonSuburbLocalities: readonly { slug: string; name: string; regionSlug: string; councilSlug: string }[];\n regions: readonly { slug: string; name: string; seoName: string; alternateNames?: readonly string[] }[];\n subRegions: readonly { slug: string; name: string }[];\n}\n\n// A variable specifier, so the package compiles without site-core; it resolves to the site's installed copy.\nconst GEOGRAPHY_MODULE: string = \"@brandlab-digital/site-core/geography\";\nlet loaded: Promise<FullGeography> | undefined;\n\n/** The site's installed site-core geography (3.4.0 or later). */\nexport function loadFullGeography(): Promise<FullGeography> {\n loaded ??= (import(GEOGRAPHY_MODULE) as Promise<{\n getSuburbCentre?: SuburbCentreLookup;\n sydneyGeography: RegistryLike;\n centralCoastGeography: RegistryLike;\n }>).then((module) => {\n if (typeof module.getSuburbCentre !== \"function\") throw new Error(\"the installed site-core geography has no suburb centres (3.4.0 or later is needed)\");\n const registries = [module.sydneyGeography, module.centralCoastGeography];\n return defineFullGeography({\n suburbs: registries.flatMap((registry) =>\n [...registry.suburbs, ...registry.nonSuburbLocalities].map((place) => ({ slug: place.slug, name: place.name, region: place.regionSlug, council: place.councilSlug }))),\n regions: registries.flatMap((registry) => [\n ...registry.regions.map((region) => ({ slug: region.slug, name: region.name, names: [region.seoName, ...(region.alternateNames ?? [])] })),\n ...registry.subRegions.map((region) => ({ slug: region.slug, name: region.name })),\n ]),\n centreOf: module.getSuburbCentre,\n });\n });\n return loaded;\n}\n\nexport interface PathPlace {\n readonly slug: string;\n readonly kind: \"suburb\" | \"region\";\n /** The path with the place replaced by `{place}`: pages sharing a stem are one family's pages. */\n readonly stem: string;\n}\n\n/** Public slugs that differ from the registry's (strategy.ts `estate.slugs`, 3.14.0): public slug → registry slug. */\nexport interface PathAliases {\n readonly regions: ReadonlyMap<string, string>;\n readonly suburbs: ReadonlyMap<string, string>;\n}\n\n/**\n * The place a path names: its last segment, or the end of its last segment after a hyphen (`/tree-removal-ryde`),\n * when that is a registry suburb or region (`{region}-area` included), or a public slug the estate plan renames\n * (`ryde` for the region `ryde-area`, `ryde-suburb` for the suburb `ryde`), read first. The longest match wins.\n */\nexport function placeOfPath(path: string, geography: FullGeography, aliases?: PathAliases): PathPlace | undefined {\n const segments = path.split(\"/\");\n const last = segments.pop() ?? \"\";\n if (!last) return undefined;\n const parent = segments.join(\"/\");\n const alias = aliases?.suburbs.get(last) ?? aliases?.regions.get(last);\n if (alias !== undefined) return { slug: alias, kind: aliases?.suburbs.has(last) ? \"suburb\" : \"region\", stem: `${parent}/{place}` };\n const kindOf = (slug: string): PathPlace[\"kind\"] | undefined => {\n if (geography.suburbs.has(slug)) return \"suburb\";\n if (geography.regions.has(slug)) return \"region\";\n if (slug.endsWith(\"-area\") && geography.regions.has(slug.slice(0, -5))) return \"region\";\n return undefined;\n };\n const whole = kindOf(last);\n if (whole) return { slug: regionSlug(last, geography), kind: whole, stem: `${parent}/{place}` };\n const parts = last.split(\"-\");\n for (let start = 1; start < parts.length; start += 1) {\n const slug = parts.slice(start).join(\"-\");\n const kind = kindOf(slug);\n if (kind) return { slug: regionSlug(slug, geography), kind, stem: `${parent}/${parts.slice(0, start).join(\"-\")}-{place}` };\n }\n return undefined;\n}\n\nfunction regionSlug(slug: string, geography: FullGeography): string {\n return !geography.suburbs.has(slug) && !geography.regions.has(slug) && slug.endsWith(\"-area\") ? slug.slice(0, -5) : slug;\n}\n\n/** A place's display name, for messages and for matching it in copy. */\nexport function placeName(slug: string, geography: FullGeography): string {\n return geography.suburbs.get(slug)?.name ?? geography.regions.get(slug)?.name ?? slug;\n}\n"]}
|