@brandlab-digital/conformance 3.17.1 → 3.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/current-release.js +5 -5
- package/dist/current-release.js.map +1 -1
- package/dist/site-system/checks.d.ts +6 -0
- package/dist/site-system/checks.d.ts.map +1 -1
- package/dist/site-system/checks.js +1 -0
- package/dist/site-system/checks.js.map +1 -1
- package/dist/site-system/journeys/grounds.d.ts +3 -0
- package/dist/site-system/journeys/grounds.d.ts.map +1 -0
- package/dist/site-system/journeys/grounds.js +29 -0
- package/dist/site-system/journeys/grounds.js.map +1 -0
- package/dist/site-system/journeys/page-helpers.d.ts +22 -0
- package/dist/site-system/journeys/page-helpers.d.ts.map +1 -1
- package/dist/site-system/journeys/page-helpers.js +81 -1
- package/dist/site-system/journeys/page-helpers.js.map +1 -1
- package/dist/site-system/journeys/plan.d.ts +8 -1
- package/dist/site-system/journeys/plan.d.ts.map +1 -1
- package/dist/site-system/journeys/plan.js +8 -1
- package/dist/site-system/journeys/plan.js.map +1 -1
- package/dist/site-system/rules/full/k12-manifests.d.ts +4 -1
- package/dist/site-system/rules/full/k12-manifests.d.ts.map +1 -1
- package/dist/site-system/rules/full/k12-manifests.js +12 -2
- package/dist/site-system/rules/full/k12-manifests.js.map +1 -1
- package/dist/site-system/rules/shell/budgets.d.ts.map +1 -1
- package/dist/site-system/rules/shell/budgets.js +7 -3
- package/dist/site-system/rules/shell/budgets.js.map +1 -1
- package/dist/site-system-e2e.d.ts.map +1 -1
- package/dist/site-system-e2e.js +3 -1
- package/dist/site-system-e2e.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page-helpers.js","sourceRoot":"","sources":["../../../src/site-system/journeys/page-helpers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Functions the site-system journeys run inside the page under test. Each one is self-contained: it uses DOM globals\n * and the other helpers in this file only, because `pageHelpersSource()` injects their source into every document\n * (as `window.__brandlabSiteSystem`, through Playwright's init script, which a Content Security Policy does not\n * block). The pure parts (colour, contrast, placement) are unit-tested in Node.\n */\n\n/**\n * The placements `phone_link_click` accepts: site-next's PHONE_CALL_PLACEMENTS (conformance cannot depend on\n * site-next; a test reads the site-next source and compares). Injected into the page with the helpers.\n */\nexport const SITE_SYSTEM_PHONE_PLACEMENTS: readonly string[] = Object.freeze(['header', 'footer', 'hero', 'cta', 'fab', 'contact', 'location', 'page', 'emergency']);\n\nexport type Rgba = [number, number, number, number];\n\n/** What `watchDisclosure` has seen, in `performance.now()` milliseconds. */\nexport interface DisclosureWatch {\n enter: number | null;\n leave: number | null;\n opened: number | null;\n closed: number | null;\n open: boolean;\n}\n\n/**\n * Whether an element is rendered: connected, with a box, not `visibility: hidden`, not fully transparent and not\n * inside a closed `<details>` (outside its summary). Chromium gives the content of a closed `<details>` a box, so\n * the box alone is not enough; `checkVisibility()` settles it where the browser has it.\n */\nexport function isRendered(element: Element | null | undefined): boolean {\n if (!element || !element.isConnected) return false;\n for (let details = element.closest('details:not([open])'); details; details = details.parentElement?.closest('details:not([open])') ?? null) {\n const summary = Array.from(details.children).find((child) => child.tagName === 'SUMMARY');\n if (!summary || !summary.contains(element)) return false;\n }\n if (typeof element.checkVisibility === 'function' && !element.checkVisibility({ checkOpacity: true, checkVisibilityCSS: true })) return false;\n const rect = element.getBoundingClientRect();\n if (rect.width <= 0 || rect.height <= 0) return false;\n if (getComputedStyle(element).visibility !== 'visible') return false;\n for (let node: Element | null = element; node; node = node.parentElement) {\n if (getComputedStyle(node).opacity === '0') return false;\n }\n return true;\n}\n\n/** A short, readable name for an element in a failure message. */\nexport function describeElement(element: Element): string {\n const tag = element.tagName.toLowerCase();\n const label = element.getAttribute('aria-label') ?? (element as HTMLElement).innerText ?? element.textContent ?? '';\n const text = label.replace(/\\s+/g, ' ').trim().slice(0, 40);\n const href = element.getAttribute('href');\n return `${tag}${text ? ` \"${text}\"` : ''}${href ? ` (${href})` : ''}`;\n}\n\n/** The accessible name, approximately: aria-label, aria-labelledby, the rendered text, then the title. */\nexport function accessibleName(element: Element): string {\n const label = element.getAttribute('aria-label');\n if (label && label.trim()) return label.trim();\n const labelledBy = element.getAttribute('aria-labelledby');\n if (labelledBy) {\n const text = labelledBy.split(/\\s+/).map((id) => document.getElementById(id)?.textContent ?? '').join(' ').trim();\n if (text) return text.replace(/\\s+/g, ' ');\n }\n const text = ((element as HTMLElement).innerText ?? element.textContent ?? '').replace(/\\s+/g, ' ').trim();\n return text || (element.getAttribute('title') ?? '').trim();\n}\n\n/**\n * Where a telephone link reports its tap, exactly as site-next's shared listener resolves it: its own valid\n * `data-phone-location`, then a `<header>` or `<footer>` ancestor, then the nearest ancestor with a valid value,\n * otherwise `page`. `invalid` is the nearest declared value when it is not an allowed placement (the listener then\n * reports the link somewhere else, silently).\n */\nexport function phonePlacement(link: Element): { placement: string; invalid: string | null } {\n const valid = (node: Element): string | undefined => {\n const value = node.getAttribute('data-phone-location')?.trim().toLowerCase();\n return value && SITE_SYSTEM_PHONE_PLACEMENTS.includes(value) ? value : undefined;\n };\n const nearest = link.closest('[data-phone-location]');\n const invalid = nearest && !valid(nearest) ? nearest.getAttribute('data-phone-location') : null;\n const own = valid(link);\n if (own) return { placement: own, invalid };\n if (link.closest('header')) return { placement: 'header', invalid };\n if (link.closest('footer')) return { placement: 'footer', invalid };\n for (let node = link.parentElement?.closest('[data-phone-location]') ?? null; node; node = node.parentElement?.closest('[data-phone-location]') ?? null) {\n const value = valid(node);\n if (value) return { placement: value, invalid };\n }\n return { placement: 'page', invalid };\n}\n\n/** Parse a computed colour. `rgb()`/`rgba()` directly; any other syntax (oklch, lab, color()) through a canvas pixel. */\nexport function parseColour(value: string): Rgba | null {\n const text = value.trim().toLowerCase();\n if (text === 'transparent') return [0, 0, 0, 0];\n const match = /^rgba?\\(([^)]+)\\)$/.exec(text);\n if (match) {\n const parts = match[1]!.split(/[\\s,/]+/).filter(Boolean);\n if (parts.length < 3) return null;\n const channel = (part: string) => (part.endsWith('%') ? (Number.parseFloat(part) / 100) * 255 : Number.parseFloat(part));\n const alphaPart = parts[3];\n const alpha = alphaPart === undefined ? 1 : alphaPart.endsWith('%') ? Number.parseFloat(alphaPart) / 100 : Number.parseFloat(alphaPart);\n const rgba: Rgba = [channel(parts[0]!), channel(parts[1]!), channel(parts[2]!), alpha];\n return rgba.every((part) => Number.isFinite(part)) ? rgba : null;\n }\n if (typeof document === 'undefined') return null;\n const canvas = document.createElement('canvas');\n canvas.width = 1;\n canvas.height = 1;\n const context = canvas.getContext('2d', { willReadFrequently: true });\n if (!context) return null;\n context.clearRect(0, 0, 1, 1);\n context.fillStyle = value;\n context.fillRect(0, 0, 1, 1);\n const [red = 0, green = 0, blue = 0, alpha = 0] = Array.from(context.getImageData(0, 0, 1, 1).data);\n return [red, green, blue, alpha / 255];\n}\n\n/** `top` painted over an opaque `bottom`. */\nexport function compositeColour(top: Rgba, bottom: Rgba): Rgba {\n const alpha = top[3];\n return [\n top[0] * alpha + bottom[0] * (1 - alpha),\n top[1] * alpha + bottom[1] * (1 - alpha),\n top[2] * alpha + bottom[2] * (1 - alpha),\n 1,\n ];\n}\n\n/** The WCAG contrast ratio of two opaque colours. */\nexport function contrastRatio(first: Rgba, second: Rgba): number {\n const luminance = (colour: Rgba) => {\n const [red, green, blue] = colour.slice(0, 3).map((channel) => {\n const value = channel / 255;\n return value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4;\n }) as [number, number, number];\n return 0.2126 * red + 0.7152 * green + 0.0722 * blue;\n };\n const [light, dark] = [luminance(first), luminance(second)].sort((left, right) => right - left) as [number, number];\n return (light + 0.05) / (dark + 0.05);\n}\n\n/**\n * The opaque colour behind an element, from its own and its ancestors' background colours over a white canvas.\n * `null` when a background image (a photo or gradient) is in the way: the contrast cannot be computed there.\n */\nexport function backgroundBehind(element: Element): Rgba | null {\n const layers: Rgba[] = [];\n for (let node: Element | null = element; node; node = node.parentElement) {\n const style = getComputedStyle(node);\n if (style.backgroundImage && style.backgroundImage !== 'none') return null;\n const colour = parseColour(style.backgroundColor);\n if (colour && colour[3] > 0) {\n layers.push(colour);\n if (colour[3] >= 1) break;\n }\n }\n return layers.reverse().reduce<Rgba>((bottom, top) => compositeColour(top, bottom), [255, 255, 255, 1]);\n}\n\n/**\n * Non-text contrast (WCAG 1.4.11) of icon-only controls inside `root`: a link or button with no visible text whose\n * icon is an SVG must reach 3:1 against what is behind it. Returns one line per failure; controls over a photo are\n * counted in `unmeasured`.\n */\nexport function iconContrastProblems(root: Element): { problems: string[]; checked: number; unmeasured: number } {\n const problems: string[] = [];\n let checked = 0;\n let unmeasured = 0;\n const paintOf = (svg: SVGElement): Rgba | null => {\n for (const shape of Array.from(svg.querySelectorAll('path, circle, rect, ellipse, line, polyline, polygon, text, use'))) {\n if (!isRendered(shape)) continue;\n const style = getComputedStyle(shape);\n for (const [paint, opacity] of [[style.fill, style.fillOpacity], [style.stroke, style.strokeOpacity]] as const) {\n if (!paint || paint === 'none' || paint.startsWith('url(')) continue;\n const colour = parseColour(paint);\n const alpha = colour ? colour[3] * Number(opacity || 1) * Number(style.opacity || 1) : 0;\n if (colour && alpha > 0) return [colour[0], colour[1], colour[2], alpha];\n }\n }\n return null;\n };\n for (const control of Array.from(root.querySelectorAll('a[href], button'))) {\n if (!isRendered(control)) continue;\n if (((control as HTMLElement).innerText ?? '').trim()) continue;\n const svg = control.querySelector('svg');\n if (!svg || !isRendered(svg)) continue;\n const paint = paintOf(svg);\n if (!paint) continue;\n const background = backgroundBehind(svg);\n if (!background) {\n unmeasured += 1;\n continue;\n }\n checked += 1;\n const ratio = contrastRatio(compositeColour(paint, background), background);\n if (ratio < 3) problems.push(`${describeElement(control)}: its icon is ${ratio.toFixed(2)}:1 against its background (needs 3:1)`);\n }\n return { problems, checked, unmeasured };\n}\n\n/**\n * The phone call bar: the shared `MobileCallBar`, or any fixed or sticky element along the bottom of the screen that\n * holds a visible telephone link (outside the header and dialogs). `null` when none is on screen.\n */\nexport function findCallBar(): Element | null {\n const tagged = Array.from(document.querySelectorAll('[data-bl=\"call-bar\"], [data-bl=\"callbar\"], [data-bl=\"mobile-call-bar\"]')).find(isRendered);\n if (tagged) return tagged;\n const height = window.innerHeight;\n for (const element of Array.from(document.body.querySelectorAll('*'))) {\n const position = getComputedStyle(element).position;\n if (position !== 'fixed' && position !== 'sticky') continue;\n if (element.closest('header, dialog, [role=\"dialog\"]')) continue;\n const rect = element.getBoundingClientRect();\n if (rect.height <= 0 || rect.bottom < height - 4 || rect.top < height / 2) continue;\n if (!isRendered(element)) continue;\n if (Array.from(element.querySelectorAll('a[href^=\"tel:\"]')).some(isRendered)) return element;\n }\n return null;\n}\n\n/** Visible quote actions in `root`: links or buttons named like the quote action, or the shared quote hooks. */\nexport function quoteActions(root: Element, name: { source: string; flags: string }): Element[] {\n const pattern = new RegExp(name.source, name.flags);\n return Array.from(root.querySelectorAll('a[href], button')).filter((element) => {\n if (!isRendered(element) || element.getAttribute('href')?.startsWith('tel:')) return false;\n if (element.matches('[data-bl=\"quote-button\"], [data-bl-cta^=\"quote\"], [data-lead-cta^=\"quote\"]')) return true;\n return pattern.test(accessibleName(element));\n });\n}\n\n/** The order of the first visible phone link and quote action in `root`. */\nexport function actionOrder(root: Element, name: { source: string; flags: string }): 'phone-first' | 'quote-first' | 'incomplete' {\n const phone = Array.from(root.querySelectorAll('a[href^=\"tel:\"]')).find(isRendered);\n const quote = quoteActions(root, name)[0];\n if (!phone || !quote) return 'incomplete';\n return phone.compareDocumentPosition(quote) & Node.DOCUMENT_POSITION_FOLLOWING ? 'phone-first' : 'quote-first';\n}\n\n/**\n * The hero: the shared hero section, else the smallest block around the page's visible H1 that holds a phone link\n * and a quote action, never above the H1's own section and never `<main>` (without a section, never a block holding\n * an H2). When none holds both, the H1's section (or its parent): its order then reads \"incomplete\".\n */\nexport function heroRegion(name: { source: string; flags: string }): Element | null {\n const heading = Array.from(document.querySelectorAll('h1')).find(isRendered);\n if (!heading) return null;\n const tagged = heading.closest('[data-bl-section=\"hero\"]');\n if (tagged) return tagged;\n const section = heading.closest('section');\n const fallback = section ?? heading.parentElement;\n for (let node = heading.parentElement; node && node !== document.body && node.tagName !== 'MAIN'; node = node.parentElement) {\n if (!section && node.querySelector('h2')) break;\n if (Array.from(node.querySelectorAll('a[href^=\"tel:\"]')).some(isRendered) && quoteActions(node, name).length > 0) return node;\n if (node === section) break;\n }\n return fallback && fallback.tagName !== 'MAIN' ? fallback : heading;\n}\n\n/** A point in the page that is not on an interactive element, a menu or anything in `avoid`. */\nexport function outsidePoint(avoid: Element[]): { x: number; y: number } | null {\n const interactive = 'a[href], button, input, select, textarea, label, summary, details, iframe, video, audio, [role=\"button\"], [role=\"link\"], [role=\"menuitem\"], [role=\"tab\"], [tabindex], [contenteditable=\"\"], [contenteditable=\"true\"]';\n for (let row = 9; row >= 3; row -= 1) {\n for (let column = 1; column <= 9; column += 1) {\n const x = Math.round((window.innerWidth * column) / 10);\n const y = Math.round((window.innerHeight * row) / 10);\n const element = document.elementFromPoint(x, y);\n if (!element || avoid.some((region) => region.contains(element))) continue;\n if (element.closest(interactive) || element.closest('header, nav, dialog, [role=\"dialog\"]')) continue;\n return { x, y };\n }\n }\n return null;\n}\n\n/** Tag an element so Playwright and axe can find it by `[data-brandlab-journey~=\"<name>\"]`. */\nexport function markElement(element: Element, name: string): void {\n const names = new Set((element.getAttribute('data-brandlab-journey') ?? '').split(/\\s+/).filter(Boolean));\n names.add(name);\n element.setAttribute('data-brandlab-journey', [...names].join(' '));\n}\n\n/**\n * Watch one disclosure: when the pointer enters and leaves its item (and panel), and when the panel it controls\n * becomes rendered or hidden, timed with `performance.now()`. Attribute and tree changes are sampled at once; style\n * changes without a DOM change (CSS `:hover`) every animation frame.\n */\nexport function watchDisclosure(trigger: Element, panelId: string): void {\n const item = trigger.closest('li') ?? trigger.parentElement ?? trigger;\n const panel = () => document.getElementById(panelId);\n const inside = (node: EventTarget | null) => node instanceof Node && (item.contains(node) || Boolean(panel()?.contains(node)));\n const state: DisclosureWatch = { enter: null, leave: null, opened: null, closed: null, open: isRendered(panel()) };\n const sample = () => {\n const open = isRendered(panel());\n if (open === state.open) return;\n state.open = open;\n if (open && state.opened === null) state.opened = performance.now();\n if (!open && state.closed === null) state.closed = performance.now();\n };\n const onOver = (event: Event) => {\n if (state.enter === null && inside(event.target)) state.enter = performance.now();\n };\n const onOut = (event: Event) => {\n if (state.leave === null && inside(event.target) && !inside((event as PointerEvent).relatedTarget)) state.leave = performance.now();\n };\n const observer = new MutationObserver(sample);\n observer.observe(document.documentElement, { attributes: true, childList: true, subtree: true });\n let frame = 0;\n const loop = () => {\n sample();\n frame = requestAnimationFrame(loop);\n };\n loop();\n document.addEventListener('pointerover', onOver, true);\n document.addEventListener('pointerout', onOut, true);\n const previous = (window as unknown as { __brandlabSiteSystemWatch?: { stop(): void } }).__brandlabSiteSystemWatch;\n previous?.stop();\n (window as unknown as { __brandlabSiteSystemWatch: unknown }).__brandlabSiteSystemWatch = {\n state,\n stop() {\n observer.disconnect();\n cancelAnimationFrame(frame);\n document.removeEventListener('pointerover', onOver, true);\n document.removeEventListener('pointerout', onOut, true);\n },\n };\n}\n\n/** The current state of `watchDisclosure`'s watch. */\nexport function watchState(): DisclosureWatch | null {\n const watch = (window as unknown as { __brandlabSiteSystemWatch?: { state: DisclosureWatch } }).__brandlabSiteSystemWatch;\n return watch ? { ...watch.state } : null;\n}\n\n/**\n * After a Tab press: is the focused element fully hidden under the sticky header or the call bar? Samples nine points\n * across the visible part of its box; it is hidden when the header or call bar is on top at every one. `repeat` is\n * true once focus comes back to an element it has already visited.\n */\nexport function focusStep(): { done: boolean; repeat: boolean; obscured: string | null; covered: 'header' | 'call bar' | null } {\n const element = document.activeElement;\n const store = window as unknown as { __brandlabSiteSystemFocus?: WeakSet<Element> };\n store.__brandlabSiteSystemFocus ??= new WeakSet<Element>();\n if (!element || element === document.body || element === document.documentElement) return { done: true, repeat: false, obscured: null, covered: null };\n const repeat = store.__brandlabSiteSystemFocus.has(element);\n store.__brandlabSiteSystemFocus.add(element);\n const header = document.querySelector('[data-brandlab-journey~=\"header\"]')\n ?? Array.from(document.querySelectorAll('[data-bl=\"header\"], header')).find((candidate) => isRendered(candidate) && !candidate.closest('main, article, section, aside, footer'))\n ?? null;\n const callBar = findCallBar();\n if (header?.contains(element) || callBar?.contains(element)) return { done: false, repeat, obscured: null, covered: null };\n const rect = element.getBoundingClientRect();\n const left = Math.max(rect.left, 0);\n const right = Math.min(rect.right, window.innerWidth);\n const top = Math.max(rect.top, 0);\n const bottom = Math.min(rect.bottom, window.innerHeight);\n if (right - left < 1 || bottom - top < 1) return { done: false, repeat, obscured: null, covered: null };\n let coveredBy: 'header' | 'call bar' | null = null;\n for (const fx of [0.15, 0.5, 0.85]) {\n for (const fy of [0.15, 0.5, 0.85]) {\n const hit = document.elementFromPoint(left + (right - left) * fx, top + (bottom - top) * fy);\n if (!hit || element.contains(hit)) return { done: false, repeat, obscured: null, covered: null };\n if (header?.contains(hit)) coveredBy ??= 'header';\n else if (callBar?.contains(hit)) coveredBy ??= 'call bar';\n else return { done: false, repeat, obscured: null, covered: null };\n }\n }\n return { done: false, repeat, obscured: describeElement(element), covered: coveredBy };\n}\n\n/**\n * `focusStep` one animation frame after the focus moved (capped at 50 ms, since a background page may not paint), so\n * a sticky bar that hides on its observer's next frame is measured after it moved, not mid-transition.\n */\nexport function focusStepAfterFrame(): Promise<ReturnType<typeof focusStep>> {\n return new Promise((resolve) => {\n let settled = false;\n const finish = () => {\n if (settled) return;\n settled = true;\n resolve(focusStep());\n };\n requestAnimationFrame(() => finish());\n setTimeout(finish, 50);\n });\n}\n\n/** Elements a Tab press can reach, roughly: enough to bound the K5 walk. */\nexport function tabbableCount(): number {\n const selector = 'a[href], button:not([disabled]), input:not([disabled]):not([type=\"hidden\"]), select:not([disabled]), textarea:not([disabled]), summary, iframe, [tabindex]:not([tabindex=\"-1\"])';\n return Array.from(document.querySelectorAll(selector)).filter(isRendered).length;\n}\n\nconst PAGE_HELPERS = {\n isRendered, describeElement, accessibleName, phonePlacement, parseColour, compositeColour, contrastRatio, backgroundBehind,\n iconContrastProblems, findCallBar, quoteActions, actionOrder, heroRegion, outsidePoint, markElement, watchDisclosure,\n watchState, focusStep, focusStepAfterFrame, tabbableCount,\n};\n\n/** `window.__brandlabSiteSystem` in a page the journeys opened. */\nexport type SiteSystemPageHelpers = typeof PAGE_HELPERS;\n\n/** The init script that defines `window.__brandlabSiteSystem` in every document of the page. */\nexport function pageHelpersSource(): string {\n const names = Object.keys(PAGE_HELPERS);\n return `(() => {\\nconst SITE_SYSTEM_PHONE_PLACEMENTS = ${JSON.stringify(SITE_SYSTEM_PHONE_PLACEMENTS)};\\n${Object.values(PAGE_HELPERS).map((helper) => helper.toString()).join('\\n')}\\nwindow.__brandlabSiteSystem = { ${names.join(', ')} };\\n})();`;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"page-helpers.js","sourceRoot":"","sources":["../../../src/site-system/journeys/page-helpers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Functions the site-system journeys run inside the page under test. Each one is self-contained: it uses DOM globals\n * and the other helpers in this file only, because `pageHelpersSource()` injects their source into every document\n * (as `window.__brandlabSiteSystem`, through Playwright's init script, which a Content Security Policy does not\n * block). The pure parts (colour, contrast, placement) are unit-tested in Node.\n */\n\n/**\n * The placements `phone_link_click` accepts: site-next's PHONE_CALL_PLACEMENTS (conformance cannot depend on\n * site-next; a test reads the site-next source and compares). Injected into the page with the helpers.\n */\nexport const SITE_SYSTEM_PHONE_PLACEMENTS: readonly string[] = Object.freeze(['header', 'footer', 'hero', 'cta', 'fab', 'contact', 'location', 'page', 'emergency']);\n\nexport type Rgba = [number, number, number, number];\n\n/** What `watchDisclosure` has seen, in `performance.now()` milliseconds. */\nexport interface DisclosureWatch {\n enter: number | null;\n leave: number | null;\n opened: number | null;\n closed: number | null;\n open: boolean;\n}\n\n/**\n * Whether an element is rendered: connected, with a box, not `visibility: hidden`, not fully transparent and not\n * inside a closed `<details>` (outside its summary). Chromium gives the content of a closed `<details>` a box, so\n * the box alone is not enough; `checkVisibility()` settles it where the browser has it.\n */\nexport function isRendered(element: Element | null | undefined): boolean {\n if (!element || !element.isConnected) return false;\n for (let details = element.closest('details:not([open])'); details; details = details.parentElement?.closest('details:not([open])') ?? null) {\n const summary = Array.from(details.children).find((child) => child.tagName === 'SUMMARY');\n if (!summary || !summary.contains(element)) return false;\n }\n if (typeof element.checkVisibility === 'function' && !element.checkVisibility({ checkOpacity: true, checkVisibilityCSS: true })) return false;\n const rect = element.getBoundingClientRect();\n if (rect.width <= 0 || rect.height <= 0) return false;\n if (getComputedStyle(element).visibility !== 'visible') return false;\n for (let node: Element | null = element; node; node = node.parentElement) {\n if (getComputedStyle(node).opacity === '0') return false;\n }\n return true;\n}\n\n/** A short, readable name for an element in a failure message. */\nexport function describeElement(element: Element): string {\n const tag = element.tagName.toLowerCase();\n const label = element.getAttribute('aria-label') ?? (element as HTMLElement).innerText ?? element.textContent ?? '';\n const text = label.replace(/\\s+/g, ' ').trim().slice(0, 40);\n const href = element.getAttribute('href');\n return `${tag}${text ? ` \"${text}\"` : ''}${href ? ` (${href})` : ''}`;\n}\n\n/** The accessible name, approximately: aria-label, aria-labelledby, the rendered text, then the title. */\nexport function accessibleName(element: Element): string {\n const label = element.getAttribute('aria-label');\n if (label && label.trim()) return label.trim();\n const labelledBy = element.getAttribute('aria-labelledby');\n if (labelledBy) {\n const text = labelledBy.split(/\\s+/).map((id) => document.getElementById(id)?.textContent ?? '').join(' ').trim();\n if (text) return text.replace(/\\s+/g, ' ');\n }\n const text = ((element as HTMLElement).innerText ?? element.textContent ?? '').replace(/\\s+/g, ' ').trim();\n return text || (element.getAttribute('title') ?? '').trim();\n}\n\n/**\n * Where a telephone link reports its tap, exactly as site-next's shared listener resolves it: its own valid\n * `data-phone-location`, then a `<header>` or `<footer>` ancestor, then the nearest ancestor with a valid value,\n * otherwise `page`. `invalid` is the nearest declared value when it is not an allowed placement (the listener then\n * reports the link somewhere else, silently).\n */\nexport function phonePlacement(link: Element): { placement: string; invalid: string | null } {\n const valid = (node: Element): string | undefined => {\n const value = node.getAttribute('data-phone-location')?.trim().toLowerCase();\n return value && SITE_SYSTEM_PHONE_PLACEMENTS.includes(value) ? value : undefined;\n };\n const nearest = link.closest('[data-phone-location]');\n const invalid = nearest && !valid(nearest) ? nearest.getAttribute('data-phone-location') : null;\n const own = valid(link);\n if (own) return { placement: own, invalid };\n if (link.closest('header')) return { placement: 'header', invalid };\n if (link.closest('footer')) return { placement: 'footer', invalid };\n for (let node = link.parentElement?.closest('[data-phone-location]') ?? null; node; node = node.parentElement?.closest('[data-phone-location]') ?? null) {\n const value = valid(node);\n if (value) return { placement: value, invalid };\n }\n return { placement: 'page', invalid };\n}\n\n/** Parse a computed colour. `rgb()`/`rgba()` directly; any other syntax (oklch, lab, color()) through a canvas pixel. */\nexport function parseColour(value: string): Rgba | null {\n const text = value.trim().toLowerCase();\n if (text === 'transparent') return [0, 0, 0, 0];\n const match = /^rgba?\\(([^)]+)\\)$/.exec(text);\n if (match) {\n const parts = match[1]!.split(/[\\s,/]+/).filter(Boolean);\n if (parts.length < 3) return null;\n const channel = (part: string) => (part.endsWith('%') ? (Number.parseFloat(part) / 100) * 255 : Number.parseFloat(part));\n const alphaPart = parts[3];\n const alpha = alphaPart === undefined ? 1 : alphaPart.endsWith('%') ? Number.parseFloat(alphaPart) / 100 : Number.parseFloat(alphaPart);\n const rgba: Rgba = [channel(parts[0]!), channel(parts[1]!), channel(parts[2]!), alpha];\n return rgba.every((part) => Number.isFinite(part)) ? rgba : null;\n }\n if (typeof document === 'undefined') return null;\n const canvas = document.createElement('canvas');\n canvas.width = 1;\n canvas.height = 1;\n const context = canvas.getContext('2d', { willReadFrequently: true });\n if (!context) return null;\n context.clearRect(0, 0, 1, 1);\n context.fillStyle = value;\n context.fillRect(0, 0, 1, 1);\n const [red = 0, green = 0, blue = 0, alpha = 0] = Array.from(context.getImageData(0, 0, 1, 1).data);\n return [red, green, blue, alpha / 255];\n}\n\n/** `top` painted over an opaque `bottom`. */\nexport function compositeColour(top: Rgba, bottom: Rgba): Rgba {\n const alpha = top[3];\n return [\n top[0] * alpha + bottom[0] * (1 - alpha),\n top[1] * alpha + bottom[1] * (1 - alpha),\n top[2] * alpha + bottom[2] * (1 - alpha),\n 1,\n ];\n}\n\n/** The WCAG contrast ratio of two opaque colours. */\nexport function contrastRatio(first: Rgba, second: Rgba): number {\n const luminance = (colour: Rgba) => {\n const [red, green, blue] = colour.slice(0, 3).map((channel) => {\n const value = channel / 255;\n return value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4;\n }) as [number, number, number];\n return 0.2126 * red + 0.7152 * green + 0.0722 * blue;\n };\n const [light, dark] = [luminance(first), luminance(second)].sort((left, right) => right - left) as [number, number];\n return (light + 0.05) / (dark + 0.05);\n}\n\n/**\n * The opaque colour behind an element, from its own and its ancestors' background colours over a white canvas.\n * `null` when a background image (a photo or gradient) is in the way: the contrast cannot be computed there.\n */\nexport function backgroundBehind(element: Element): Rgba | null {\n const layers: Rgba[] = [];\n for (let node: Element | null = element; node; node = node.parentElement) {\n const style = getComputedStyle(node);\n if (style.backgroundImage && style.backgroundImage !== 'none') return null;\n const colour = parseColour(style.backgroundColor);\n if (colour && colour[3] > 0) {\n layers.push(colour);\n if (colour[3] >= 1) break;\n }\n }\n return layers.reverse().reduce<Rgba>((bottom, top) => compositeColour(top, bottom), [255, 255, 255, 1]);\n}\n\n/**\n * Non-text contrast (WCAG 1.4.11) of icon-only controls inside `root`: a link or button with no visible text whose\n * icon is an SVG must reach 3:1 against what is behind it. Returns one line per failure; controls over a photo are\n * counted in `unmeasured`.\n */\nexport function iconContrastProblems(root: Element): { problems: string[]; checked: number; unmeasured: number } {\n const problems: string[] = [];\n let checked = 0;\n let unmeasured = 0;\n const paintOf = (svg: SVGElement): Rgba | null => {\n for (const shape of Array.from(svg.querySelectorAll('path, circle, rect, ellipse, line, polyline, polygon, text, use'))) {\n if (!isRendered(shape)) continue;\n const style = getComputedStyle(shape);\n for (const [paint, opacity] of [[style.fill, style.fillOpacity], [style.stroke, style.strokeOpacity]] as const) {\n if (!paint || paint === 'none' || paint.startsWith('url(')) continue;\n const colour = parseColour(paint);\n const alpha = colour ? colour[3] * Number(opacity || 1) * Number(style.opacity || 1) : 0;\n if (colour && alpha > 0) return [colour[0], colour[1], colour[2], alpha];\n }\n }\n return null;\n };\n for (const control of Array.from(root.querySelectorAll('a[href], button'))) {\n if (!isRendered(control)) continue;\n if (((control as HTMLElement).innerText ?? '').trim()) continue;\n const svg = control.querySelector('svg');\n if (!svg || !isRendered(svg)) continue;\n const paint = paintOf(svg);\n if (!paint) continue;\n const background = backgroundBehind(svg);\n if (!background) {\n unmeasured += 1;\n continue;\n }\n checked += 1;\n const ratio = contrastRatio(compositeColour(paint, background), background);\n if (ratio < 3) problems.push(`${describeElement(control)}: its icon is ${ratio.toFixed(2)}:1 against its background (needs 3:1)`);\n }\n return { problems, checked, unmeasured };\n}\n\n/**\n * The phone call bar: the shared `MobileCallBar`, or any fixed or sticky element along the bottom of the screen that\n * holds a visible telephone link (outside the header and dialogs). `null` when none is on screen.\n */\nexport function findCallBar(): Element | null {\n const tagged = Array.from(document.querySelectorAll('[data-bl=\"call-bar\"], [data-bl=\"callbar\"], [data-bl=\"mobile-call-bar\"]')).find(isRendered);\n if (tagged) return tagged;\n const height = window.innerHeight;\n for (const element of Array.from(document.body.querySelectorAll('*'))) {\n const position = getComputedStyle(element).position;\n if (position !== 'fixed' && position !== 'sticky') continue;\n if (element.closest('header, dialog, [role=\"dialog\"]')) continue;\n const rect = element.getBoundingClientRect();\n if (rect.height <= 0 || rect.bottom < height - 4 || rect.top < height / 2) continue;\n if (!isRendered(element)) continue;\n if (Array.from(element.querySelectorAll('a[href^=\"tel:\"]')).some(isRendered)) return element;\n }\n return null;\n}\n\n/** Visible quote actions in `root`: links or buttons named like the quote action, or the shared quote hooks. */\nexport function quoteActions(root: Element, name: { source: string; flags: string }): Element[] {\n const pattern = new RegExp(name.source, name.flags);\n return Array.from(root.querySelectorAll('a[href], button')).filter((element) => {\n if (!isRendered(element) || element.getAttribute('href')?.startsWith('tel:')) return false;\n if (element.matches('[data-bl=\"quote-button\"], [data-bl-cta^=\"quote\"], [data-lead-cta^=\"quote\"]')) return true;\n return pattern.test(accessibleName(element));\n });\n}\n\n/** The order of the first visible phone link and quote action in `root`. */\nexport function actionOrder(root: Element, name: { source: string; flags: string }): 'phone-first' | 'quote-first' | 'incomplete' {\n const phone = Array.from(root.querySelectorAll('a[href^=\"tel:\"]')).find(isRendered);\n const quote = quoteActions(root, name)[0];\n if (!phone || !quote) return 'incomplete';\n return phone.compareDocumentPosition(quote) & Node.DOCUMENT_POSITION_FOLLOWING ? 'phone-first' : 'quote-first';\n}\n\n/**\n * The hero: the shared hero section, else the smallest block around the page's visible H1 that holds a phone link\n * and a quote action, never above the H1's own section and never `<main>` (without a section, never a block holding\n * an H2). When none holds both, the H1's section (or its parent): its order then reads \"incomplete\".\n */\nexport function heroRegion(name: { source: string; flags: string }): Element | null {\n const heading = Array.from(document.querySelectorAll('h1')).find(isRendered);\n if (!heading) return null;\n const tagged = heading.closest('[data-bl-section=\"hero\"]');\n if (tagged) return tagged;\n const section = heading.closest('section');\n const fallback = section ?? heading.parentElement;\n for (let node = heading.parentElement; node && node !== document.body && node.tagName !== 'MAIN'; node = node.parentElement) {\n if (!section && node.querySelector('h2')) break;\n if (Array.from(node.querySelectorAll('a[href^=\"tel:\"]')).some(isRendered) && quoteActions(node, name).length > 0) return node;\n if (node === section) break;\n }\n return fallback && fallback.tagName !== 'MAIN' ? fallback : heading;\n}\n\n/** A point in the page that is not on an interactive element, a menu or anything in `avoid`. */\nexport function outsidePoint(avoid: Element[]): { x: number; y: number } | null {\n const interactive = 'a[href], button, input, select, textarea, label, summary, details, iframe, video, audio, [role=\"button\"], [role=\"link\"], [role=\"menuitem\"], [role=\"tab\"], [tabindex], [contenteditable=\"\"], [contenteditable=\"true\"]';\n for (let row = 9; row >= 3; row -= 1) {\n for (let column = 1; column <= 9; column += 1) {\n const x = Math.round((window.innerWidth * column) / 10);\n const y = Math.round((window.innerHeight * row) / 10);\n const element = document.elementFromPoint(x, y);\n if (!element || avoid.some((region) => region.contains(element))) continue;\n if (element.closest(interactive) || element.closest('header, nav, dialog, [role=\"dialog\"]')) continue;\n return { x, y };\n }\n }\n return null;\n}\n\n/** Tag an element so Playwright and axe can find it by `[data-brandlab-journey~=\"<name>\"]`. */\nexport function markElement(element: Element, name: string): void {\n const names = new Set((element.getAttribute('data-brandlab-journey') ?? '').split(/\\s+/).filter(Boolean));\n names.add(name);\n element.setAttribute('data-brandlab-journey', [...names].join(' '));\n}\n\n/**\n * Watch one disclosure: when the pointer enters and leaves its item (and panel), and when the panel it controls\n * becomes rendered or hidden, timed with `performance.now()`. Attribute and tree changes are sampled at once; style\n * changes without a DOM change (CSS `:hover`) every animation frame.\n */\nexport function watchDisclosure(trigger: Element, panelId: string): void {\n const item = trigger.closest('li') ?? trigger.parentElement ?? trigger;\n const panel = () => document.getElementById(panelId);\n const inside = (node: EventTarget | null) => node instanceof Node && (item.contains(node) || Boolean(panel()?.contains(node)));\n const state: DisclosureWatch = { enter: null, leave: null, opened: null, closed: null, open: isRendered(panel()) };\n const sample = () => {\n const open = isRendered(panel());\n if (open === state.open) return;\n state.open = open;\n if (open && state.opened === null) state.opened = performance.now();\n if (!open && state.closed === null) state.closed = performance.now();\n };\n const onOver = (event: Event) => {\n if (state.enter === null && inside(event.target)) state.enter = performance.now();\n };\n const onOut = (event: Event) => {\n if (state.leave === null && inside(event.target) && !inside((event as PointerEvent).relatedTarget)) state.leave = performance.now();\n };\n const observer = new MutationObserver(sample);\n observer.observe(document.documentElement, { attributes: true, childList: true, subtree: true });\n let frame = 0;\n const loop = () => {\n sample();\n frame = requestAnimationFrame(loop);\n };\n loop();\n document.addEventListener('pointerover', onOver, true);\n document.addEventListener('pointerout', onOut, true);\n const previous = (window as unknown as { __brandlabSiteSystemWatch?: { stop(): void } }).__brandlabSiteSystemWatch;\n previous?.stop();\n (window as unknown as { __brandlabSiteSystemWatch: unknown }).__brandlabSiteSystemWatch = {\n state,\n stop() {\n observer.disconnect();\n cancelAnimationFrame(frame);\n document.removeEventListener('pointerover', onOver, true);\n document.removeEventListener('pointerout', onOut, true);\n },\n };\n}\n\n/** The current state of `watchDisclosure`'s watch. */\nexport function watchState(): DisclosureWatch | null {\n const watch = (window as unknown as { __brandlabSiteSystemWatch?: { state: DisclosureWatch } }).__brandlabSiteSystemWatch;\n return watch ? { ...watch.state } : null;\n}\n\n/**\n * After a Tab press: is the focused element fully hidden under the sticky header or the call bar? Samples nine points\n * across the visible part of its box; it is hidden when the header or call bar is on top at every one. `repeat` is\n * true once focus comes back to an element it has already visited.\n */\nexport function focusStep(): { done: boolean; repeat: boolean; obscured: string | null; covered: 'header' | 'call bar' | null } {\n const element = document.activeElement;\n const store = window as unknown as { __brandlabSiteSystemFocus?: WeakSet<Element> };\n store.__brandlabSiteSystemFocus ??= new WeakSet<Element>();\n if (!element || element === document.body || element === document.documentElement) return { done: true, repeat: false, obscured: null, covered: null };\n const repeat = store.__brandlabSiteSystemFocus.has(element);\n store.__brandlabSiteSystemFocus.add(element);\n const header = document.querySelector('[data-brandlab-journey~=\"header\"]')\n ?? Array.from(document.querySelectorAll('[data-bl=\"header\"], header')).find((candidate) => isRendered(candidate) && !candidate.closest('main, article, section, aside, footer'))\n ?? null;\n const callBar = findCallBar();\n if (header?.contains(element) || callBar?.contains(element)) return { done: false, repeat, obscured: null, covered: null };\n const rect = element.getBoundingClientRect();\n const left = Math.max(rect.left, 0);\n const right = Math.min(rect.right, window.innerWidth);\n const top = Math.max(rect.top, 0);\n const bottom = Math.min(rect.bottom, window.innerHeight);\n if (right - left < 1 || bottom - top < 1) return { done: false, repeat, obscured: null, covered: null };\n let coveredBy: 'header' | 'call bar' | null = null;\n for (const fx of [0.15, 0.5, 0.85]) {\n for (const fy of [0.15, 0.5, 0.85]) {\n const hit = document.elementFromPoint(left + (right - left) * fx, top + (bottom - top) * fy);\n if (!hit || element.contains(hit)) return { done: false, repeat, obscured: null, covered: null };\n if (header?.contains(hit)) coveredBy ??= 'header';\n else if (callBar?.contains(hit)) coveredBy ??= 'call bar';\n else return { done: false, repeat, obscured: null, covered: null };\n }\n }\n return { done: false, repeat, obscured: describeElement(element), covered: coveredBy };\n}\n\n/**\n * `focusStep` one animation frame after the focus moved (capped at 50 ms, since a background page may not paint), so\n * a sticky bar that hides on its observer's next frame is measured after it moved, not mid-transition.\n */\nexport function focusStepAfterFrame(): Promise<ReturnType<typeof focusStep>> {\n return new Promise((resolve) => {\n let settled = false;\n const finish = () => {\n if (settled) return;\n settled = true;\n resolve(focusStep());\n };\n requestAnimationFrame(() => finish());\n setTimeout(finish, 50);\n });\n}\n\n/** Elements a Tab press can reach, roughly: enough to bound the K5 walk. */\nexport function tabbableCount(): number {\n const selector = 'a[href], button:not([disabled]), input:not([disabled]):not([type=\"hidden\"]), select:not([disabled]), textarea:not([disabled]), summary, iframe, [tabindex]:not([tabindex=\"-1\"])';\n return Array.from(document.querySelectorAll(selector)).filter(isRendered).length;\n}\n\n/** What a K14 block paints: an opaque colour, a photo or gradient (never equal to another block's), or unknown. */\nexport interface PaintedGround {\n description: string;\n /** `rgb(r, g, b)`, `image` or `unknown`. */\n ground: string;\n}\n\n/**\n * The ground a top-level block paints (K14, 3.19.0): its own background image (a photo band or gradient), a photo\n * covering most of it (a fill image), else its background colour composited over what shows through from its\n * ancestors. A transparent block whose one child covers it and paints a colour takes the child's.\n */\nexport function paintedGround(element: Element): string {\n const box = element.getBoundingClientRect();\n const area = box.width * box.height;\n if (area <= 0) return 'unknown';\n if (getComputedStyle(element).backgroundImage !== 'none') return 'image';\n for (const media of Array.from(element.querySelectorAll('img, picture, video'))) {\n const rect = media.getBoundingClientRect();\n if (rect.width * rect.height >= 0.8 * area && isRendered(media)) return 'image';\n }\n let painter: Element = element;\n const own = parseColour(getComputedStyle(element).backgroundColor);\n if (!own || own[3] === 0) {\n const cover = Array.from(element.children).find((child) => {\n const rect = child.getBoundingClientRect();\n const colour = parseColour(getComputedStyle(child).backgroundColor);\n return rect.width * rect.height >= 0.9 * area && colour !== null && colour[3] > 0;\n });\n if (cover) {\n if (getComputedStyle(cover).backgroundImage !== 'none') return 'image';\n painter = cover;\n }\n }\n const colour = backgroundBehind(painter);\n if (!colour) return 'image';\n return `rgb(${colour.slice(0, 3).map((channel) => Math.round(channel)).join(', ')})`;\n}\n\n/**\n * The page's top-level blocks in order (K14): each rendered child of `main` (through a lone wrapper), then what follows\n * `main` up to and including the footer. A `[data-bl-inset]` block is part of the place before it, so it is left out.\n */\nexport function groundBlocks(): PaintedGround[] {\n const main = document.querySelector('main');\n if (!main) return [];\n const usable = (element: Element) => !['SCRIPT', 'STYLE', 'TEMPLATE', 'NOSCRIPT', 'LINK'].includes(element.tagName)\n && !element.hasAttribute('data-bl-inset') && isRendered(element) && element.getBoundingClientRect().height >= 8;\n let blocks = Array.from(main.children).filter(usable);\n while (blocks.length === 1 && Array.from(blocks[0]!.children).filter(usable).length > 1 && paintedGround(blocks[0]!).startsWith('rgb') === false) {\n blocks = Array.from(blocks[0]!.children).filter(usable);\n }\n const footer = document.querySelector('footer[data-bl=\"footer\"], body footer:not(main footer)');\n for (let node = main.nextElementSibling; node; node = node.nextElementSibling) {\n if (usable(node)) blocks.push(node);\n if (node === footer || node.contains(footer)) break;\n }\n if (footer && !blocks.some((block) => block === footer || block.contains(footer)) && isRendered(footer)) blocks.push(footer);\n return blocks.map((block) => {\n const section = block.getAttribute('data-bl-section') ?? (block.tagName === 'FOOTER' ? 'footer' : null);\n const description = section ? `\"${section}\"` : `${block.tagName.toLowerCase()}${block.id ? `#${block.id}` : ''}`;\n return { description, ground: paintedGround(block) };\n });\n}\n\n/** Neighbouring blocks that paint the same colour (K14): a photo or an unknown ground never matches. */\nexport function groundProblems(path: string, blocks: readonly PaintedGround[]): string[] {\n const problems: string[] = [];\n const channels = (ground: string) => ground.slice(4, -1).split(',').map(Number);\n for (let index = 1; index < blocks.length; index += 1) {\n const [before, after] = [blocks[index - 1]!, blocks[index]!];\n if (!before.ground.startsWith('rgb') || !after.ground.startsWith('rgb')) continue;\n const [left, right] = [channels(before.ground), channels(after.ground)];\n if (left.every((channel, at) => Math.abs(channel - right[at]!) <= 2)) {\n problems.push(`${path}: ${before.description} and ${after.description} share the background ${after.ground}`);\n }\n }\n return problems;\n}\n\nconst PAGE_HELPERS = {\n isRendered, describeElement, accessibleName, phonePlacement, parseColour, compositeColour, contrastRatio, backgroundBehind,\n iconContrastProblems, findCallBar, quoteActions, actionOrder, heroRegion, outsidePoint, markElement, watchDisclosure,\n watchState, focusStep, focusStepAfterFrame, tabbableCount, paintedGround, groundBlocks, groundProblems,\n};\n\n/** `window.__brandlabSiteSystem` in a page the journeys opened. */\nexport type SiteSystemPageHelpers = typeof PAGE_HELPERS;\n\n/** The init script that defines `window.__brandlabSiteSystem` in every document of the page. */\nexport function pageHelpersSource(): string {\n const names = Object.keys(PAGE_HELPERS);\n return `(() => {\\nconst SITE_SYSTEM_PHONE_PLACEMENTS = ${JSON.stringify(SITE_SYSTEM_PHONE_PLACEMENTS)};\\n${Object.values(PAGE_HELPERS).map((helper) => helper.toString()).join('\\n')}\\nwindow.__brandlabSiteSystem = { ${names.join(', ')} };\\n})();`;\n}\n"]}
|
|
@@ -5,7 +5,7 @@ type JourneyCheck = Extract<(typeof SITE_SYSTEM_CHECKS)[number], {
|
|
|
5
5
|
}>;
|
|
6
6
|
export type SiteSystemJourneyId = JourneyCheck['id'];
|
|
7
7
|
/** Every journey check, in the order the journeys register. */
|
|
8
|
-
export declare const SITE_SYSTEM_JOURNEY_IDS: readonly ["N3", "N4", "N5", "N6", "N8", "K3", "K4", "K5", "K6", "C4", "W2", "C1", "W9"];
|
|
8
|
+
export declare const SITE_SYSTEM_JOURNEY_IDS: readonly ["N3", "N4", "N5", "N6", "N8", "K3", "K4", "K5", "K6", "C4", "W2", "K14", "C1", "W9"];
|
|
9
9
|
/** Desktop widths for N6: both ends and the middle of the compact band, the desktop breakpoint and two wide screens. */
|
|
10
10
|
export declare const SITE_SYSTEM_DESKTOP_WIDTHS: readonly number[];
|
|
11
11
|
export declare const SITE_SYSTEM_PHONE_VIEWPORT: Readonly<{
|
|
@@ -40,6 +40,11 @@ export interface BrandlabSiteSystemTestOptions {
|
|
|
40
40
|
money?: string | readonly string[];
|
|
41
41
|
contact?: string;
|
|
42
42
|
families?: string | readonly string[];
|
|
43
|
+
/**
|
|
44
|
+
* More pages for K14 (3.19.0), one per page family the other lists don't cover, for example `/about` and a guide.
|
|
45
|
+
* K14 also runs on home, the money pages, the contact page and the family pages.
|
|
46
|
+
*/
|
|
47
|
+
grounds?: string | readonly string[];
|
|
43
48
|
};
|
|
44
49
|
/** Desktop widths for N6, each 1024 px or more (default 1024, 1100, 1280, 1440 and 1920). */
|
|
45
50
|
desktopWidths?: readonly number[];
|
|
@@ -69,6 +74,8 @@ export interface SiteSystemJourneyPlan {
|
|
|
69
74
|
families: readonly string[];
|
|
70
75
|
/** Home, the money pages and the contact page, without repeats: K5, K6 and C4 run on each. */
|
|
71
76
|
sampled: readonly string[];
|
|
77
|
+
/** The sampled pages, the family pages and `pages.grounds`, without repeats: K14 runs on each. */
|
|
78
|
+
grounds: readonly string[];
|
|
72
79
|
desktopWidths: readonly number[];
|
|
73
80
|
actionOrder: SiteSystemActionOrder;
|
|
74
81
|
quoteName: RegExp;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/site-system/journeys/plan.ts"],"names":[],"mappings":"AAKA,OAAO,EAA+B,8BAA8B,EAAE,MAAM,kBAAkB,CAAC;AAC/F,OAAO,EAAE,kBAAkB,EAA4C,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAEjH,KAAK,YAAY,GAAG,OAAO,CAAC,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,EAAE;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC,CAAC;AACtF,MAAM,MAAM,mBAAmB,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;AAErD,+DAA+D;AAC/D,eAAO,MAAM,uBAAuB,
|
|
1
|
+
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/site-system/journeys/plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,7 +6,7 @@ import { BRANDLAB_CURRENT_RUNTIME_RELEASE } from '../../current-release.js';
|
|
|
6
6
|
import { detectBrandlabCanaryRelease, detectInstalledBrandlabRelease } from '../../project.js';
|
|
7
7
|
import { SITE_SYSTEM_CHECKS, SITE_SYSTEM_TIERS, siteSystemReleaseRank } from '../checks.js';
|
|
8
8
|
/** Every journey check, in the order the journeys register. */
|
|
9
|
-
export const SITE_SYSTEM_JOURNEY_IDS = Object.freeze(['N3', 'N4', 'N5', 'N6', 'N8', 'K3', 'K4', 'K5', 'K6', 'C4', 'W2', 'C1', 'W9']);
|
|
9
|
+
export const SITE_SYSTEM_JOURNEY_IDS = Object.freeze(['N3', 'N4', 'N5', 'N6', 'N8', 'K3', 'K4', 'K5', 'K6', 'C4', 'W2', 'K14', 'C1', 'W9']);
|
|
10
10
|
/** Desktop widths for N6: both ends and the middle of the compact band, the desktop breakpoint and two wide screens. */
|
|
11
11
|
export const SITE_SYSTEM_DESKTOP_WIDTHS = Object.freeze([1024, 1100, 1280, 1440, 1920]);
|
|
12
12
|
export const SITE_SYSTEM_PHONE_VIEWPORT = Object.freeze({ width: 390, height: 844 });
|
|
@@ -74,6 +74,12 @@ export function planBrandlabSiteSystemJourneys(options) {
|
|
|
74
74
|
if (problem)
|
|
75
75
|
errors.push(problem);
|
|
76
76
|
});
|
|
77
|
+
const grounds = pages.grounds === undefined ? [] : typeof pages.grounds === 'string' ? [pages.grounds] : [...pages.grounds];
|
|
78
|
+
grounds.forEach((path, index) => {
|
|
79
|
+
const problem = pathProblem(`pages.grounds[${index}]`, path);
|
|
80
|
+
if (problem)
|
|
81
|
+
errors.push(problem);
|
|
82
|
+
});
|
|
77
83
|
const desktopWidths = input.desktopWidths?.length ? [...input.desktopWidths] : [...SITE_SYSTEM_DESKTOP_WIDTHS];
|
|
78
84
|
for (const width of desktopWidths) {
|
|
79
85
|
if (!Number.isInteger(width) || width < 1024 || width > 3840)
|
|
@@ -118,6 +124,7 @@ export function planBrandlabSiteSystemJourneys(options) {
|
|
|
118
124
|
contact: pages.contact,
|
|
119
125
|
families: [...new Set(families)],
|
|
120
126
|
sampled: [...new Set([pages.home, ...money, ...(pages.contact ? [pages.contact] : [])])],
|
|
127
|
+
grounds: [...new Set([pages.home, ...money, ...(pages.contact ? [pages.contact] : []), ...families, ...grounds])],
|
|
121
128
|
desktopWidths,
|
|
122
129
|
actionOrder: input.actionOrder ?? 'phone-first',
|
|
123
130
|
quoteName,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../src/site-system/journeys/plan.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Options and planning for the site-system journeys: which journeys a tier registers, the sampled pages and the\n * defaults. Pure, so it is unit-tested without a browser.\n */\nimport { BRANDLAB_CURRENT_RUNTIME_RELEASE } from '../../current-release.js';\nimport { detectBrandlabCanaryRelease, detectInstalledBrandlabRelease } from '../../project.js';\nimport { SITE_SYSTEM_CHECKS, SITE_SYSTEM_TIERS, siteSystemReleaseRank, type SiteSystemTier } from '../checks.js';\n\ntype JourneyCheck = Extract<(typeof SITE_SYSTEM_CHECKS)[number], { kind: 'journey' }>;\nexport type SiteSystemJourneyId = JourneyCheck['id'];\n\n/** Every journey check, in the order the journeys register. */\nexport const SITE_SYSTEM_JOURNEY_IDS = Object.freeze(['N3', 'N4', 'N5', 'N6', 'N8', 'K3', 'K4', 'K5', 'K6', 'C4', 'W2', 'C1', 'W9'] as const satisfies readonly SiteSystemJourneyId[]);\n\n/** Desktop widths for N6: both ends and the middle of the compact band, the desktop breakpoint and two wide screens. */\nexport const SITE_SYSTEM_DESKTOP_WIDTHS = Object.freeze([1024, 1100, 1280, 1440, 1920]);\nexport const SITE_SYSTEM_PHONE_VIEWPORT = Object.freeze({ width: 390, height: 844 });\nexport const SITE_SYSTEM_DESKTOP_VIEWPORT = Object.freeze({ width: 1440, height: 900 });\n\n/** The quote action's accessible name when the site does not record one. */\nexport const SITE_SYSTEM_QUOTE_NAME = /\\bquote\\b/i;\n\nexport type SiteSystemActionOrder = 'phone-first' | 'quote-first';\n\nexport interface BrandlabSiteSystemTestOptions {\n /** The adoption tier from brandlab.config.ts (`siteSystem.tier`). C1 registers from `enquiry`. */\n tier: SiteSystemTier;\n /**\n * The release whose journeys register. `defineBrandlabSiteSystemTests` defaults it to the site's installed Brandlab\n * release, read from its package.json as `brandlab-ready` reads it (one exact version, or one canary such as\n * `3.15.0-canary.2`), else this conformance release. A journey registers only from the release that brings it, so a\n * later journey never turns a site's e2e run red before the gate blocks on it, and a check that blocks has its\n * journey. Name a later release to preview its journeys.\n */\n release?: string;\n /**\n * The sampled pages: home, the money pages (service pages with the enquiry form) and the contact page. `families`\n * (W9, full tier from 3.13.0) names one built page per dynamic route family, such as `/services/blocked-drains` and\n * `/locations/ryde`: its URL variants are checked.\n */\n pages: { home: string; money?: string | readonly string[]; contact?: string; families?: string | readonly string[] };\n /** Desktop widths for N6, each 1024 px or more (default 1024, 1100, 1280, 1440 and 1920). */\n desktopWidths?: readonly number[];\n /** The recorded order of the phone and quote actions (K6), default `phone-first`. */\n actionOrder?: SiteSystemActionOrder;\n /** The quote action's accessible name (default /\\bquote\\b/i), for a recorded label such as \"Book an inspection\". */\n quoteName?: string | RegExp;\n /** The main menu's accessible name (default \"Main\"). */\n navName?: string;\n /** The phone menu button's accessible name (default \"Menu\"). */\n menuName?: string | RegExp;\n /** How long a document may take to load, default 45 seconds; a timeout is retried once. */\n navigationTimeoutMs?: number;\n /** How long to wait for the network to settle after a load, default 10 seconds; a busy network is not a failure. */\n settleTimeoutMs?: number;\n /** The most Tab presses K5 makes on one page (default 400); a longer page is reported, not failed. */\n maxTabStops?: number;\n}\n\nexport interface SiteSystemJourneyPlan {\n tier: SiteSystemTier;\n release: string;\n journeys: readonly SiteSystemJourneyId[];\n home: string;\n money: readonly string[];\n contact: string | undefined;\n /** One page per dynamic route family, for W9's URL variants. */\n families: readonly string[];\n /** Home, the money pages and the contact page, without repeats: K5, K6 and C4 run on each. */\n sampled: readonly string[];\n desktopWidths: readonly number[];\n actionOrder: SiteSystemActionOrder;\n quoteName: RegExp;\n navName: string;\n menuName: string | RegExp;\n navigationTimeoutMs: number;\n settleTimeoutMs: number;\n maxTabStops: number;\n /** Gaps that fail a journey when it runs (fail closed), rather than stopping the whole spec file. */\n problems: Partial<Record<SiteSystemJourneyId, string>>;\n}\n\nexport function siteSystemJourneyTitle(id: SiteSystemJourneyId, text: string): string {\n return `[${id}] ${text}`;\n}\n\n/**\n * The journey checks a tier registers on a release: its own and the tiers below it, each from the release that brings\n * it (default: this conformance release).\n */\nexport function siteSystemJourneysFor(tier: SiteSystemTier, release: string = BRANDLAB_CURRENT_RUNTIME_RELEASE.releaseVersion): SiteSystemJourneyId[] {\n const rank = SITE_SYSTEM_TIERS.indexOf(tier);\n const releaseRank = siteSystemReleaseRank(release);\n const journeys = new Map<string, { tier: string; from: string }>(SITE_SYSTEM_CHECKS.filter((check) => check.kind === 'journey').map((check) => [check.id, check]));\n return SITE_SYSTEM_JOURNEY_IDS.filter((id) => {\n const check = journeys.get(id);\n return check !== undefined\n && SITE_SYSTEM_TIERS.indexOf(check.tier as SiteSystemTier) <= rank\n && siteSystemReleaseRank(check.from) <= releaseRank;\n });\n}\n\n/**\n * The release the journeys register for on a site: its installed Brandlab release as `brandlab-ready` reads it (all\n * four packages at one exact version, or one canary, from package.json), else this conformance release. A canary's\n * own release manifest still names the last published release, so without this its new journeys (W2 and W9 on\n * 3.15.0-canary.2) would not register while the gate blocks on them.\n */\nexport function siteSystemJourneyRelease(packageJson: Parameters<typeof detectInstalledBrandlabRelease>[0]): string {\n return detectInstalledBrandlabRelease(packageJson) ?? detectBrandlabCanaryRelease(packageJson)?.version ?? BRANDLAB_CURRENT_RUNTIME_RELEASE.releaseVersion;\n}\n\nfunction pathProblem(label: string, path: unknown): string | null {\n if (typeof path !== 'string' || !path.startsWith('/') || path.startsWith('//') || /\\s/.test(path)) {\n return `${label} must be a site path starting with \"/\" (got ${JSON.stringify(path)})`;\n }\n return null;\n}\n\n/** Validate the options and fill the defaults. Malformed options throw, listing every problem. */\nexport function planBrandlabSiteSystemJourneys(options: BrandlabSiteSystemTestOptions): SiteSystemJourneyPlan {\n const errors: string[] = [];\n const input = (options ?? {}) as Partial<BrandlabSiteSystemTestOptions>;\n if (!SITE_SYSTEM_TIERS.includes(input.tier as SiteSystemTier)) {\n errors.push(`tier must be one of ${SITE_SYSTEM_TIERS.join(', ')} (got ${JSON.stringify(input.tier)})`);\n }\n const pages = input.pages ?? ({} as BrandlabSiteSystemTestOptions['pages']);\n const homeProblem = pathProblem('pages.home', pages.home);\n if (homeProblem) errors.push(homeProblem);\n const money = pages.money === undefined ? [] : typeof pages.money === 'string' ? [pages.money] : [...pages.money];\n money.forEach((path, index) => {\n const problem = pathProblem(`pages.money[${index}]`, path);\n if (problem) errors.push(problem);\n });\n if (pages.contact !== undefined) {\n const problem = pathProblem('pages.contact', pages.contact);\n if (problem) errors.push(problem);\n }\n const families = pages.families === undefined ? [] : typeof pages.families === 'string' ? [pages.families] : [...pages.families];\n families.forEach((path, index) => {\n const problem = pathProblem(`pages.families[${index}]`, path) ?? (/[?#]/.test(path) || path === '/' ? `pages.families[${index}] must be a page path below home with no query (got ${JSON.stringify(path)})` : null);\n if (problem) errors.push(problem);\n });\n const desktopWidths = input.desktopWidths?.length ? [...input.desktopWidths] : [...SITE_SYSTEM_DESKTOP_WIDTHS];\n for (const width of desktopWidths) {\n if (!Number.isInteger(width) || width < 1024 || width > 3840) errors.push(`desktopWidths must be whole pixel widths from 1024 to 3840 (got ${width})`);\n }\n if (input.actionOrder !== undefined && input.actionOrder !== 'phone-first' && input.actionOrder !== 'quote-first') {\n errors.push(`actionOrder must be phone-first or quote-first (got ${JSON.stringify(input.actionOrder)})`);\n }\n for (const key of ['navigationTimeoutMs', 'settleTimeoutMs', 'maxTabStops'] as const) {\n const value = input[key];\n if (value !== undefined && (!Number.isInteger(value) || value <= 0)) errors.push(`${key} must be a positive whole number (got ${value})`);\n }\n if (input.release !== undefined && (typeof input.release !== 'string' || !/^\\d+\\.\\d+\\.\\d+(?:-canary\\.\\d+)?$/.test(input.release))) {\n errors.push(`release must be a version such as 3.9.0 or 3.15.0-canary.2 (got ${JSON.stringify(input.release)})`);\n }\n if (input.navName !== undefined && (typeof input.navName !== 'string' || !input.navName.trim())) errors.push('navName must be a non-empty string');\n if (errors.length > 0) throw new TypeError(`defineBrandlabSiteSystemTests: ${errors.join('; ')}`);\n\n const tier = input.tier as SiteSystemTier;\n const release = input.release ?? BRANDLAB_CURRENT_RUNTIME_RELEASE.releaseVersion;\n const journeys = siteSystemJourneysFor(tier, release);\n const problems: SiteSystemJourneyPlan['problems'] = {};\n if (journeys.includes('C1') && money.length === 0) {\n problems.C1 = 'pages.money names no money page: C1 checks the first screen of each service page with the enquiry form';\n }\n if (journeys.includes('W9') && families.length === 0) {\n problems.W9 = 'pages.families names no page: W9 checks the URL variants of one built page per dynamic route family';\n }\n const quoteName = input.quoteName === undefined\n ? SITE_SYSTEM_QUOTE_NAME\n : input.quoteName instanceof RegExp\n ? input.quoteName\n : new RegExp(`^\\\\s*${input.quoteName.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\\\\s*$`, 'i');\n return {\n tier,\n release,\n journeys,\n home: pages.home,\n money,\n contact: pages.contact,\n families: [...new Set(families)],\n sampled: [...new Set([pages.home, ...money, ...(pages.contact ? [pages.contact] : [])])],\n desktopWidths,\n actionOrder: input.actionOrder ?? 'phone-first',\n quoteName,\n navName: input.navName ?? 'Main',\n menuName: input.menuName ?? 'Menu',\n navigationTimeoutMs: input.navigationTimeoutMs ?? 45_000,\n settleTimeoutMs: input.settleTimeoutMs ?? 10_000,\n maxTabStops: input.maxTabStops ?? 400,\n problems,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../src/site-system/journeys/plan.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Options and planning for the site-system journeys: which journeys a tier registers, the sampled pages and the\n * defaults. Pure, so it is unit-tested without a browser.\n */\nimport { BRANDLAB_CURRENT_RUNTIME_RELEASE } from '../../current-release.js';\nimport { detectBrandlabCanaryRelease, detectInstalledBrandlabRelease } from '../../project.js';\nimport { SITE_SYSTEM_CHECKS, SITE_SYSTEM_TIERS, siteSystemReleaseRank, type SiteSystemTier } from '../checks.js';\n\ntype JourneyCheck = Extract<(typeof SITE_SYSTEM_CHECKS)[number], { kind: 'journey' }>;\nexport type SiteSystemJourneyId = JourneyCheck['id'];\n\n/** Every journey check, in the order the journeys register. */\nexport const SITE_SYSTEM_JOURNEY_IDS = Object.freeze(['N3', 'N4', 'N5', 'N6', 'N8', 'K3', 'K4', 'K5', 'K6', 'C4', 'W2', 'K14', 'C1', 'W9'] as const satisfies readonly SiteSystemJourneyId[]);\n\n/** Desktop widths for N6: both ends and the middle of the compact band, the desktop breakpoint and two wide screens. */\nexport const SITE_SYSTEM_DESKTOP_WIDTHS = Object.freeze([1024, 1100, 1280, 1440, 1920]);\nexport const SITE_SYSTEM_PHONE_VIEWPORT = Object.freeze({ width: 390, height: 844 });\nexport const SITE_SYSTEM_DESKTOP_VIEWPORT = Object.freeze({ width: 1440, height: 900 });\n\n/** The quote action's accessible name when the site does not record one. */\nexport const SITE_SYSTEM_QUOTE_NAME = /\\bquote\\b/i;\n\nexport type SiteSystemActionOrder = 'phone-first' | 'quote-first';\n\nexport interface BrandlabSiteSystemTestOptions {\n /** The adoption tier from brandlab.config.ts (`siteSystem.tier`). C1 registers from `enquiry`. */\n tier: SiteSystemTier;\n /**\n * The release whose journeys register. `defineBrandlabSiteSystemTests` defaults it to the site's installed Brandlab\n * release, read from its package.json as `brandlab-ready` reads it (one exact version, or one canary such as\n * `3.15.0-canary.2`), else this conformance release. A journey registers only from the release that brings it, so a\n * later journey never turns a site's e2e run red before the gate blocks on it, and a check that blocks has its\n * journey. Name a later release to preview its journeys.\n */\n release?: string;\n /**\n * The sampled pages: home, the money pages (service pages with the enquiry form) and the contact page. `families`\n * (W9, full tier from 3.13.0) names one built page per dynamic route family, such as `/services/blocked-drains` and\n * `/locations/ryde`: its URL variants are checked.\n */\n pages: {\n home: string;\n money?: string | readonly string[];\n contact?: string;\n families?: string | readonly string[];\n /**\n * More pages for K14 (3.19.0), one per page family the other lists don't cover, for example `/about` and a guide.\n * K14 also runs on home, the money pages, the contact page and the family pages.\n */\n grounds?: string | readonly string[];\n };\n /** Desktop widths for N6, each 1024 px or more (default 1024, 1100, 1280, 1440 and 1920). */\n desktopWidths?: readonly number[];\n /** The recorded order of the phone and quote actions (K6), default `phone-first`. */\n actionOrder?: SiteSystemActionOrder;\n /** The quote action's accessible name (default /\\bquote\\b/i), for a recorded label such as \"Book an inspection\". */\n quoteName?: string | RegExp;\n /** The main menu's accessible name (default \"Main\"). */\n navName?: string;\n /** The phone menu button's accessible name (default \"Menu\"). */\n menuName?: string | RegExp;\n /** How long a document may take to load, default 45 seconds; a timeout is retried once. */\n navigationTimeoutMs?: number;\n /** How long to wait for the network to settle after a load, default 10 seconds; a busy network is not a failure. */\n settleTimeoutMs?: number;\n /** The most Tab presses K5 makes on one page (default 400); a longer page is reported, not failed. */\n maxTabStops?: number;\n}\n\nexport interface SiteSystemJourneyPlan {\n tier: SiteSystemTier;\n release: string;\n journeys: readonly SiteSystemJourneyId[];\n home: string;\n money: readonly string[];\n contact: string | undefined;\n /** One page per dynamic route family, for W9's URL variants. */\n families: readonly string[];\n /** Home, the money pages and the contact page, without repeats: K5, K6 and C4 run on each. */\n sampled: readonly string[];\n /** The sampled pages, the family pages and `pages.grounds`, without repeats: K14 runs on each. */\n grounds: readonly string[];\n desktopWidths: readonly number[];\n actionOrder: SiteSystemActionOrder;\n quoteName: RegExp;\n navName: string;\n menuName: string | RegExp;\n navigationTimeoutMs: number;\n settleTimeoutMs: number;\n maxTabStops: number;\n /** Gaps that fail a journey when it runs (fail closed), rather than stopping the whole spec file. */\n problems: Partial<Record<SiteSystemJourneyId, string>>;\n}\n\nexport function siteSystemJourneyTitle(id: SiteSystemJourneyId, text: string): string {\n return `[${id}] ${text}`;\n}\n\n/**\n * The journey checks a tier registers on a release: its own and the tiers below it, each from the release that brings\n * it (default: this conformance release).\n */\nexport function siteSystemJourneysFor(tier: SiteSystemTier, release: string = BRANDLAB_CURRENT_RUNTIME_RELEASE.releaseVersion): SiteSystemJourneyId[] {\n const rank = SITE_SYSTEM_TIERS.indexOf(tier);\n const releaseRank = siteSystemReleaseRank(release);\n const journeys = new Map<string, { tier: string; from: string }>(SITE_SYSTEM_CHECKS.filter((check) => check.kind === 'journey').map((check) => [check.id, check]));\n return SITE_SYSTEM_JOURNEY_IDS.filter((id) => {\n const check = journeys.get(id);\n return check !== undefined\n && SITE_SYSTEM_TIERS.indexOf(check.tier as SiteSystemTier) <= rank\n && siteSystemReleaseRank(check.from) <= releaseRank;\n });\n}\n\n/**\n * The release the journeys register for on a site: its installed Brandlab release as `brandlab-ready` reads it (all\n * four packages at one exact version, or one canary, from package.json), else this conformance release. A canary's\n * own release manifest still names the last published release, so without this its new journeys (W2 and W9 on\n * 3.15.0-canary.2) would not register while the gate blocks on them.\n */\nexport function siteSystemJourneyRelease(packageJson: Parameters<typeof detectInstalledBrandlabRelease>[0]): string {\n return detectInstalledBrandlabRelease(packageJson) ?? detectBrandlabCanaryRelease(packageJson)?.version ?? BRANDLAB_CURRENT_RUNTIME_RELEASE.releaseVersion;\n}\n\nfunction pathProblem(label: string, path: unknown): string | null {\n if (typeof path !== 'string' || !path.startsWith('/') || path.startsWith('//') || /\\s/.test(path)) {\n return `${label} must be a site path starting with \"/\" (got ${JSON.stringify(path)})`;\n }\n return null;\n}\n\n/** Validate the options and fill the defaults. Malformed options throw, listing every problem. */\nexport function planBrandlabSiteSystemJourneys(options: BrandlabSiteSystemTestOptions): SiteSystemJourneyPlan {\n const errors: string[] = [];\n const input = (options ?? {}) as Partial<BrandlabSiteSystemTestOptions>;\n if (!SITE_SYSTEM_TIERS.includes(input.tier as SiteSystemTier)) {\n errors.push(`tier must be one of ${SITE_SYSTEM_TIERS.join(', ')} (got ${JSON.stringify(input.tier)})`);\n }\n const pages = input.pages ?? ({} as BrandlabSiteSystemTestOptions['pages']);\n const homeProblem = pathProblem('pages.home', pages.home);\n if (homeProblem) errors.push(homeProblem);\n const money = pages.money === undefined ? [] : typeof pages.money === 'string' ? [pages.money] : [...pages.money];\n money.forEach((path, index) => {\n const problem = pathProblem(`pages.money[${index}]`, path);\n if (problem) errors.push(problem);\n });\n if (pages.contact !== undefined) {\n const problem = pathProblem('pages.contact', pages.contact);\n if (problem) errors.push(problem);\n }\n const families = pages.families === undefined ? [] : typeof pages.families === 'string' ? [pages.families] : [...pages.families];\n families.forEach((path, index) => {\n const problem = pathProblem(`pages.families[${index}]`, path) ?? (/[?#]/.test(path) || path === '/' ? `pages.families[${index}] must be a page path below home with no query (got ${JSON.stringify(path)})` : null);\n if (problem) errors.push(problem);\n });\n const grounds = pages.grounds === undefined ? [] : typeof pages.grounds === 'string' ? [pages.grounds] : [...pages.grounds];\n grounds.forEach((path, index) => {\n const problem = pathProblem(`pages.grounds[${index}]`, path);\n if (problem) errors.push(problem);\n });\n const desktopWidths = input.desktopWidths?.length ? [...input.desktopWidths] : [...SITE_SYSTEM_DESKTOP_WIDTHS];\n for (const width of desktopWidths) {\n if (!Number.isInteger(width) || width < 1024 || width > 3840) errors.push(`desktopWidths must be whole pixel widths from 1024 to 3840 (got ${width})`);\n }\n if (input.actionOrder !== undefined && input.actionOrder !== 'phone-first' && input.actionOrder !== 'quote-first') {\n errors.push(`actionOrder must be phone-first or quote-first (got ${JSON.stringify(input.actionOrder)})`);\n }\n for (const key of ['navigationTimeoutMs', 'settleTimeoutMs', 'maxTabStops'] as const) {\n const value = input[key];\n if (value !== undefined && (!Number.isInteger(value) || value <= 0)) errors.push(`${key} must be a positive whole number (got ${value})`);\n }\n if (input.release !== undefined && (typeof input.release !== 'string' || !/^\\d+\\.\\d+\\.\\d+(?:-canary\\.\\d+)?$/.test(input.release))) {\n errors.push(`release must be a version such as 3.9.0 or 3.15.0-canary.2 (got ${JSON.stringify(input.release)})`);\n }\n if (input.navName !== undefined && (typeof input.navName !== 'string' || !input.navName.trim())) errors.push('navName must be a non-empty string');\n if (errors.length > 0) throw new TypeError(`defineBrandlabSiteSystemTests: ${errors.join('; ')}`);\n\n const tier = input.tier as SiteSystemTier;\n const release = input.release ?? BRANDLAB_CURRENT_RUNTIME_RELEASE.releaseVersion;\n const journeys = siteSystemJourneysFor(tier, release);\n const problems: SiteSystemJourneyPlan['problems'] = {};\n if (journeys.includes('C1') && money.length === 0) {\n problems.C1 = 'pages.money names no money page: C1 checks the first screen of each service page with the enquiry form';\n }\n if (journeys.includes('W9') && families.length === 0) {\n problems.W9 = 'pages.families names no page: W9 checks the URL variants of one built page per dynamic route family';\n }\n const quoteName = input.quoteName === undefined\n ? SITE_SYSTEM_QUOTE_NAME\n : input.quoteName instanceof RegExp\n ? input.quoteName\n : new RegExp(`^\\\\s*${input.quoteName.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\\\\s*$`, 'i');\n return {\n tier,\n release,\n journeys,\n home: pages.home,\n money,\n contact: pages.contact,\n families: [...new Set(families)],\n sampled: [...new Set([pages.home, ...money, ...(pages.contact ? [pages.contact] : [])])],\n grounds: [...new Set([pages.home, ...money, ...(pages.contact ? [pages.contact] : []), ...families, ...grounds])],\n desktopWidths,\n actionOrder: input.actionOrder ?? 'phone-first',\n quoteName,\n navName: input.navName ?? 'Main',\n menuName: input.menuName ?? 'Menu',\n navigationTimeoutMs: input.navigationTimeoutMs ?? 45_000,\n settleTimeoutMs: input.settleTimeoutMs ?? 10_000,\n maxTabStops: input.maxTabStops ?? 400,\n problems,\n };\n}\n"]}
|
|
@@ -16,7 +16,10 @@ import { type FullContext } from "./common.js";
|
|
|
16
16
|
import type { EstatePage, ManifestData } from "./estate.js";
|
|
17
17
|
/** The families that carry a manifest (site-core BRANDLAB_PAGE_FAMILIES without the contact page). */
|
|
18
18
|
export declare const K12_FAMILIES: readonly ["home", "service", "service-in-suburb", "region", "suburb", "cost-guide", "services-hub", "locations-hub", "projects-hub", "project", "gallery", "reviews", "about", "faqs", "guides-hub", "guide", "council", "emergency"];
|
|
19
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* As site-core's isDataBackedSkipReason: the section's own data is absent, its content is in the hero checklist, or
|
|
21
|
+
* (3.18.0) the nearby suburbs are the area map's place list.
|
|
22
|
+
*/
|
|
20
23
|
export declare function isDataBackedReason(reason: string): boolean;
|
|
21
24
|
export declare function manifestProblems(page: EstatePage, manifest: ManifestData, context: FullContext): string[];
|
|
22
25
|
export declare function checkK12(context: FullContext): SiteSystemFinding[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"k12-manifests.d.ts","sourceRoot":"","sources":["../../../../src/site-system/rules/full/k12-manifests.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAyD,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AACtG,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE5D,sGAAsG;AACtG,eAAO,MAAM,YAAY,uOAmBf,CAAC;AAEX
|
|
1
|
+
{"version":3,"file":"k12-manifests.d.ts","sourceRoot":"","sources":["../../../../src/site-system/rules/full/k12-manifests.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAyD,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AACtG,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE5D,sGAAsG;AACtG,eAAO,MAAM,YAAY,uOAmBf,CAAC;AAEX;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE1D;AAMD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,GAAG,MAAM,EAAE,CAyEzG;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,iBAAiB,EAAE,CAoClE"}
|
|
@@ -20,9 +20,12 @@ export const K12_FAMILIES = [
|
|
|
20
20
|
"council",
|
|
21
21
|
"emergency",
|
|
22
22
|
];
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* As site-core's isDataBackedSkipReason: the section's own data is absent, its content is in the hero checklist, or
|
|
25
|
+
* (3.18.0) the nearby suburbs are the area map's place list.
|
|
26
|
+
*/
|
|
24
27
|
export function isDataBackedReason(reason) {
|
|
25
|
-
return reason === "merge-into-hero-checklist" || /^no-[a-z0-9]+(?:-[a-z0-9]+)*$/.test(reason);
|
|
28
|
+
return reason === "merge-into-hero-checklist" || reason === "merge-into-area-map" || /^no-[a-z0-9]+(?:-[a-z0-9]+)*$/.test(reason);
|
|
26
29
|
}
|
|
27
30
|
function sameList(left, right) {
|
|
28
31
|
return left.length === right.length && left.every((item, index) => item === right[index]);
|
|
@@ -82,6 +85,13 @@ export function manifestProblems(page, manifest, context) {
|
|
|
82
85
|
problems.push(`${where} renders the sections ${page.sections.join(", ") || "(none)"}, but its manifest lists ${listed.join(", ") || "(none)"}.`);
|
|
83
86
|
}
|
|
84
87
|
const renderedIds = new Set(manifest.rendered.map((entry) => entry.id));
|
|
88
|
+
// merge-into-area-map (3.18.0): only the nearby suburbs merge, and only into an area map the page renders.
|
|
89
|
+
for (const skip of manifest.skipped.filter((item) => item.reason === "merge-into-area-map")) {
|
|
90
|
+
if (skip.id !== "nearby-areas")
|
|
91
|
+
problems.push(`${where} gives "${skip.id}" the reason merge-into-area-map; only nearby-areas merges into the area map.`);
|
|
92
|
+
else if (!renderedIds.has("area-map"))
|
|
93
|
+
problems.push(`${where} merges its nearby suburbs into the area map, but renders no area map.`);
|
|
94
|
+
}
|
|
85
95
|
for (const entry of manifest.planned) {
|
|
86
96
|
if (entry.requirement !== "R" && entry.requirement !== "C")
|
|
87
97
|
continue;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"k12-manifests.js","sourceRoot":"","sources":["../../../../src/site-system/rules/full/k12-manifests.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * K12 on every family (Site System v2 §3.3, §13.2): each page of a family carries one section manifest\n * (`<script type=\"application/json\" data-bl-manifest>`, written by SectionSequence). Every required section renders\n * or is skipped with a reason drawn from its data (`no-…`), never the sequencer's `not-provided`, `cap` or\n * `duplicate`; every conditional section that does not render says its data is absent; the planned order is the\n * family's canonical one or the alternative recorded in strategy.ts; and the page renders exactly the sections the\n * manifest lists, in that order. A page over its cap (`cap-exceeded`) is a warning, not a failure. The contact page\n * has its own check (K12-contact).\n *\n * 3.16.0: signature sections take the place the site declares, so they are left out of the order walk (an `after`\n * must name a planned section; K13 checks the rest). An optional or recommended section with data that drops for the\n * cap is a warning, so a clean gate still shows when the site's content was cut.\n */\nimport type { SiteSystemFinding } from \"../../checks.js\";\nimport { fail, listOf, notApplicable, outcome, plural, warning, type FullContext } from \"./common.js\";\nimport type { EstatePage, ManifestData } from \"./estate.js\";\n\n/** The families that carry a manifest (site-core BRANDLAB_PAGE_FAMILIES without the contact page). */\nexport const K12_FAMILIES = [\n \"home\",\n \"service\",\n \"service-in-suburb\",\n \"region\",\n \"suburb\",\n \"cost-guide\",\n \"services-hub\",\n \"locations-hub\",\n \"projects-hub\",\n \"project\",\n \"gallery\",\n \"reviews\",\n \"about\",\n \"faqs\",\n \"guides-hub\",\n \"guide\",\n \"council\",\n \"emergency\",\n] as const;\n\n/** As site-core's isDataBackedSkipReason: the section's own data is absent, or its content is in the hero checklist. */\nexport function isDataBackedReason(reason: string): boolean {\n return reason === \"merge-into-hero-checklist\" || /^no-[a-z0-9]+(?:-[a-z0-9]+)*$/.test(reason);\n}\n\nfunction sameList(left: readonly string[], right: readonly string[]): boolean {\n return left.length === right.length && left.every((item, index) => item === right[index]);\n}\n\nexport function manifestProblems(page: EstatePage, manifest: ManifestData, context: FullContext): string[] {\n const problems: string[] = [];\n const where = page.path;\n const planned = manifest.planned.map((entry) => entry.id);\n\n if (!(K12_FAMILIES as readonly string[]).includes(manifest.family)) {\n return [`The manifest on ${where} names \"${manifest.family}\", which is not a page family that carries one.`];\n }\n if (manifest.order === \"recorded\") {\n const recorded = context.strategy.recordedOrders.get(manifest.family);\n if (!recorded) problems.push(`The manifest on ${where} says its order is recorded, but strategy.ts records no order for ${manifest.family} pages.`);\n else if (!sameList(planned, recorded)) problems.push(`The sections planned on ${where} (${planned.join(\", \")}) are not the order recorded for ${manifest.family} pages (${recorded.join(\", \")}).`);\n }\n const canonical = typeof context.defaultOrder === \"string\" ? undefined : context.defaultOrder(manifest.family, context.strategy.trade);\n if (canonical) {\n const ids = canonical.entries.map((entry) => entry.id);\n if (manifest.order !== \"recorded\" && !sameList(planned, ids)) {\n problems.push(`The sections planned on ${where} (${planned.join(\", \")}) are not the canonical order for ${manifest.family} pages (${ids.join(\", \")}).`);\n }\n // Each planned section keeps the requirement the family gives it, whatever the order.\n const requirementOf = new Map(canonical.entries.map((entry) => [entry.id, entry.requirement]));\n for (const entry of manifest.planned) {\n const expected = requirementOf.get(entry.id);\n if (expected !== undefined && expected !== entry.requirement) {\n problems.push(`The manifest on ${where} marks \"${entry.id}\" as ${entry.requirement}; on ${manifest.family} pages it is ${expected}.`);\n }\n }\n if (manifest.cap !== canonical.cap) problems.push(`The manifest on ${where} gives a cap of ${manifest.cap}; ${manifest.family} pages have a cap of ${canonical.cap}.`);\n }\n if (manifest.flags.includes(\"cap-exceeded\") !== manifest.counted > manifest.cap) {\n problems.push(`The manifest on ${where} counts ${manifest.counted} sections against a cap of ${manifest.cap} but ${manifest.flags.includes(\"cap-exceeded\") ? \"flags\" : \"does not flag\"} cap-exceeded.`);\n }\n\n // What renders follows the plan, and the page shows exactly what the manifest lists.\n let position = -1;\n for (const entry of manifest.rendered) {\n if (entry.id === \"signature\") {\n if (entry.after !== undefined && !planned.includes(entry.after)) {\n problems.push(`The manifest on ${where} places the signature \"${entry.signature ?? \"\"}\" after \"${entry.after}\", which is not a planned section.`);\n }\n continue;\n }\n const index = planned.indexOf(entry.id, position + 1);\n if (index === -1) {\n problems.push(`The manifest on ${where} lists \"${entry.id}\" as rendered out of its planned place.`);\n break;\n }\n position = index;\n }\n const listed = manifest.rendered.map((entry) => entry.section);\n if (!sameList(page.sections, listed)) {\n problems.push(`${where} renders the sections ${page.sections.join(\", \") || \"(none)\"}, but its manifest lists ${listed.join(\", \") || \"(none)\"}.`);\n }\n\n const renderedIds = new Set(manifest.rendered.map((entry) => entry.id));\n for (const entry of manifest.planned) {\n if (entry.requirement !== \"R\" && entry.requirement !== \"C\") continue;\n if (renderedIds.has(entry.id)) continue;\n const reasons = manifest.skipped.filter((skip) => skip.id === entry.id).map((skip) => skip.reason);\n if (reasons.some(isDataBackedReason)) continue;\n const reason = reasons[0] ?? \"no reason recorded\";\n problems.push(\n entry.requirement === \"R\"\n ? `${where} skips its required \"${entry.id}\" section without a reason drawn from its data (${reason}).`\n : `${where} leaves out its conditional \"${entry.id}\" section without saying its data is absent (${reason}).`,\n );\n }\n return problems;\n}\n\nexport function checkK12(context: FullContext): SiteSystemFinding[] {\n const failures: SiteSystemFinding[] = [];\n let checked = 0;\n if (typeof context.defaultOrder === \"string\") {\n failures.push(fail(\"K12\", undefined, `The canonical section orders could not be loaded (${context.defaultOrder}), so default orders were not compared.`));\n }\n for (const problem of context.strategy.problems.orders) failures.push(fail(\"K12\", \"src/data/strategy.ts\", problem));\n for (const page of context.estate.pages) {\n if (!(K12_FAMILIES as readonly string[]).includes(page.family ?? \"\")) continue;\n checked += 1;\n const state = page.manifest;\n if (state.kind === \"none\") {\n failures.push(fail(\"K12\", page.path, `${page.path} is a ${page.family} page with no section manifest; its sections go through SectionSequence.`));\n continue;\n }\n if (state.kind === \"many\") {\n failures.push(fail(\"K12\", page.path, `${page.path} carries ${state.count} section manifests; a page has one.`));\n continue;\n }\n if (state.kind === \"invalid\") {\n failures.push(fail(\"K12\", page.path, `The section manifest on ${page.path} ${state.reason}.`));\n continue;\n }\n for (const problem of manifestProblems(page, state.manifest, context)) failures.push(fail(\"K12\", page.path, problem));\n for (const skip of state.manifest.skipped) {\n if (skip.reason === \"cap\" && (skip.requirement === \"O\" || skip.requirement === \"Rec\")) {\n failures.push(warning(\"K12\", page.path, `${page.path} drops its ${skip.requirement === \"O\" ? \"optional\" : \"recommended\"} \"${skip.section}\" section for the cap of ${state.manifest.cap}, although its data is there.`));\n }\n }\n if (state.manifest.flags.includes(\"cap-exceeded\")) {\n failures.push(warning(\"K12\", page.path, `${page.path} renders ${state.manifest.counted} sections against a cap of ${state.manifest.cap}, because its required and conditional sections all have data.`));\n }\n }\n if (checked === 0) return [...failures, notApplicable(\"K12\", \"No page of a family that carries a section manifest was found.\")];\n const families = [...new Set(context.estate.pages.flatMap((page) => ((K12_FAMILIES as readonly string[]).includes(page.family ?? \"\") ? [page.family!] : [])))];\n return outcome(\"K12\", failures, `${plural(checked, \"page\")} across ${listOf(families)} carry a section manifest with every required and conditional section accounted for, in the canonical or recorded order.`);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"k12-manifests.js","sourceRoot":"","sources":["../../../../src/site-system/rules/full/k12-manifests.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * K12 on every family (Site System v2 §3.3, §13.2): each page of a family carries one section manifest\n * (`<script type=\"application/json\" data-bl-manifest>`, written by SectionSequence). Every required section renders\n * or is skipped with a reason drawn from its data (`no-…`), never the sequencer's `not-provided`, `cap` or\n * `duplicate`; every conditional section that does not render says its data is absent; the planned order is the\n * family's canonical one or the alternative recorded in strategy.ts; and the page renders exactly the sections the\n * manifest lists, in that order. A page over its cap (`cap-exceeded`) is a warning, not a failure. The contact page\n * has its own check (K12-contact).\n *\n * 3.16.0: signature sections take the place the site declares, so they are left out of the order walk (an `after`\n * must name a planned section; K13 checks the rest). An optional or recommended section with data that drops for the\n * cap is a warning, so a clean gate still shows when the site's content was cut.\n */\nimport type { SiteSystemFinding } from \"../../checks.js\";\nimport { fail, listOf, notApplicable, outcome, plural, warning, type FullContext } from \"./common.js\";\nimport type { EstatePage, ManifestData } from \"./estate.js\";\n\n/** The families that carry a manifest (site-core BRANDLAB_PAGE_FAMILIES without the contact page). */\nexport const K12_FAMILIES = [\n \"home\",\n \"service\",\n \"service-in-suburb\",\n \"region\",\n \"suburb\",\n \"cost-guide\",\n \"services-hub\",\n \"locations-hub\",\n \"projects-hub\",\n \"project\",\n \"gallery\",\n \"reviews\",\n \"about\",\n \"faqs\",\n \"guides-hub\",\n \"guide\",\n \"council\",\n \"emergency\",\n] as const;\n\n/**\n * As site-core's isDataBackedSkipReason: the section's own data is absent, its content is in the hero checklist, or\n * (3.18.0) the nearby suburbs are the area map's place list.\n */\nexport function isDataBackedReason(reason: string): boolean {\n return reason === \"merge-into-hero-checklist\" || reason === \"merge-into-area-map\" || /^no-[a-z0-9]+(?:-[a-z0-9]+)*$/.test(reason);\n}\n\nfunction sameList(left: readonly string[], right: readonly string[]): boolean {\n return left.length === right.length && left.every((item, index) => item === right[index]);\n}\n\nexport function manifestProblems(page: EstatePage, manifest: ManifestData, context: FullContext): string[] {\n const problems: string[] = [];\n const where = page.path;\n const planned = manifest.planned.map((entry) => entry.id);\n\n if (!(K12_FAMILIES as readonly string[]).includes(manifest.family)) {\n return [`The manifest on ${where} names \"${manifest.family}\", which is not a page family that carries one.`];\n }\n if (manifest.order === \"recorded\") {\n const recorded = context.strategy.recordedOrders.get(manifest.family);\n if (!recorded) problems.push(`The manifest on ${where} says its order is recorded, but strategy.ts records no order for ${manifest.family} pages.`);\n else if (!sameList(planned, recorded)) problems.push(`The sections planned on ${where} (${planned.join(\", \")}) are not the order recorded for ${manifest.family} pages (${recorded.join(\", \")}).`);\n }\n const canonical = typeof context.defaultOrder === \"string\" ? undefined : context.defaultOrder(manifest.family, context.strategy.trade);\n if (canonical) {\n const ids = canonical.entries.map((entry) => entry.id);\n if (manifest.order !== \"recorded\" && !sameList(planned, ids)) {\n problems.push(`The sections planned on ${where} (${planned.join(\", \")}) are not the canonical order for ${manifest.family} pages (${ids.join(\", \")}).`);\n }\n // Each planned section keeps the requirement the family gives it, whatever the order.\n const requirementOf = new Map(canonical.entries.map((entry) => [entry.id, entry.requirement]));\n for (const entry of manifest.planned) {\n const expected = requirementOf.get(entry.id);\n if (expected !== undefined && expected !== entry.requirement) {\n problems.push(`The manifest on ${where} marks \"${entry.id}\" as ${entry.requirement}; on ${manifest.family} pages it is ${expected}.`);\n }\n }\n if (manifest.cap !== canonical.cap) problems.push(`The manifest on ${where} gives a cap of ${manifest.cap}; ${manifest.family} pages have a cap of ${canonical.cap}.`);\n }\n if (manifest.flags.includes(\"cap-exceeded\") !== manifest.counted > manifest.cap) {\n problems.push(`The manifest on ${where} counts ${manifest.counted} sections against a cap of ${manifest.cap} but ${manifest.flags.includes(\"cap-exceeded\") ? \"flags\" : \"does not flag\"} cap-exceeded.`);\n }\n\n // What renders follows the plan, and the page shows exactly what the manifest lists.\n let position = -1;\n for (const entry of manifest.rendered) {\n if (entry.id === \"signature\") {\n if (entry.after !== undefined && !planned.includes(entry.after)) {\n problems.push(`The manifest on ${where} places the signature \"${entry.signature ?? \"\"}\" after \"${entry.after}\", which is not a planned section.`);\n }\n continue;\n }\n const index = planned.indexOf(entry.id, position + 1);\n if (index === -1) {\n problems.push(`The manifest on ${where} lists \"${entry.id}\" as rendered out of its planned place.`);\n break;\n }\n position = index;\n }\n const listed = manifest.rendered.map((entry) => entry.section);\n if (!sameList(page.sections, listed)) {\n problems.push(`${where} renders the sections ${page.sections.join(\", \") || \"(none)\"}, but its manifest lists ${listed.join(\", \") || \"(none)\"}.`);\n }\n\n const renderedIds = new Set(manifest.rendered.map((entry) => entry.id));\n // merge-into-area-map (3.18.0): only the nearby suburbs merge, and only into an area map the page renders.\n for (const skip of manifest.skipped.filter((item) => item.reason === \"merge-into-area-map\")) {\n if (skip.id !== \"nearby-areas\") problems.push(`${where} gives \"${skip.id}\" the reason merge-into-area-map; only nearby-areas merges into the area map.`);\n else if (!renderedIds.has(\"area-map\")) problems.push(`${where} merges its nearby suburbs into the area map, but renders no area map.`);\n }\n for (const entry of manifest.planned) {\n if (entry.requirement !== \"R\" && entry.requirement !== \"C\") continue;\n if (renderedIds.has(entry.id)) continue;\n const reasons = manifest.skipped.filter((skip) => skip.id === entry.id).map((skip) => skip.reason);\n if (reasons.some(isDataBackedReason)) continue;\n const reason = reasons[0] ?? \"no reason recorded\";\n problems.push(\n entry.requirement === \"R\"\n ? `${where} skips its required \"${entry.id}\" section without a reason drawn from its data (${reason}).`\n : `${where} leaves out its conditional \"${entry.id}\" section without saying its data is absent (${reason}).`,\n );\n }\n return problems;\n}\n\nexport function checkK12(context: FullContext): SiteSystemFinding[] {\n const failures: SiteSystemFinding[] = [];\n let checked = 0;\n if (typeof context.defaultOrder === \"string\") {\n failures.push(fail(\"K12\", undefined, `The canonical section orders could not be loaded (${context.defaultOrder}), so default orders were not compared.`));\n }\n for (const problem of context.strategy.problems.orders) failures.push(fail(\"K12\", \"src/data/strategy.ts\", problem));\n for (const page of context.estate.pages) {\n if (!(K12_FAMILIES as readonly string[]).includes(page.family ?? \"\")) continue;\n checked += 1;\n const state = page.manifest;\n if (state.kind === \"none\") {\n failures.push(fail(\"K12\", page.path, `${page.path} is a ${page.family} page with no section manifest; its sections go through SectionSequence.`));\n continue;\n }\n if (state.kind === \"many\") {\n failures.push(fail(\"K12\", page.path, `${page.path} carries ${state.count} section manifests; a page has one.`));\n continue;\n }\n if (state.kind === \"invalid\") {\n failures.push(fail(\"K12\", page.path, `The section manifest on ${page.path} ${state.reason}.`));\n continue;\n }\n for (const problem of manifestProblems(page, state.manifest, context)) failures.push(fail(\"K12\", page.path, problem));\n for (const skip of state.manifest.skipped) {\n if (skip.reason === \"cap\" && (skip.requirement === \"O\" || skip.requirement === \"Rec\")) {\n failures.push(warning(\"K12\", page.path, `${page.path} drops its ${skip.requirement === \"O\" ? \"optional\" : \"recommended\"} \"${skip.section}\" section for the cap of ${state.manifest.cap}, although its data is there.`));\n }\n }\n if (state.manifest.flags.includes(\"cap-exceeded\")) {\n failures.push(warning(\"K12\", page.path, `${page.path} renders ${state.manifest.counted} sections against a cap of ${state.manifest.cap}, because its required and conditional sections all have data.`));\n }\n }\n if (checked === 0) return [...failures, notApplicable(\"K12\", \"No page of a family that carries a section manifest was found.\")];\n const families = [...new Set(context.estate.pages.flatMap((page) => ((K12_FAMILIES as readonly string[]).includes(page.family ?? \"\") ? [page.family!] : [])))];\n return outcome(\"K12\", failures, `${plural(checked, \"page\")} across ${listOf(families)} carry a section manifest with every required and conditional section accounted for, in the canonical or recorded order.`);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"budgets.d.ts","sourceRoot":"","sources":["../../../../src/site-system/rules/shell/budgets.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EACqC,KAAK,gBAAgB,EAAE,KAAK,YAAY,EACnF,MAAM,YAAY,CAAC;AAEpB;;;;;GAKG;AAEH,iHAAiH;AACjH,eAAO,MAAM,iCAAiC,QAAa,CAAC;AAC5D,yFAAyF;AACzF,eAAO,MAAM,iCAAiC,QAAa,CAAC;AAC5D,eAAO,MAAM,iBAAiB,QAAa,CAAC;AAC5C,eAAO,MAAM,uBAAuB,QAAa,CAAC;AAClD,sDAAsD;AACtD,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAExC,KAAK,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,aAAa,CAAC;AA6CnE,UAAU,OAAO;IACf,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,GAAG,IAAI,CAaxD;AAeD;;;GAGG;AACH,eAAO,MAAM,mBAAmB,iCAAiC,CAAC;AAUlE;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"budgets.d.ts","sourceRoot":"","sources":["../../../../src/site-system/rules/shell/budgets.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EACqC,KAAK,gBAAgB,EAAE,KAAK,YAAY,EACnF,MAAM,YAAY,CAAC;AAEpB;;;;;GAKG;AAEH,iHAAiH;AACjH,eAAO,MAAM,iCAAiC,QAAa,CAAC;AAC5D,yFAAyF;AACzF,eAAO,MAAM,iCAAiC,QAAa,CAAC;AAC5D,eAAO,MAAM,iBAAiB,QAAa,CAAC;AAC5C,eAAO,MAAM,uBAAuB,QAAa,CAAC;AAClD,sDAAsD;AACtD,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAExC,KAAK,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,aAAa,CAAC;AA6CnE,UAAU,OAAO;IACf,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,GAAG,IAAI,CAaxD;AAeD;;;GAGG;AACH,eAAO,MAAM,mBAAmB,iCAAiC,CAAC;AAUlE;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,gBAgC5B,CAAC;AAgFF,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,oBAAoB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,SAAS,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AAED,iCAAiC;AACjC,wBAAsB,eAAe,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAqFlH"}
|
|
@@ -125,7 +125,8 @@ export const readBuiltAsset = async (url, { projectRoot, baseUrl }) => {
|
|
|
125
125
|
if (!given || !/^https?:$/.test(url.protocol))
|
|
126
126
|
return undefined;
|
|
127
127
|
try {
|
|
128
|
-
|
|
128
|
+
// A browser asks for WebP, and Next's optimiser answers in the format asked for (3.18.0).
|
|
129
|
+
const response = await fetch(url, { headers: { accept: "image/webp,image/*;q=0.8" }, signal: AbortSignal.timeout(15_000) });
|
|
129
130
|
return response.ok ? new Uint8Array(await response.arrayBuffer()) : undefined;
|
|
130
131
|
}
|
|
131
132
|
catch {
|
|
@@ -182,15 +183,18 @@ function srcsetCandidates(srcset) {
|
|
|
182
183
|
return srcset.split(",").map((part) => part.trim().split(/\s+/)).filter((parts) => parts[0])
|
|
183
184
|
.map(([url, descriptor]) => ({ url: url, width: descriptor?.endsWith("w") ? Number.parseInt(descriptor, 10) : descriptor?.endsWith("x") ? Number.parseFloat(descriptor) * 1000 : 0 }));
|
|
184
185
|
}
|
|
186
|
+
/** Below this rendered width an image is an avatar, icon or badge, never the hero's photo (3.18.0). */
|
|
187
|
+
const B1_HERO_MIN_IMAGE_PX = 160;
|
|
185
188
|
/** The image the hero shows on a wide screen: the smallest candidate at least 1440 px wide, else the widest. */
|
|
186
189
|
function heroImage(page) {
|
|
187
190
|
const hero = page.hero;
|
|
188
191
|
if (!hero)
|
|
189
192
|
return null;
|
|
190
|
-
const
|
|
193
|
+
const width = (image) => Number.parseInt(image.attrs.width ?? "0", 10) || 0;
|
|
194
|
+
const images = findAll(hero, (element) => element.tag === "img" && !page.headers.some((header) => isWithin(element, header)) && element.attrs["data-bl"] !== "logo")
|
|
195
|
+
.filter((image) => image.attrs.fetchpriority === "high" || width(image) === 0 || width(image) >= B1_HERO_MIN_IMAGE_PX);
|
|
191
196
|
if (images.length === 0)
|
|
192
197
|
return null;
|
|
193
|
-
const width = (image) => Number.parseInt(image.attrs.width ?? "0", 10) || 0;
|
|
194
198
|
const element = images.find((image) => image.attrs.fetchpriority === "high") ?? images.reduce((best, image) => (width(image) > width(best) ? image : best), images[0]);
|
|
195
199
|
const candidates = srcsetCandidates(element.attrs.srcset ?? "");
|
|
196
200
|
const wide = candidates.filter((candidate) => candidate.width >= B1_HERO_VIEWPORT_PX).sort((left, right) => left.width - right.width)[0]
|