@brandlab-digital/conformance 3.14.0 → 3.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -3
- package/dist/current-release.js +5 -5
- package/dist/current-release.js.map +1 -1
- package/dist/engineering.d.ts.map +1 -1
- package/dist/engineering.js +18 -2
- package/dist/engineering.js.map +1 -1
- package/dist/estate-snapshot.d.ts +54 -0
- package/dist/estate-snapshot.d.ts.map +1 -0
- package/dist/estate-snapshot.js +164 -0
- package/dist/estate-snapshot.js.map +1 -0
- package/dist/estate.d.ts +10 -0
- package/dist/estate.d.ts.map +1 -1
- package/dist/estate.js +36 -16
- package/dist/estate.js.map +1 -1
- package/dist/media-snapshot.d.ts +53 -0
- package/dist/media-snapshot.d.ts.map +1 -0
- package/dist/media-snapshot.js +66 -0
- package/dist/media-snapshot.js.map +1 -0
- package/dist/site-system/checks.d.ts +2 -2
- package/dist/site-system/checks.js +2 -2
- package/dist/site-system/checks.js.map +1 -1
- package/dist/site-system/config.d.ts +13 -0
- package/dist/site-system/config.d.ts.map +1 -1
- package/dist/site-system/config.js +30 -1
- package/dist/site-system/config.js.map +1 -1
- package/dist/site-system/index.d.ts +1 -1
- package/dist/site-system/index.d.ts.map +1 -1
- package/dist/site-system/index.js +1 -1
- package/dist/site-system/index.js.map +1 -1
- package/dist/site-system/journeys/conversion.d.ts.map +1 -1
- package/dist/site-system/journeys/conversion.js +15 -2
- package/dist/site-system/journeys/conversion.js.map +1 -1
- package/dist/site-system/journeys/menu.d.ts.map +1 -1
- package/dist/site-system/journeys/menu.js +24 -1
- package/dist/site-system/journeys/menu.js.map +1 -1
- package/dist/site-system/journeys/page-helpers.d.ts.map +1 -1
- package/dist/site-system/journeys/page-helpers.js +1 -1
- package/dist/site-system/journeys/page-helpers.js.map +1 -1
- package/dist/site-system/journeys/plan.d.ts +13 -3
- package/dist/site-system/journeys/plan.d.ts.map +1 -1
- package/dist/site-system/journeys/plan.js +12 -2
- package/dist/site-system/journeys/plan.js.map +1 -1
- package/dist/site-system/journeys/shell.d.ts +1 -1
- package/dist/site-system/journeys/shell.js +2 -2
- package/dist/site-system/journeys/shell.js.map +1 -1
- package/dist/site-system/report.d.ts.map +1 -1
- package/dist/site-system/report.js +24 -4
- package/dist/site-system/report.js.map +1 -1
- package/dist/site-system/rules/form/c7-thank-you.d.ts +7 -1
- package/dist/site-system/rules/form/c7-thank-you.d.ts.map +1 -1
- package/dist/site-system/rules/form/c7-thank-you.js +26 -3
- package/dist/site-system/rules/form/c7-thank-you.js.map +1 -1
- package/dist/site-system/rules/form/index.d.ts.map +1 -1
- package/dist/site-system/rules/form/index.js +11 -1
- package/dist/site-system/rules/form/index.js.map +1 -1
- package/dist/site-system/rules/full/common.d.ts +2 -0
- package/dist/site-system/rules/full/common.d.ts.map +1 -1
- package/dist/site-system/rules/full/common.js.map +1 -1
- package/dist/site-system/rules/full/estate.d.ts +10 -2
- package/dist/site-system/rules/full/estate.d.ts.map +1 -1
- package/dist/site-system/rules/full/estate.js +35 -5
- package/dist/site-system/rules/full/estate.js.map +1 -1
- package/dist/site-system/rules/full/geography.d.ts +7 -0
- package/dist/site-system/rules/full/geography.d.ts.map +1 -1
- package/dist/site-system/rules/full/geography.js +9 -0
- package/dist/site-system/rules/full/geography.js.map +1 -1
- package/dist/site-system/rules/full/index.d.ts +2 -1
- package/dist/site-system/rules/full/index.d.ts.map +1 -1
- package/dist/site-system/rules/full/index.js +5 -1
- package/dist/site-system/rules/full/index.js.map +1 -1
- package/dist/site-system/rules/full/l10-location-copy.d.ts +1 -1
- package/dist/site-system/rules/full/l10-location-copy.d.ts.map +1 -1
- package/dist/site-system/rules/full/l10-location-copy.js +5 -2
- package/dist/site-system/rules/full/l10-location-copy.js.map +1 -1
- package/dist/site-system/rules/full/l3-neighbours.d.ts +3 -2
- package/dist/site-system/rules/full/l3-neighbours.d.ts.map +1 -1
- package/dist/site-system/rules/full/l3-neighbours.js +4 -1
- package/dist/site-system/rules/full/l3-neighbours.js.map +1 -1
- package/dist/site-system/rules/full/l4-local-copy.d.ts +2 -1
- package/dist/site-system/rules/full/l4-local-copy.d.ts.map +1 -1
- package/dist/site-system/rules/full/l4-local-copy.js +8 -3
- package/dist/site-system/rules/full/l4-local-copy.js.map +1 -1
- package/dist/site-system/rules/full/l9-data-contract.js +2 -2
- package/dist/site-system/rules/full/l9-data-contract.js.map +1 -1
- package/dist/site-system/rules/full/links.d.ts +3 -1
- package/dist/site-system/rules/full/links.d.ts.map +1 -1
- package/dist/site-system/rules/full/links.js +15 -5
- package/dist/site-system/rules/full/links.js.map +1 -1
- package/dist/site-system/rules/full/route-kinds.d.ts +15 -0
- package/dist/site-system/rules/full/route-kinds.d.ts.map +1 -0
- package/dist/site-system/rules/full/route-kinds.js +52 -0
- package/dist/site-system/rules/full/route-kinds.js.map +1 -0
- package/dist/site-system/rules/full/strategy.d.ts +2 -0
- package/dist/site-system/rules/full/strategy.d.ts.map +1 -1
- package/dist/site-system/rules/full/strategy.js +86 -14
- 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 +9 -2
- package/dist/site-system/rules/sections/k2-skin-coverage.js.map +1 -1
- package/dist/site-system/rules/sections/t6-media-entries.d.ts.map +1 -1
- package/dist/site-system/rules/sections/t6-media-entries.js +69 -5
- package/dist/site-system/rules/sections/t6-media-entries.js.map +1 -1
- package/dist/site-system-e2e.d.ts +1 -1
- package/dist/site-system-e2e.d.ts.map +1 -1
- package/dist/site-system-e2e.js +17 -4
- package/dist/site-system-e2e.js.map +1 -1
- package/package.json +10 -2
|
@@ -114,7 +114,7 @@ export function readEstate(input) {
|
|
|
114
114
|
});
|
|
115
115
|
}
|
|
116
116
|
const byPath = new Map(pages.map((page) => [page.path, page]));
|
|
117
|
-
inferFamilies(pages, input.seeds ?? {});
|
|
117
|
+
inferFamilies(pages, input.seeds ?? {}, input.paths);
|
|
118
118
|
// Second pass: the copy of location pages found without a manifest.
|
|
119
119
|
for (const [index, page] of pages.entries()) {
|
|
120
120
|
if (!isLocationFamily(page.family) || page.copy)
|
|
@@ -250,7 +250,26 @@ function isGenerated(route) {
|
|
|
250
250
|
* Families for pages without a manifest: the sitemap file, then the family of the other pages of their dynamic route,
|
|
251
251
|
* the seeds (the representative service route), the family of their stem, then `/` as home.
|
|
252
252
|
*/
|
|
253
|
-
function inferFamilies(pages, seeds) {
|
|
253
|
+
function inferFamilies(pages, seeds, paths) {
|
|
254
|
+
// The estate plan's family paths come first: region and suburb pages can share a dynamic route with service pages
|
|
255
|
+
// (AA's /tree-services/[slug]), so the route alone cannot type them.
|
|
256
|
+
const parent = (template) => template.slice(0, template.lastIndexOf("/"));
|
|
257
|
+
const suburbParents = new Map([
|
|
258
|
+
...(paths?.serviceInSuburb ?? []).map((template) => [parent(template), "service-in-suburb"]),
|
|
259
|
+
...(paths?.suburb !== undefined ? [[parent(paths.suburb), "suburb"]] : []),
|
|
260
|
+
]);
|
|
261
|
+
const regionParents = new Set([paths?.region, ...(paths?.serviceInSuburb ?? [])].flatMap((template) => (template === undefined ? [] : [parent(template)])));
|
|
262
|
+
for (const page of pages) {
|
|
263
|
+
const at = parent(page.path);
|
|
264
|
+
// The whole last segment is the place: "/tree-services/tree-removal-sydney" is a service page, not a suburb page.
|
|
265
|
+
if (page.family !== undefined || !page.place || page.place.stem !== `${at}/{place}`)
|
|
266
|
+
continue;
|
|
267
|
+
const family = page.place.kind === "region" ? (regionParents.has(at) ? "region" : undefined) : suburbParents.get(at);
|
|
268
|
+
if (family) {
|
|
269
|
+
page.family = family;
|
|
270
|
+
page.familySource = "plan";
|
|
271
|
+
}
|
|
272
|
+
}
|
|
254
273
|
for (const page of pages) {
|
|
255
274
|
if (page.family !== undefined || !page.sitemapFile)
|
|
256
275
|
continue;
|
|
@@ -286,7 +305,8 @@ function inferFamilies(pages, seeds) {
|
|
|
286
305
|
for (const page of pages) {
|
|
287
306
|
if (page.family !== undefined || !page.srcRoute || !isGenerated(page.srcRoute))
|
|
288
307
|
continue;
|
|
289
|
-
|
|
308
|
+
// Only pages naming the same kind of place: a route that builds service pages and suburb pages types them apart.
|
|
309
|
+
const seeded = pages.find((other) => other.familySource === "route" && routeKey(other) === routeKey(page));
|
|
290
310
|
if (seeded) {
|
|
291
311
|
page.family = seeded.family;
|
|
292
312
|
page.familySource = "route";
|
|
@@ -372,9 +392,19 @@ function locationCopy(root) {
|
|
|
372
392
|
if (jobsSection) {
|
|
373
393
|
const cards = descendants(jobsSection).filter((element) => (element.tag === "li" || element.tag === "article") && !descendants(element).some((inner) => inner.tag === "li" || inner.tag === "article"));
|
|
374
394
|
const headings = new Set(descendants(jobsSection).filter((element) => /^h[1-6]$/.test(element.tag)).map((element) => textOf(element)));
|
|
395
|
+
// The job's place is structured data on the card (NearbyJobs renders `data-suburb`), so its outcome text is never
|
|
396
|
+
// read for place names when the card says where the job was.
|
|
397
|
+
const placeOf = (card) => {
|
|
398
|
+
const carrier = [card, ...descendants(card)].find((element) => attr(element, "data-suburb"));
|
|
399
|
+
return carrier ? attr(carrier, "data-suburb").trim() : undefined;
|
|
400
|
+
};
|
|
375
401
|
jobs = cards.length > 0
|
|
376
|
-
? cards.
|
|
377
|
-
|
|
402
|
+
? cards.flatMap((card) => {
|
|
403
|
+
const text = textOf(card, true);
|
|
404
|
+
const place = placeOf(card);
|
|
405
|
+
return text ? [place ? { text, place } : { text }] : [];
|
|
406
|
+
})
|
|
407
|
+
: readableLines(jobsSection).map((line) => line.text).filter((text) => !headings.has(text)).map((text) => ({ text }));
|
|
378
408
|
}
|
|
379
409
|
const pricesSection = sectionOf("price-guide");
|
|
380
410
|
const reviewsSection = sectionOf("reviews");
|
|
@@ -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 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"]}
|
|
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 type { SiteEstatePaths } from \"@brandlab-digital/site-core/strategy\";\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 LocationJobCard[] | 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\n/** A nearby-job card: its text, and the job's suburb slug from the card's `data-suburb` (NearbyJobs) when it carries one. */\nexport interface LocationJobCard {\n readonly text: string;\n readonly place?: string;\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\" | \"plan\" | \"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 /** The estate plan's family paths (3.14.0): they type region, suburb and service-in-suburb pages without a manifest. */\n readonly paths?: SiteEstatePaths;\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 ?? {}, input.paths);\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>>, paths: SiteEstatePaths | undefined): void {\n // The estate plan's family paths come first: region and suburb pages can share a dynamic route with service pages\n // (AA's /tree-services/[slug]), so the route alone cannot type them.\n const parent = (template: string) => template.slice(0, template.lastIndexOf(\"/\"));\n const suburbParents = new Map<string, string>([\n ...(paths?.serviceInSuburb ?? []).map((template) => [parent(template), \"service-in-suburb\"] as const),\n ...(paths?.suburb !== undefined ? [[parent(paths.suburb), \"suburb\"] as const] : []),\n ]);\n const regionParents = new Set([paths?.region, ...(paths?.serviceInSuburb ?? [])].flatMap((template) => (template === undefined ? [] : [parent(template)])));\n for (const page of pages) {\n const at = parent(page.path);\n // The whole last segment is the place: \"/tree-services/tree-removal-sydney\" is a service page, not a suburb page.\n if (page.family !== undefined || !page.place || page.place.stem !== `${at}/{place}`) continue;\n const family = page.place.kind === \"region\" ? (regionParents.has(at) ? \"region\" : undefined) : suburbParents.get(at);\n if (family) {\n page.family = family;\n page.familySource = \"plan\";\n }\n }\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 // Only pages naming the same kind of place: a route that builds service pages and suburb pages types them apart.\n const seeded = pages.find((other) => other.familySource === \"route\" && routeKey(other) === routeKey(page));\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: LocationJobCard[] | 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 // The job's place is structured data on the card (NearbyJobs renders `data-suburb`), so its outcome text is never\n // read for place names when the card says where the job was.\n const placeOf = (card: HtmlElement) => {\n const carrier = [card, ...descendants(card)].find((element) => attr(element, \"data-suburb\"));\n return carrier ? attr(carrier, \"data-suburb\")!.trim() : undefined;\n };\n jobs = cards.length > 0\n ? cards.flatMap((card) => {\n const text = textOf(card, true);\n const place = placeOf(card);\n return text ? [place ? { text, place } : { text }] : [];\n })\n : readableLines(jobsSection).map((line) => line.text).filter((text) => !headings.has(text)).map((text) => ({ 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"]}
|
|
@@ -62,5 +62,12 @@ export interface PathAliases {
|
|
|
62
62
|
*/
|
|
63
63
|
export declare function placeOfPath(path: string, geography: FullGeography, aliases?: PathAliases): PathPlace | undefined;
|
|
64
64
|
/** A place's display name, for messages and for matching it in copy. */
|
|
65
|
+
/**
|
|
66
|
+
* Tree and plant names that start with a place name ("Sydney blue gum", "Port Jackson fig"). Masked before a job's
|
|
67
|
+
* free text is read for places, so a species is never taken for the suburb the job was in.
|
|
68
|
+
*/
|
|
69
|
+
export declare const PLACE_COMPOUND_NAMES: RegExp;
|
|
70
|
+
/** The text with place-named species masked, for reading the places a job's free text names. */
|
|
71
|
+
export declare function withoutCompoundNames(text: string): string;
|
|
65
72
|
export declare function placeName(slug: string, geography: FullGeography): string;
|
|
66
73
|
//# 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,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"}
|
|
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;;;GAGG;AACH,eAAO,MAAM,oBAAoB,QACsG,CAAC;AAExI,gGAAgG;AAChG,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,GAAG,MAAM,CAExE"}
|
|
@@ -109,6 +109,15 @@ function regionSlug(slug, geography) {
|
|
|
109
109
|
return !geography.suburbs.has(slug) && !geography.regions.has(slug) && slug.endsWith("-area") ? slug.slice(0, -5) : slug;
|
|
110
110
|
}
|
|
111
111
|
/** A place's display name, for messages and for matching it in copy. */
|
|
112
|
+
/**
|
|
113
|
+
* Tree and plant names that start with a place name ("Sydney blue gum", "Port Jackson fig"). Masked before a job's
|
|
114
|
+
* free text is read for places, so a species is never taken for the suburb the job was in.
|
|
115
|
+
*/
|
|
116
|
+
export const PLACE_COMPOUND_NAMES = /\b(?:sydney\s+(?:blue|red)\s+gums?|sydney\s+peppermints?|sydney\s+golden\s+wattles?|port\s+jackson\s+(?:figs?|pines?|mallees?))\b/gi;
|
|
117
|
+
/** The text with place-named species masked, for reading the places a job's free text names. */
|
|
118
|
+
export function withoutCompoundNames(text) {
|
|
119
|
+
return text.replace(PLACE_COMPOUND_NAMES, (match) => " ".repeat(match.length));
|
|
120
|
+
}
|
|
112
121
|
export function placeName(slug, geography) {
|
|
113
122
|
return geography.suburbs.get(slug)?.name ?? geography.regions.get(slug)?.name ?? slug;
|
|
114
123
|
}
|
|
@@ -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/** 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"]}
|
|
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. */\n/**\n * Tree and plant names that start with a place name (\"Sydney blue gum\", \"Port Jackson fig\"). Masked before a job's\n * free text is read for places, so a species is never taken for the suburb the job was in.\n */\nexport const PLACE_COMPOUND_NAMES =\n /\\b(?:sydney\\s+(?:blue|red)\\s+gums?|sydney\\s+peppermints?|sydney\\s+golden\\s+wattles?|port\\s+jackson\\s+(?:figs?|pines?|mallees?))\\b/gi;\n\n/** The text with place-named species masked, for reading the places a job's free text names. */\nexport function withoutCompoundNames(text: string): string {\n return text.replace(PLACE_COMPOUND_NAMES, (match) => \" \".repeat(match.length));\n}\n\nexport function placeName(slug: string, geography: FullGeography): string {\n return geography.suburbs.get(slug)?.name ?? geography.regions.get(slug)?.name ?? slug;\n}\n"]}
|
|
@@ -11,9 +11,10 @@ export { L3_MAX_LIST, L3_MIN_LIST, L3_TOLERANCE_KM } from "./l3-neighbours.js";
|
|
|
11
11
|
export { L4_MIN_ROTATION_PAGES, L4_MIN_TEMPLATE_WORDS } from "./l4-local-copy.js";
|
|
12
12
|
export { yearStamp } from "./l10-location-copy.js";
|
|
13
13
|
export { L6_MIN_INBOUND, L6_MIN_PAGE_TYPES, L7_MAX_DEPTH, clickDepths } from "./links.js";
|
|
14
|
+
export { CATALOGUE_HUB_FAMILIES, ROUTE_CATALOGUE_FILE, linkingPageType, readRouteCatalogueKinds } from "./route-kinds.js";
|
|
14
15
|
export { sydneyDay } from "./loc-index.js";
|
|
15
16
|
export { W3_FAMILIES, W3_MIN_REVALIDATE_SECONDS, refreshInterval } from "./w3-refresh.js";
|
|
16
|
-
export { FULL_STRATEGY_FILE, WAVE_MAX_GAP_DAYS, WAVE_MIN_GAP_DAYS, matchesWaveRoute, normalisePhrase, readFullStrategy, waveScheduleProblems } from "./strategy.js";
|
|
17
|
+
export { ESTATE_PLAN_SNAPSHOT_FILE, FULL_STRATEGY_FILE, WAVE_MAX_GAP_DAYS, WAVE_MIN_GAP_DAYS, matchesWaveRoute, normalisePhrase, readFullStrategy, waveScheduleProblems } from "./strategy.js";
|
|
17
18
|
/** The full-tier checks this module runs, in the order their findings are returned. */
|
|
18
19
|
export declare const FULL_TIER_CHECK_IDS: readonly ["K12", "K12-slots", "E1-pattern", "E5", "E10", "L3", "L4", "L6", "L7", "L8", "L9", "L10", "S4", "LOC-INDEX", "W3"];
|
|
19
20
|
export interface FullTierRuleOptions {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/site-system/rules/full/index.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAqB,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C,OAAO,EAAqB,KAAK,aAAa,EAAoB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/site-system/rules/full/index.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAqB,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C,OAAO,EAAqB,KAAK,aAAa,EAAoB,MAAM,gBAAgB,CAAC;AAczF,OAAO,EAAE,oBAAoB,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,KAAK,MAAM,EAAE,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAC7G,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,WAAW,EAAE,KAAK,aAAa,EAAE,KAAK,kBAAkB,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACpJ,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC1F,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC1H,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC1F,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,eAAe,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAE/L,uFAAuF;AACvF,eAAO,MAAM,mBAAmB,8HAAsK,CAAC;AAEvM,MAAM,WAAW,mBAAmB;IAClC,oDAAoD;IACpD,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC;IACrB,qFAAqF;IACrF,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,oGAAoG;IACpG,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IAC1C,uGAAuG;IACvG,QAAQ,CAAC,YAAY,CAAC,EAAE,WAAW,CAAC,cAAc,CAAC,CAAC;CACrD;AA8CD;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,uBAAuB,EAC9B,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,SAAS,iBAAiB,EAAE,CAAC,CAsDvC"}
|
|
@@ -19,6 +19,7 @@ import { checkL4 } from "./l4-local-copy.js";
|
|
|
19
19
|
import { checkL9 } from "./l9-data-contract.js";
|
|
20
20
|
import { checkL10 } from "./l10-location-copy.js";
|
|
21
21
|
import { checkE5, checkL6, checkL7, checkL8, inboundLinks } from "./links.js";
|
|
22
|
+
import { readRouteCatalogueKinds } from "./route-kinds.js";
|
|
22
23
|
import { checkLocationIndexing, sydneyDay } from "./loc-index.js";
|
|
23
24
|
import { checkS4 } from "./s4-route-files.js";
|
|
24
25
|
import { readFullStrategy } from "./strategy.js";
|
|
@@ -32,9 +33,10 @@ export { L3_MAX_LIST, L3_MIN_LIST, L3_TOLERANCE_KM } from "./l3-neighbours.js";
|
|
|
32
33
|
export { L4_MIN_ROTATION_PAGES, L4_MIN_TEMPLATE_WORDS } from "./l4-local-copy.js";
|
|
33
34
|
export { yearStamp } from "./l10-location-copy.js";
|
|
34
35
|
export { L6_MIN_INBOUND, L6_MIN_PAGE_TYPES, L7_MAX_DEPTH, clickDepths } from "./links.js";
|
|
36
|
+
export { CATALOGUE_HUB_FAMILIES, ROUTE_CATALOGUE_FILE, linkingPageType, readRouteCatalogueKinds } from "./route-kinds.js";
|
|
35
37
|
export { sydneyDay } from "./loc-index.js";
|
|
36
38
|
export { W3_FAMILIES, W3_MIN_REVALIDATE_SECONDS, refreshInterval } from "./w3-refresh.js";
|
|
37
|
-
export { FULL_STRATEGY_FILE, WAVE_MAX_GAP_DAYS, WAVE_MIN_GAP_DAYS, matchesWaveRoute, normalisePhrase, readFullStrategy, waveScheduleProblems } from "./strategy.js";
|
|
39
|
+
export { ESTATE_PLAN_SNAPSHOT_FILE, FULL_STRATEGY_FILE, WAVE_MAX_GAP_DAYS, WAVE_MIN_GAP_DAYS, matchesWaveRoute, normalisePhrase, readFullStrategy, waveScheduleProblems } from "./strategy.js";
|
|
38
40
|
/** The full-tier checks this module runs, in the order their findings are returned. */
|
|
39
41
|
export const FULL_TIER_CHECK_IDS = ["K12", "K12-slots", "E1-pattern", "E5", "E10", "L3", "L4", "L6", "L7", "L8", "L9", "L10", "S4", "LOC-INDEX", "W3"];
|
|
40
42
|
// Variable specifiers, so the package compiles without site-core; they resolve to the site's installed copy.
|
|
@@ -110,6 +112,7 @@ export async function runFullTierRules(input, options = {}) {
|
|
|
110
112
|
geography,
|
|
111
113
|
...(settings.service ? { seeds: { [settings.service]: "service" } } : {}),
|
|
112
114
|
...(strategy.estate?.slugs ? { aliases: pathAliases(strategy.estate) } : {}),
|
|
115
|
+
...(strategy.estate?.paths ? { paths: strategy.estate.paths } : {}),
|
|
113
116
|
});
|
|
114
117
|
const context = {
|
|
115
118
|
estate,
|
|
@@ -117,6 +120,7 @@ export async function runFullTierRules(input, options = {}) {
|
|
|
117
120
|
geographyProblem,
|
|
118
121
|
strategy,
|
|
119
122
|
projectRoot: input.projectRoot,
|
|
123
|
+
catalogueKinds: readRouteCatalogueKinds(input.projectRoot),
|
|
120
124
|
refreshExceptions: settings.refreshExceptions,
|
|
121
125
|
today,
|
|
122
126
|
defaultOrder: options.defaultOrder ?? (await loadDefaultOrder()),
|