@brandlab-digital/conformance 3.3.3 → 3.5.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/engineering.d.ts.map +1 -1
- package/dist/engineering.js +3 -1
- package/dist/engineering.js.map +1 -1
- package/dist/estate.d.ts +38 -1
- package/dist/estate.d.ts.map +1 -1
- package/dist/estate.js +201 -6
- package/dist/estate.js.map +1 -1
- package/dist/families-e2e.d.ts +21 -0
- package/dist/families-e2e.d.ts.map +1 -1
- package/dist/families-e2e.js +69 -1
- package/dist/families-e2e.js.map +1 -1
- package/dist/page-standard.d.ts +198 -0
- package/dist/page-standard.d.ts.map +1 -0
- package/dist/page-standard.js +536 -0
- package/dist/page-standard.js.map +1 -0
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +14 -0
- package/dist/project.js.map +1 -1
- package/dist/rule-registry.d.ts +10 -0
- package/dist/rule-registry.d.ts.map +1 -1
- package/dist/rule-registry.js +2 -0
- package/dist/rule-registry.js.map +1 -1
- package/package.json +2 -1
package/dist/families-e2e.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"families-e2e.js","sourceRoot":"","sources":["../src/families-e2e.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The shared page-family journey for a Brandlab production build: one page per\n * app route, at 390 and 1440 pixels wide, must render without sideways\n * scrolling, uncaught page errors or Content Security Policy violations.\n *\n * // tests/e2e/families.spec.ts\n * import { defineBrandlabFamiliesTests } from '@brandlab-digital/conformance/families-e2e'\n * import { routes } from '../../src/data/routes'\n *\n * defineBrandlabFamiliesTests({ routes })\n *\n * The app routes come from the build's `.next/app-path-routes-manifest.json`,\n * so run `next build` first. Each app route's page is the first catalogue path\n * Next routes to it; an app route with no page fails the run until `samples`\n * names one or `skip` gives the reason it has none (fail closed). Every other\n * request leaves the browser only as a GET or HEAD to the build under test.\n *\n * A page is checked once its document has loaded (DOMContentLoaded) and the\n * network has settled, or after a capped settle wait: images the build generates\n * for the first time under load are not a failure. A navigation that times out\n * is retried once; any other navigation failure, a wrong status, a redirect, a\n * missing policy, a page error or a CSP violation fails the check at once.\n */\nimport { readFileSync } from 'node:fs';\nimport { isAbsolute, join } from 'node:path';\nimport { errors, expect, test, type Page, type Response } from '@playwright/test';\nimport { isolateFromNetwork } from './e2e-support.js';\n\nexport interface BrandlabFamiliesTestOptions {\n /** The route catalogue; each app route's page is the first path Next routes to it. */\n routes: readonly { path: string }[];\n /** Pages for app routes the catalogue does not list, keyed by app route (for example `'/quote'`). */\n samples?: Readonly<Record<string, string>>;\n /** App routes with no page to check, each with the reason. */\n skip?: Readonly<Record<string, string>>;\n /** The production build directory, relative to the working directory (default `.next`). */\n buildDir?: string;\n /** Viewport widths (default 390 and 1440). */\n widths?: readonly number[];\n /** How long a document may take to load (DOMContentLoaded), default 45 seconds; a timeout is retried once. */\n navigationTimeoutMs?: number;\n /** How long to wait for the network to settle before checking, default 10 seconds; a busy network is not a failure. */\n settleTimeoutMs?: number;\n}\n\nexport interface BrandlabFamilyPage {\n /** The app route, for example `/services/[slug]`. */\n appRoute: string;\n /** The page checked for it. */\n path: string;\n /** 200, or 404 for the not-found page. */\n status: 200 | 404;\n}\n\nexport const BRANDLAB_FAMILIES_WIDTHS = Object.freeze([390, 1440]);\nconst NOT_FOUND_APP_ROUTE = '/_not-found';\nconst NOT_FOUND_PROBE = '/brandlab-families-unknown-page';\nconst INTERNAL_APP_ROUTES = new Set(['/_global-error']);\nconst VIEWPORT_HEIGHTS: Readonly<Record<number, number>> = { 390: 844, 1440: 900 };\nconst NAVIGATION_TIMEOUT_MS = 45_000;\nconst SETTLE_TIMEOUT_MS = 10_000;\nconst FONTS_TIMEOUT_MS = 5_000;\n\ntype Segment =\n | { kind: 'static'; value: string }\n | { kind: 'dynamic' }\n | { kind: 'catch-all' }\n | { kind: 'optional-catch-all' };\n\nconst SEGMENT_RANK = { static: 0, dynamic: 1, 'catch-all': 2, 'optional-catch-all': 3 } as const;\n\nfunction parseAppRoute(appRoute: string): Segment[] {\n return appRoute.split('/').filter(Boolean).map((part): Segment => {\n if (/^\\[\\[\\.\\.\\.[^\\]]+\\]\\]$/.test(part)) return { kind: 'optional-catch-all' };\n if (/^\\[\\.\\.\\.[^\\]]+\\]$/.test(part)) return { kind: 'catch-all' };\n if (/^\\[[^\\]]+\\]$/.test(part)) return { kind: 'dynamic' };\n return { kind: 'static', value: part };\n });\n}\n\nfunction matches(segments: readonly Segment[], parts: readonly string[]): boolean {\n const [segment, ...rest] = segments;\n if (!segment) return parts.length === 0;\n if (segment.kind === 'static') return parts[0] === segment.value && matches(rest, parts.slice(1));\n if (segment.kind === 'dynamic') return parts.length > 0 && matches(rest, parts.slice(1));\n // Next allows a catch-all only as the final segment.\n return segment.kind === 'catch-all' ? parts.length > 0 : true;\n}\n\nfunction specificity(segments: readonly Segment[]): number[] {\n return segments.map((segment) => SEGMENT_RANK[segment.kind]);\n}\n\nfunction compareSpecificity(left: readonly number[], right: readonly number[]): number {\n for (let index = 0; index < Math.max(left.length, right.length); index += 1) {\n const difference = (left[index] ?? -1) - (right[index] ?? -1);\n if (difference !== 0) return difference;\n }\n return 0;\n}\n\n/** Page app routes from `app-path-routes-manifest.json`, without Next's internal error pages. */\nexport function appPageRoutes(manifest: Readonly<Record<string, string>>): string[] {\n const routes = Object.entries(manifest)\n .filter(([entry]) => entry === '/page' || entry.endsWith('/page'))\n .map(([, appRoute]) => appRoute)\n .filter((appRoute) => !INTERNAL_APP_ROUTES.has(appRoute))\n // Intercepting and parallel-slot routes have no URL of their own.\n .filter((appRoute) => !/\\/(?:@|\\(\\.{1,3}\\))/.test(appRoute));\n return [...new Set(routes)].sort();\n}\n\n/** The app route Next serves a path from, by Next's precedence: static, then dynamic, then catch-all. */\nexport function resolveAppRoute(appRoutes: readonly string[], path: string): string | undefined {\n const parts = path.split(/[?#]/, 1)[0]!.split('/').filter(Boolean);\n const candidates = appRoutes\n .filter((appRoute) => appRoute !== NOT_FOUND_APP_ROUTE)\n .map((appRoute) => ({ appRoute, segments: parseAppRoute(appRoute) }))\n .filter(({ segments }) => matches(segments, parts))\n .sort((left, right) => compareSpecificity(specificity(left.segments), specificity(right.segments)));\n return candidates[0]?.appRoute;\n}\n\n/** One page per app route, and every reason the plan cannot cover the build. */\nexport function planBrandlabFamilyPages(input: {\n manifest: Readonly<Record<string, string>>;\n routes: readonly { path: string }[];\n samples?: Readonly<Record<string, string>>;\n skip?: Readonly<Record<string, string>>;\n}): { pages: BrandlabFamilyPage[]; problems: string[] } {\n const appRoutes = appPageRoutes(input.manifest);\n const known = new Set(appRoutes);\n const problems: string[] = [];\n const chosen = new Map<string, string>();\n for (const [appRoute, reason] of Object.entries(input.skip ?? {})) {\n if (!known.has(appRoute)) problems.push(`skip names ${appRoute}, which is not an app route of this build`);\n if (typeof reason !== 'string' || !reason.trim()) problems.push(`skip for ${appRoute} gives no reason`);\n }\n for (const [appRoute, path] of Object.entries(input.samples ?? {})) {\n if (!known.has(appRoute)) {\n problems.push(`samples names ${appRoute}, which is not an app route of this build`);\n continue;\n }\n const served = resolveAppRoute(appRoutes, path);\n if (appRoute !== NOT_FOUND_APP_ROUTE && served !== appRoute) {\n problems.push(`the sample ${path} for ${appRoute} is served by ${served ?? 'no app route'}`);\n continue;\n }\n chosen.set(appRoute, path);\n }\n for (const route of input.routes) {\n const appRoute = resolveAppRoute(appRoutes, route.path);\n if (appRoute && !chosen.has(appRoute)) chosen.set(appRoute, route.path);\n }\n if (known.has(NOT_FOUND_APP_ROUTE) && !chosen.has(NOT_FOUND_APP_ROUTE)) chosen.set(NOT_FOUND_APP_ROUTE, NOT_FOUND_PROBE);\n const pages: BrandlabFamilyPage[] = [];\n for (const appRoute of appRoutes) {\n if (input.skip && Object.hasOwn(input.skip, appRoute)) continue;\n const path = chosen.get(appRoute);\n if (!path) {\n problems.push(`${appRoute} has no page to check: list one in the catalogue or samples, or skip it with a reason`);\n continue;\n }\n pages.push({ appRoute, path, status: appRoute === NOT_FOUND_APP_ROUTE ? 404 : 200 });\n }\n if (appRoutes.length === 0) problems.push('the build has no app pages');\n return { pages, problems };\n}\n\nfunction readManifest(buildDir: string): { manifest?: Record<string, string>; problem?: string } {\n const directory = isAbsolute(buildDir) ? buildDir : join(process.cwd(), buildDir);\n const file = join(directory, 'app-path-routes-manifest.json');\n try {\n const parsed = JSON.parse(readFileSync(file, 'utf8')) as unknown;\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return { problem: `${file} is not an app route manifest` };\n return { manifest: parsed as Record<string, string> };\n } catch {\n return { problem: `${file} is missing or unreadable: run next build before the families spec` };\n }\n}\n\n/**\n * Open a page for the family checks: wait for its document, then for the network to\n * settle within the cap. A navigation timeout is retried once, because a first\n * request under load can outlast the limit while the build renders the page or\n * generates its images; every other navigation error is thrown at once.\n */\nasync function openBrandlabFamilyPage(\n page: Page,\n path: string,\n options: { navigationTimeoutMs?: number; settleTimeoutMs?: number; note?: (note: string) => void } = {},\n): Promise<Response | null> {\n const navigationTimeout = options.navigationTimeoutMs ?? NAVIGATION_TIMEOUT_MS;\n const settleTimeout = options.settleTimeoutMs ?? SETTLE_TIMEOUT_MS;\n let response: Response | null;\n try {\n response = await page.goto(path, { waitUntil: 'domcontentloaded', timeout: navigationTimeout });\n } catch (error) {\n if (!(error instanceof errors.TimeoutError)) throw error;\n options.note?.(`${path}: the first navigation timed out after ${navigationTimeout} ms; retried once`);\n response = await page.goto(path, { waitUntil: 'domcontentloaded', timeout: navigationTimeout });\n }\n try {\n await page.waitForLoadState('networkidle', { timeout: settleTimeout });\n } catch (error) {\n if (!(error instanceof errors.TimeoutError)) throw error;\n options.note?.(`${path}: the network was still busy ${settleTimeout} ms after the document loaded (images may still be generating); checked the rendered page`);\n }\n return response;\n}\n\nexport function defineBrandlabFamiliesTests(options: BrandlabFamiliesTestOptions) {\n const widths = options.widths?.length ? options.widths : BRANDLAB_FAMILIES_WIDTHS;\n const navigationTimeoutMs = options.navigationTimeoutMs ?? NAVIGATION_TIMEOUT_MS;\n const settleTimeoutMs = options.settleTimeoutMs ?? SETTLE_TIMEOUT_MS;\n // Room for a retried navigation, the settle wait and the checks, unless the project allows more.\n const testBudget = 2 * navigationTimeoutMs + settleTimeoutMs + FONTS_TIMEOUT_MS + 30_000;\n const { manifest, problem } = readManifest(options.buildDir ?? '.next');\n const plan = manifest\n ? planBrandlabFamilyPages({ manifest, routes: options.routes, samples: options.samples, skip: options.skip })\n : { pages: [], problems: [problem!] };\n\n test.describe('Brandlab page families', () => {\n // Service workers could answer requests outside page and context routing.\n test.use({ serviceWorkers: 'block' });\n\n test('every app route has a page to check', () => {\n expect(plan.problems).toEqual([]);\n });\n\n for (const page of plan.pages) {\n for (const width of widths) {\n test(`${page.appRoute} renders cleanly at ${width}px (${page.path})`, async ({ page: browserPage, baseURL }, testInfo) => {\n if (testInfo.timeout !== 0 && testInfo.timeout < testBudget) testInfo.setTimeout(testBudget);\n await isolateFromNetwork(browserPage, { baseURL, googleTag: 'stub' });\n const problems: string[] = [];\n browserPage.on('pageerror', (error) => problems.push(`page error: ${error.message}`));\n browserPage.on('console', (message) => {\n if (message.type() === 'error' && /Content Security Policy/i.test(message.text())) {\n problems.push(`CSP: ${message.text()}`);\n }\n });\n await browserPage.exposeFunction('__brandlabRecordCspViolation', (violation: string) => {\n problems.push(`CSP violation: ${violation}`);\n });\n await browserPage.addInitScript(() => {\n document.addEventListener('securitypolicyviolation', (event) => {\n void (window as unknown as { __brandlabRecordCspViolation: (value: string) => Promise<void> })\n .__brandlabRecordCspViolation(`${event.effectiveDirective} blocked ${event.blockedURI || 'inline code'}`);\n }, true);\n });\n await browserPage.setViewportSize({ width, height: VIEWPORT_HEIGHTS[width] ?? 900 });\n\n const response = await openBrandlabFamilyPage(browserPage, page.path, {\n navigationTimeoutMs,\n settleTimeoutMs,\n note: (description) => testInfo.annotations.push({ type: 'brandlab-families', description }),\n });\n expect(response, `${page.path} did not answer`).not.toBeNull();\n expect(response!.request().redirectedFrom()?.url() ?? null, `${page.path} redirects`).toBeNull();\n expect(response!.status(), `${page.path} status`).toBe(page.status);\n const headers = response!.headers();\n expect(\n Boolean(headers['content-security-policy'] || headers['content-security-policy-report-only']),\n `${page.path} is served without a Content-Security-Policy`,\n ).toBe(true);\n\n await browserPage.evaluate(async (timeout) => {\n await Promise.race([document.fonts?.ready, new Promise((resolve) => setTimeout(resolve, timeout))]);\n }, FONTS_TIMEOUT_MS);\n await browserPage.waitForTimeout(300);\n const sideways = await browserPage.evaluate(() => {\n const root = document.scrollingElement ?? document.documentElement;\n const top = window.scrollY;\n window.scrollTo({ left: root.scrollWidth, top, behavior: 'instant' });\n const scrolled = window.scrollX;\n window.scrollTo({ left: 0, top, behavior: 'instant' });\n return { scrolled, scrollWidth: root.scrollWidth, viewport: window.innerWidth };\n });\n if (sideways.scrolled > 0) {\n problems.push(`scrolls sideways by ${sideways.scrolled}px: the page is ${sideways.scrollWidth}px wide in a ${sideways.viewport}px viewport`);\n }\n expect(problems, `${page.path} at ${width}px`).toEqual([]);\n });\n }\n }\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"families-e2e.js","sourceRoot":"","sources":["../src/families-e2e.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAA4B,MAAM,kBAAkB,CAAC;AAClF,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AA4BtD,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;AACnE,MAAM,mBAAmB,GAAG,aAAa,CAAC;AAC1C,MAAM,eAAe,GAAG,iCAAiC,CAAC;AAC1D,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;AACxD,MAAM,gBAAgB,GAAqC,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;AACnF,MAAM,qBAAqB,GAAG,MAAM,CAAC;AACrC,MAAM,iBAAiB,GAAG,MAAM,CAAC;AACjC,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAQ/B,MAAM,YAAY,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,oBAAoB,EAAE,CAAC,EAAW,CAAC;AAEjG,SAAS,aAAa,CAAC,QAAgB;IACrC,OAAO,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAW,EAAE;QAC/D,IAAI,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC;QAC/E,IAAI,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;QAClE,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QAC1D,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACzC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,OAAO,CAAC,QAA4B,EAAE,KAAwB;IACrE,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,QAAQ,CAAC;IACpC,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;IACxC,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAClG,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACzF,qDAAqD;IACrD,OAAO,OAAO,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAChE,CAAC;AAED,SAAS,WAAW,CAAC,QAA4B;IAC/C,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAuB,EAAE,KAAwB;IAC3E,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC5E,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9D,IAAI,UAAU,KAAK,CAAC;YAAE,OAAO,UAAU,CAAC;IAC1C,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,aAAa,CAAC,QAA0C;IACtE,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;SACpC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,OAAO,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;SACjE,GAAG,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC;SAC/B,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACzD,kEAAkE;SACjE,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,qBAAqB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC/D,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AACrC,CAAC;AAED,yGAAyG;AACzG,MAAM,UAAU,eAAe,CAAC,SAA4B,EAAE,IAAY;IACxE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACnE,MAAM,UAAU,GAAG,SAAS;SACzB,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,KAAK,mBAAmB,CAAC;SACtD,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;SACpE,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;SAClD,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,kBAAkB,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACtG,OAAO,UAAU,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC;AACjC,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,uBAAuB,CAAC,KAKvC;IACC,MAAM,SAAS,GAAG,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;IACjC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,KAAK,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,CAAC;QAClE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,cAAc,QAAQ,2CAA2C,CAAC,CAAC;QAC3G,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;YAAE,QAAQ,CAAC,IAAI,CAAC,YAAY,QAAQ,kBAAkB,CAAC,CAAC;IAC1G,CAAC;IACD,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;QACnE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,QAAQ,CAAC,IAAI,CAAC,iBAAiB,QAAQ,2CAA2C,CAAC,CAAC;YACpF,SAAS;QACX,CAAC;QACD,MAAM,MAAM,GAAG,eAAe,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAChD,IAAI,QAAQ,KAAK,mBAAmB,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC5D,QAAQ,CAAC,IAAI,CAAC,cAAc,IAAI,QAAQ,QAAQ,iBAAiB,MAAM,IAAI,cAAc,EAAE,CAAC,CAAC;YAC7F,SAAS;QACX,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC7B,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAG,eAAe,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACxD,IAAI,QAAQ,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC;QAAE,MAAM,CAAC,GAAG,CAAC,mBAAmB,EAAE,eAAe,CAAC,CAAC;IACzH,MAAM,KAAK,GAAyB,EAAE,CAAC;IACvC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,KAAK,CAAC,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC;YAAE,SAAS;QAChE,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAClC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,QAAQ,CAAC,IAAI,CAAC,GAAG,QAAQ,uFAAuF,CAAC,CAAC;YAClH,SAAS;QACX,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,KAAK,mBAAmB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IACvF,CAAC;IACD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,QAAQ,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;IACxE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AAC7B,CAAC;AAED,SAAS,YAAY,CAAC,QAAgB;IACpC,MAAM,SAAS,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC;IAClF,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,+BAA+B,CAAC,CAAC;IAC9D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAY,CAAC;QACjE,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;YAAE,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,+BAA+B,EAAE,CAAC;QAC/H,OAAO,EAAE,QAAQ,EAAE,MAAgC,EAAE,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,oEAAoE,EAAE,CAAC;IAClG,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,sBAAsB,CACnC,IAAU,EACV,IAAY,EACZ,UAAqG,EAAE;IAEvG,MAAM,iBAAiB,GAAG,OAAO,CAAC,mBAAmB,IAAI,qBAAqB,CAAC;IAC/E,MAAM,aAAa,GAAG,OAAO,CAAC,eAAe,IAAI,iBAAiB,CAAC;IACnE,IAAI,QAAyB,CAAC;IAC9B,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,kBAAkB,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAClG,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,CAAC,KAAK,YAAY,MAAM,CAAC,YAAY,CAAC;YAAE,MAAM,KAAK,CAAC;QACzD,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,0CAA0C,iBAAiB,mBAAmB,CAAC,CAAC;QACtG,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,kBAAkB,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAClG,CAAC;IACD,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,gBAAgB,CAAC,aAAa,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC;IACzE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,CAAC,KAAK,YAAY,MAAM,CAAC,YAAY,CAAC;YAAE,MAAM,KAAK,CAAC;QACzD,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,gCAAgC,aAAa,2FAA2F,CAAC,CAAC;IAClK,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,2FAA2F;AAC3F,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC;AAWnC;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC;IAChC,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC;IAClC,IAAI,IAAI,GAAqD,IAAI,CAAC;IAClE,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,GAAG,KAAK,CAAC,qBAAqB,EAAE,CAAC;QAC3C,IAAI,IAAI,CAAC,GAAG,IAAI,MAAM,GAAG,CAAC;YAAE,SAAS;QACrC,MAAM,KAAK,GAAG,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAC7C,IAAI,KAAK,CAAC,UAAU,KAAK,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,SAAS;QAC3E,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACvF,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;QACzF,MAAM,IAAI,GAAG,YAAY,GAAG,aAAa,CAAC;QAC1C,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;YAAE,IAAI,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACtE,CAAC;IACD,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ;QAAE,OAAO,IAAI,CAAC;IAChE,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;IACvB,MAAM,GAAG,GAAG,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IAC5C,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,CAAC;IACjC,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,iCAAiC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;QACvG,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;QACpD,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,GAAG,IAAK,IAAwB,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,UAAU,KAAK,MAAM,CAAC,CAAC;IAC3I,CAAC,CAAC,CAAC;IACH,OAAO;QACL,GAAG,EAAE,OAAO,IAAI,GAAG;QACnB,OAAO,EAAE,KAAK,CAAC,YAAY,CAAC,SAAS,CAAC;QACtC,aAAa,EAAE,KAAK,CAAC,YAAY,CAAC,eAAe,CAAC;QAClD,SAAS;QACT,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG;KAC9D,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAA8B;IAC7D,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;QAC5B,OAAO,kBAAkB,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,2DAA2D,CAAC;IAChI,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,aAAa,EAAE,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;QACpE,OAAO,kBAAkB,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,0GAA0G,CAAC;IAC/K,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,OAAoC;IAC9E,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,wBAAwB,CAAC;IAClF,MAAM,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,IAAI,qBAAqB,CAAC;IACjF,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,iBAAiB,CAAC;IACrE,iGAAiG;IACjG,MAAM,UAAU,GAAG,CAAC,GAAG,mBAAmB,GAAG,eAAe,GAAG,gBAAgB,GAAG,MAAM,CAAC;IACzF,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,CAAC;IACxE,MAAM,IAAI,GAAG,QAAQ;QACnB,CAAC,CAAC,uBAAuB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;QAC7G,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,OAAQ,CAAC,EAAE,CAAC;IAExC,IAAI,CAAC,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAC3C,0EAA0E;QAC1E,IAAI,CAAC,GAAG,CAAC,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,CAAC;QAEtC,IAAI,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC/C,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,uBAAuB,KAAK,OAAO,IAAI,CAAC,IAAI,GAAG,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,EAAE;oBACvH,IAAI,QAAQ,CAAC,OAAO,KAAK,CAAC,IAAI,QAAQ,CAAC,OAAO,GAAG,UAAU;wBAAE,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;oBAC7F,MAAM,kBAAkB,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;oBACtE,MAAM,QAAQ,GAAa,EAAE,CAAC;oBAC9B,WAAW,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,eAAe,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;oBACtF,WAAW,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE;wBACpC,IAAI,OAAO,CAAC,IAAI,EAAE,KAAK,OAAO,IAAI,0BAA0B,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;4BAClF,QAAQ,CAAC,IAAI,CAAC,QAAQ,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;wBAC1C,CAAC;oBACH,CAAC,CAAC,CAAC;oBACH,MAAM,WAAW,CAAC,cAAc,CAAC,8BAA8B,EAAE,CAAC,SAAiB,EAAE,EAAE;wBACrF,QAAQ,CAAC,IAAI,CAAC,kBAAkB,SAAS,EAAE,CAAC,CAAC;oBAC/C,CAAC,CAAC,CAAC;oBACH,MAAM,WAAW,CAAC,aAAa,CAAC,GAAG,EAAE;wBACnC,QAAQ,CAAC,gBAAgB,CAAC,yBAAyB,EAAE,CAAC,KAAK,EAAE,EAAE;4BAC7D,KAAM,MAAwF;iCAC3F,4BAA4B,CAAC,GAAG,KAAK,CAAC,kBAAkB,YAAY,KAAK,CAAC,UAAU,IAAI,aAAa,EAAE,CAAC,CAAC;wBAC9G,CAAC,EAAE,IAAI,CAAC,CAAC;oBACX,CAAC,CAAC,CAAC;oBACH,MAAM,WAAW,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,CAAC,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;oBAErF,MAAM,QAAQ,GAAG,MAAM,sBAAsB,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,EAAE;wBACpE,mBAAmB;wBACnB,eAAe;wBACf,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,WAAW,EAAE,CAAC;qBAC7F,CAAC,CAAC;oBACH,MAAM,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,IAAI,iBAAiB,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;oBAC/D,MAAM,CAAC,QAAS,CAAC,OAAO,EAAE,CAAC,cAAc,EAAE,EAAE,GAAG,EAAE,IAAI,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC;oBACjG,MAAM,CAAC,QAAS,CAAC,MAAM,EAAE,EAAE,GAAG,IAAI,CAAC,IAAI,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oBACpE,MAAM,OAAO,GAAG,QAAS,CAAC,OAAO,EAAE,CAAC;oBACpC,MAAM,CACJ,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,IAAI,OAAO,CAAC,qCAAqC,CAAC,CAAC,EAC7F,GAAG,IAAI,CAAC,IAAI,8CAA8C,CAC3D,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAEb,MAAM,WAAW,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;wBAC3C,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;oBACtG,CAAC,EAAE,gBAAgB,CAAC,CAAC;oBACrB,MAAM,WAAW,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;oBACtC,IAAI,IAAI,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;wBACxB,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC;wBACvE,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;wBACvC,IAAI,OAAO;4BAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBACtC,CAAC;oBACD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,GAAG,EAAE;wBAC/C,MAAM,IAAI,GAAG,QAAQ,CAAC,gBAAgB,IAAI,QAAQ,CAAC,eAAe,CAAC;wBACnE,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC;wBAC3B,MAAM,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;wBACtE,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC;wBAChC,MAAM,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;wBACvD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC;oBAClF,CAAC,CAAC,CAAC;oBACH,IAAI,QAAQ,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;wBAC1B,QAAQ,CAAC,IAAI,CAAC,uBAAuB,QAAQ,CAAC,QAAQ,mBAAmB,QAAQ,CAAC,WAAW,gBAAgB,QAAQ,CAAC,QAAQ,aAAa,CAAC,CAAC;oBAC/I,CAAC;oBACD,MAAM,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBAC7D,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["/**\n * The shared page-family journey for a Brandlab production build: one page per\n * app route, at 390 and 1440 pixels wide, must render without sideways\n * scrolling, uncaught page errors or Content Security Policy violations.\n *\n * // tests/e2e/families.spec.ts\n * import { defineBrandlabFamiliesTests } from '@brandlab-digital/conformance/families-e2e'\n * import { routes } from '../../src/data/routes'\n *\n * defineBrandlabFamiliesTests({ routes })\n *\n * The app routes come from the build's `.next/app-path-routes-manifest.json`,\n * so run `next build` first. Each app route's page is the first catalogue path\n * Next routes to it; an app route with no page fails the run until `samples`\n * names one or `skip` gives the reason it has none (fail closed). Every other\n * request leaves the browser only as a GET or HEAD to the build under test.\n *\n * A page is checked once its document has loaded (DOMContentLoaded) and the\n * network has settled, or after a capped settle wait: images the build generates\n * for the first time under load are not a failure. From 3.4.0 the hero image\n * (the largest image covering at least 15% of the first screen) must not be\n * lazy-loaded and must be preloaded or fetched with high priority. An image\n * counts as the hero when it starts in the top half of the first screen and\n * covers at least 15% of it. A navigation that times out\n * is retried once; any other navigation failure, a wrong status, a redirect, a\n * missing policy, a page error or a CSP violation fails the check at once.\n */\nimport { readFileSync } from 'node:fs';\nimport { isAbsolute, join } from 'node:path';\nimport { errors, expect, test, type Page, type Response } from '@playwright/test';\nimport { isolateFromNetwork } from './e2e-support.js';\n\nexport interface BrandlabFamiliesTestOptions {\n /** The route catalogue; each app route's page is the first path Next routes to it. */\n routes: readonly { path: string }[];\n /** Pages for app routes the catalogue does not list, keyed by app route (for example `'/quote'`). */\n samples?: Readonly<Record<string, string>>;\n /** App routes with no page to check, each with the reason. */\n skip?: Readonly<Record<string, string>>;\n /** The production build directory, relative to the working directory (default `.next`). */\n buildDir?: string;\n /** Viewport widths (default 390 and 1440). */\n widths?: readonly number[];\n /** How long a document may take to load (DOMContentLoaded), default 45 seconds; a timeout is retried once. */\n navigationTimeoutMs?: number;\n /** How long to wait for the network to settle before checking, default 10 seconds; a busy network is not a failure. */\n settleTimeoutMs?: number;\n}\n\nexport interface BrandlabFamilyPage {\n /** The app route, for example `/services/[slug]`. */\n appRoute: string;\n /** The page checked for it. */\n path: string;\n /** 200, or 404 for the not-found page. */\n status: 200 | 404;\n}\n\nexport const BRANDLAB_FAMILIES_WIDTHS = Object.freeze([390, 1440]);\nconst NOT_FOUND_APP_ROUTE = '/_not-found';\nconst NOT_FOUND_PROBE = '/brandlab-families-unknown-page';\nconst INTERNAL_APP_ROUTES = new Set(['/_global-error']);\nconst VIEWPORT_HEIGHTS: Readonly<Record<number, number>> = { 390: 844, 1440: 900 };\nconst NAVIGATION_TIMEOUT_MS = 45_000;\nconst SETTLE_TIMEOUT_MS = 10_000;\nconst FONTS_TIMEOUT_MS = 5_000;\n\ntype Segment =\n | { kind: 'static'; value: string }\n | { kind: 'dynamic' }\n | { kind: 'catch-all' }\n | { kind: 'optional-catch-all' };\n\nconst SEGMENT_RANK = { static: 0, dynamic: 1, 'catch-all': 2, 'optional-catch-all': 3 } as const;\n\nfunction parseAppRoute(appRoute: string): Segment[] {\n return appRoute.split('/').filter(Boolean).map((part): Segment => {\n if (/^\\[\\[\\.\\.\\.[^\\]]+\\]\\]$/.test(part)) return { kind: 'optional-catch-all' };\n if (/^\\[\\.\\.\\.[^\\]]+\\]$/.test(part)) return { kind: 'catch-all' };\n if (/^\\[[^\\]]+\\]$/.test(part)) return { kind: 'dynamic' };\n return { kind: 'static', value: part };\n });\n}\n\nfunction matches(segments: readonly Segment[], parts: readonly string[]): boolean {\n const [segment, ...rest] = segments;\n if (!segment) return parts.length === 0;\n if (segment.kind === 'static') return parts[0] === segment.value && matches(rest, parts.slice(1));\n if (segment.kind === 'dynamic') return parts.length > 0 && matches(rest, parts.slice(1));\n // Next allows a catch-all only as the final segment.\n return segment.kind === 'catch-all' ? parts.length > 0 : true;\n}\n\nfunction specificity(segments: readonly Segment[]): number[] {\n return segments.map((segment) => SEGMENT_RANK[segment.kind]);\n}\n\nfunction compareSpecificity(left: readonly number[], right: readonly number[]): number {\n for (let index = 0; index < Math.max(left.length, right.length); index += 1) {\n const difference = (left[index] ?? -1) - (right[index] ?? -1);\n if (difference !== 0) return difference;\n }\n return 0;\n}\n\n/** Page app routes from `app-path-routes-manifest.json`, without Next's internal error pages. */\nexport function appPageRoutes(manifest: Readonly<Record<string, string>>): string[] {\n const routes = Object.entries(manifest)\n .filter(([entry]) => entry === '/page' || entry.endsWith('/page'))\n .map(([, appRoute]) => appRoute)\n .filter((appRoute) => !INTERNAL_APP_ROUTES.has(appRoute))\n // Intercepting and parallel-slot routes have no URL of their own.\n .filter((appRoute) => !/\\/(?:@|\\(\\.{1,3}\\))/.test(appRoute));\n return [...new Set(routes)].sort();\n}\n\n/** The app route Next serves a path from, by Next's precedence: static, then dynamic, then catch-all. */\nexport function resolveAppRoute(appRoutes: readonly string[], path: string): string | undefined {\n const parts = path.split(/[?#]/, 1)[0]!.split('/').filter(Boolean);\n const candidates = appRoutes\n .filter((appRoute) => appRoute !== NOT_FOUND_APP_ROUTE)\n .map((appRoute) => ({ appRoute, segments: parseAppRoute(appRoute) }))\n .filter(({ segments }) => matches(segments, parts))\n .sort((left, right) => compareSpecificity(specificity(left.segments), specificity(right.segments)));\n return candidates[0]?.appRoute;\n}\n\n/** One page per app route, and every reason the plan cannot cover the build. */\nexport function planBrandlabFamilyPages(input: {\n manifest: Readonly<Record<string, string>>;\n routes: readonly { path: string }[];\n samples?: Readonly<Record<string, string>>;\n skip?: Readonly<Record<string, string>>;\n}): { pages: BrandlabFamilyPage[]; problems: string[] } {\n const appRoutes = appPageRoutes(input.manifest);\n const known = new Set(appRoutes);\n const problems: string[] = [];\n const chosen = new Map<string, string>();\n for (const [appRoute, reason] of Object.entries(input.skip ?? {})) {\n if (!known.has(appRoute)) problems.push(`skip names ${appRoute}, which is not an app route of this build`);\n if (typeof reason !== 'string' || !reason.trim()) problems.push(`skip for ${appRoute} gives no reason`);\n }\n for (const [appRoute, path] of Object.entries(input.samples ?? {})) {\n if (!known.has(appRoute)) {\n problems.push(`samples names ${appRoute}, which is not an app route of this build`);\n continue;\n }\n const served = resolveAppRoute(appRoutes, path);\n if (appRoute !== NOT_FOUND_APP_ROUTE && served !== appRoute) {\n problems.push(`the sample ${path} for ${appRoute} is served by ${served ?? 'no app route'}`);\n continue;\n }\n chosen.set(appRoute, path);\n }\n for (const route of input.routes) {\n const appRoute = resolveAppRoute(appRoutes, route.path);\n if (appRoute && !chosen.has(appRoute)) chosen.set(appRoute, route.path);\n }\n if (known.has(NOT_FOUND_APP_ROUTE) && !chosen.has(NOT_FOUND_APP_ROUTE)) chosen.set(NOT_FOUND_APP_ROUTE, NOT_FOUND_PROBE);\n const pages: BrandlabFamilyPage[] = [];\n for (const appRoute of appRoutes) {\n if (input.skip && Object.hasOwn(input.skip, appRoute)) continue;\n const path = chosen.get(appRoute);\n if (!path) {\n problems.push(`${appRoute} has no page to check: list one in the catalogue or samples, or skip it with a reason`);\n continue;\n }\n pages.push({ appRoute, path, status: appRoute === NOT_FOUND_APP_ROUTE ? 404 : 200 });\n }\n if (appRoutes.length === 0) problems.push('the build has no app pages');\n return { pages, problems };\n}\n\nfunction readManifest(buildDir: string): { manifest?: Record<string, string>; problem?: string } {\n const directory = isAbsolute(buildDir) ? buildDir : join(process.cwd(), buildDir);\n const file = join(directory, 'app-path-routes-manifest.json');\n try {\n const parsed = JSON.parse(readFileSync(file, 'utf8')) as unknown;\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return { problem: `${file} is not an app route manifest` };\n return { manifest: parsed as Record<string, string> };\n } catch {\n return { problem: `${file} is missing or unreadable: run next build before the families spec` };\n }\n}\n\n/**\n * Open a page for the family checks: wait for its document, then for the network to\n * settle within the cap. A navigation timeout is retried once, because a first\n * request under load can outlast the limit while the build renders the page or\n * generates its images; every other navigation error is thrown at once.\n */\nasync function openBrandlabFamilyPage(\n page: Page,\n path: string,\n options: { navigationTimeoutMs?: number; settleTimeoutMs?: number; note?: (note: string) => void } = {},\n): Promise<Response | null> {\n const navigationTimeout = options.navigationTimeoutMs ?? NAVIGATION_TIMEOUT_MS;\n const settleTimeout = options.settleTimeoutMs ?? SETTLE_TIMEOUT_MS;\n let response: Response | null;\n try {\n response = await page.goto(path, { waitUntil: 'domcontentloaded', timeout: navigationTimeout });\n } catch (error) {\n if (!(error instanceof errors.TimeoutError)) throw error;\n options.note?.(`${path}: the first navigation timed out after ${navigationTimeout} ms; retried once`);\n response = await page.goto(path, { waitUntil: 'domcontentloaded', timeout: navigationTimeout });\n }\n try {\n await page.waitForLoadState('networkidle', { timeout: settleTimeout });\n } catch (error) {\n if (!(error instanceof errors.TimeoutError)) throw error;\n options.note?.(`${path}: the network was still busy ${settleTimeout} ms after the document loaded (images may still be generating); checked the rendered page`);\n }\n return response;\n}\n\n/** The share of the first screen an image must cover to count as the page's hero image. */\nexport const HERO_MIN_SHARE = 0.15;\n\nexport interface BrandlabHeroImage {\n src: string;\n loading: string | null;\n fetchPriority: string | null;\n preloaded: boolean;\n /** Share of the first screen the image covers. */\n share: number;\n}\n\n/**\n * Runs in the page: the largest image that starts in the top half of the first\n * screen, when it covers at least `minShare` of that screen, with how the page\n * loads it. Card images further down a listing are not the hero.\n */\nexport function findHeroImage(minShare: number): BrandlabHeroImage | null {\n const width = window.innerWidth;\n const height = window.innerHeight;\n let best: { image: HTMLImageElement; area: number } | null = null;\n for (const image of Array.from(document.images)) {\n const rect = image.getBoundingClientRect();\n if (rect.top >= height / 2) continue;\n const style = window.getComputedStyle(image);\n if (style.visibility === 'hidden' || Number(style.opacity) === 0) continue;\n const visibleWidth = Math.max(0, Math.min(rect.right, width) - Math.max(rect.left, 0));\n const visibleHeight = Math.max(0, Math.min(rect.bottom, height) - Math.max(rect.top, 0));\n const area = visibleWidth * visibleHeight;\n if (area > 0 && (!best || area > best.area)) best = { image, area };\n }\n if (!best || best.area < width * height * minShare) return null;\n const { image } = best;\n const src = image.getAttribute('src') ?? '';\n const srcset = image.getAttribute('srcset');\n const current = image.currentSrc;\n const preloaded = Array.from(document.querySelectorAll('link[rel=\"preload\"][as=\"image\"]')).some((link) => {\n const href = link.getAttribute('href');\n const linkSrcset = link.getAttribute('imagesrcset');\n return (Boolean(href) && (href === src || (link as HTMLLinkElement).href === current)) || (Boolean(linkSrcset) && linkSrcset === srcset);\n });\n return {\n src: current || src,\n loading: image.getAttribute('loading'),\n fetchPriority: image.getAttribute('fetchpriority'),\n preloaded,\n share: Math.round((best.area / (width * height)) * 100) / 100,\n };\n}\n\n/**\n * The hero image must start loading with the document: never `loading=\"lazy\"`,\n * and preloaded (`<Image preload>`) or fetched with high priority.\n */\nexport function heroImageProblem(hero: BrandlabHeroImage | null): string | null {\n if (!hero) return null;\n if (hero.loading === 'lazy') {\n return `the hero image ${hero.src} (${Math.round(hero.share * 100)}% of the first screen) is lazy-loaded; preload it instead`;\n }\n if (!hero.preloaded && hero.fetchPriority?.toLowerCase() !== 'high') {\n return `the hero image ${hero.src} (${Math.round(hero.share * 100)}% of the first screen) is neither preloaded nor fetched with high priority; give it next/image's preload`;\n }\n return null;\n}\n\nexport function defineBrandlabFamiliesTests(options: BrandlabFamiliesTestOptions) {\n const widths = options.widths?.length ? options.widths : BRANDLAB_FAMILIES_WIDTHS;\n const navigationTimeoutMs = options.navigationTimeoutMs ?? NAVIGATION_TIMEOUT_MS;\n const settleTimeoutMs = options.settleTimeoutMs ?? SETTLE_TIMEOUT_MS;\n // Room for a retried navigation, the settle wait and the checks, unless the project allows more.\n const testBudget = 2 * navigationTimeoutMs + settleTimeoutMs + FONTS_TIMEOUT_MS + 30_000;\n const { manifest, problem } = readManifest(options.buildDir ?? '.next');\n const plan = manifest\n ? planBrandlabFamilyPages({ manifest, routes: options.routes, samples: options.samples, skip: options.skip })\n : { pages: [], problems: [problem!] };\n\n test.describe('Brandlab page families', () => {\n // Service workers could answer requests outside page and context routing.\n test.use({ serviceWorkers: 'block' });\n\n test('every app route has a page to check', () => {\n expect(plan.problems).toEqual([]);\n });\n\n for (const page of plan.pages) {\n for (const width of widths) {\n test(`${page.appRoute} renders cleanly at ${width}px (${page.path})`, async ({ page: browserPage, baseURL }, testInfo) => {\n if (testInfo.timeout !== 0 && testInfo.timeout < testBudget) testInfo.setTimeout(testBudget);\n await isolateFromNetwork(browserPage, { baseURL, googleTag: 'stub' });\n const problems: string[] = [];\n browserPage.on('pageerror', (error) => problems.push(`page error: ${error.message}`));\n browserPage.on('console', (message) => {\n if (message.type() === 'error' && /Content Security Policy/i.test(message.text())) {\n problems.push(`CSP: ${message.text()}`);\n }\n });\n await browserPage.exposeFunction('__brandlabRecordCspViolation', (violation: string) => {\n problems.push(`CSP violation: ${violation}`);\n });\n await browserPage.addInitScript(() => {\n document.addEventListener('securitypolicyviolation', (event) => {\n void (window as unknown as { __brandlabRecordCspViolation: (value: string) => Promise<void> })\n .__brandlabRecordCspViolation(`${event.effectiveDirective} blocked ${event.blockedURI || 'inline code'}`);\n }, true);\n });\n await browserPage.setViewportSize({ width, height: VIEWPORT_HEIGHTS[width] ?? 900 });\n\n const response = await openBrandlabFamilyPage(browserPage, page.path, {\n navigationTimeoutMs,\n settleTimeoutMs,\n note: (description) => testInfo.annotations.push({ type: 'brandlab-families', description }),\n });\n expect(response, `${page.path} did not answer`).not.toBeNull();\n expect(response!.request().redirectedFrom()?.url() ?? null, `${page.path} redirects`).toBeNull();\n expect(response!.status(), `${page.path} status`).toBe(page.status);\n const headers = response!.headers();\n expect(\n Boolean(headers['content-security-policy'] || headers['content-security-policy-report-only']),\n `${page.path} is served without a Content-Security-Policy`,\n ).toBe(true);\n\n await browserPage.evaluate(async (timeout) => {\n await Promise.race([document.fonts?.ready, new Promise((resolve) => setTimeout(resolve, timeout))]);\n }, FONTS_TIMEOUT_MS);\n await browserPage.waitForTimeout(300);\n if (page.status === 200) {\n const hero = await browserPage.evaluate(findHeroImage, HERO_MIN_SHARE);\n const problem = heroImageProblem(hero);\n if (problem) problems.push(problem);\n }\n const sideways = await browserPage.evaluate(() => {\n const root = document.scrollingElement ?? document.documentElement;\n const top = window.scrollY;\n window.scrollTo({ left: root.scrollWidth, top, behavior: 'instant' });\n const scrolled = window.scrollX;\n window.scrollTo({ left: 0, top, behavior: 'instant' });\n return { scrolled, scrollWidth: root.scrollWidth, viewport: window.innerWidth };\n });\n if (sideways.scrolled > 0) {\n problems.push(`scrolls sideways by ${sideways.scrolled}px: the page is ${sideways.scrollWidth}px wide in a ${sideways.viewport}px viewport`);\n }\n expect(problems, `${page.path} at ${width}px`).toEqual([]);\n });\n }\n }\n });\n}\n"]}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Brandlab on-page and location standard (3.4.0) as pure checks over the
|
|
3
|
+
* server HTML of a production build. The estate journey enforces the objective
|
|
4
|
+
* ones; the page-quality journey reports the judgement ones without failing.
|
|
5
|
+
*
|
|
6
|
+
* Every function reads only the HTML a crawler receives before any script runs.
|
|
7
|
+
*/
|
|
8
|
+
/** A suburb's centre in GDA2020 degrees (site-core/geography's nswSuburbCentres). */
|
|
9
|
+
export interface SuburbCentre {
|
|
10
|
+
latitude: number;
|
|
11
|
+
longitude: number;
|
|
12
|
+
}
|
|
13
|
+
export type SuburbCentreLookup = (slug: string) => SuburbCentre | undefined;
|
|
14
|
+
/** Great-circle distance in kilometres, as site-core's distanceBetweenCentresKm. */
|
|
15
|
+
export declare function distanceBetweenCentresKm(from: SuburbCentre, to: SuburbCentre): number;
|
|
16
|
+
/** The first place listed after a farther one, as site-core's findNeighbourOrderProblem. */
|
|
17
|
+
export declare function findNeighbourOrderProblem(origin: string, slugs: readonly string[], centreOf: SuburbCentreLookup, toleranceKm?: number): {
|
|
18
|
+
index: number;
|
|
19
|
+
slug: string;
|
|
20
|
+
previous: string;
|
|
21
|
+
detail: string;
|
|
22
|
+
} | null;
|
|
23
|
+
export type BrandlabSitemapFamily = 'core' | 'services' | 'locations' | 'service-locations' | 'blog' | 'projects';
|
|
24
|
+
/** The split sitemap family of a route kind, as site-core's sitemapFamilyForKind. */
|
|
25
|
+
export declare function sitemapFamilyForKind(kind: string): BrandlabSitemapFamily;
|
|
26
|
+
export interface LocationPolicyRoute {
|
|
27
|
+
id?: string;
|
|
28
|
+
path: string;
|
|
29
|
+
kind?: string;
|
|
30
|
+
indexing: string;
|
|
31
|
+
locationDecision?: {
|
|
32
|
+
evidence?: readonly string[];
|
|
33
|
+
review?: string;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/** A capacity recorded with site-core's defineLocationCapacity. */
|
|
37
|
+
export interface LocationCapacityRecord {
|
|
38
|
+
limit: number;
|
|
39
|
+
recordedAt: string;
|
|
40
|
+
indexableAtRecord: number;
|
|
41
|
+
approval?: {
|
|
42
|
+
approvedBy: string;
|
|
43
|
+
approvedAt: string;
|
|
44
|
+
reviewBy: string;
|
|
45
|
+
maxIndexable?: number;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/** As site-core's checkLocationCapacity: blocked only beyond both the limit and the pages at record (or the approval). */
|
|
49
|
+
export declare function checkLocationCapacity(routes: readonly LocationPolicyRoute[], capacity: LocationCapacityRecord | null | undefined): {
|
|
50
|
+
indexable: number;
|
|
51
|
+
limit: number | null;
|
|
52
|
+
allowed: number | null;
|
|
53
|
+
overCapacity: boolean;
|
|
54
|
+
blocked: boolean;
|
|
55
|
+
detail: string;
|
|
56
|
+
};
|
|
57
|
+
/** As site-core's buildLocationReviewList: indexable location pages without evidence or with an open review flag. */
|
|
58
|
+
export declare function buildLocationReviewList(routes: readonly LocationPolicyRoute[]): {
|
|
59
|
+
id?: string;
|
|
60
|
+
path: string;
|
|
61
|
+
evidence: readonly string[];
|
|
62
|
+
reasons: readonly string[];
|
|
63
|
+
}[];
|
|
64
|
+
export interface BrandlabGeography {
|
|
65
|
+
centreOf: SuburbCentreLookup;
|
|
66
|
+
/** Registry place names by slug: suburbs, localities, regions and sub-regions. */
|
|
67
|
+
placeNames: ReadonlyMap<string, string>;
|
|
68
|
+
/** Masks every registry place name and postcode. */
|
|
69
|
+
maskPlaces: (text: string) => string;
|
|
70
|
+
}
|
|
71
|
+
/** The suburb centres and place names of the site's installed site-core geography. */
|
|
72
|
+
export declare function loadBrandlabGeography(): Promise<BrandlabGeography>;
|
|
73
|
+
/** Types that describe the business itself; a rating on them is a self-serving rating. */
|
|
74
|
+
export declare const BUSINESS_SCHEMA_TYPES: Set<string>;
|
|
75
|
+
export interface StructuredDataCheckOptions {
|
|
76
|
+
origin: string;
|
|
77
|
+
/** The home route: it must carry a WebSite node naming the site and its URL. */
|
|
78
|
+
home: boolean;
|
|
79
|
+
/** The business node's @id (default `<origin>/#business`). */
|
|
80
|
+
businessId?: string | false;
|
|
81
|
+
/** The business facts record: the business node's name and telephone must match it. */
|
|
82
|
+
business?: {
|
|
83
|
+
name?: string;
|
|
84
|
+
telephone?: string;
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The structured-data rules a crawler can check on one page: no FAQPage or
|
|
89
|
+
* HowTo, no rating on the business itself, a WebSite node with name and url on
|
|
90
|
+
* the homepage, and the business name and telephone matching the facts record.
|
|
91
|
+
*/
|
|
92
|
+
export declare function structuredDataProblems(payloads: readonly unknown[], options: StructuredDataCheckOptions): string[];
|
|
93
|
+
export interface SitemapUrlEntry {
|
|
94
|
+
url: string;
|
|
95
|
+
lastmod?: string;
|
|
96
|
+
}
|
|
97
|
+
export interface SitemapFile {
|
|
98
|
+
path: string;
|
|
99
|
+
entries: readonly SitemapUrlEntry[];
|
|
100
|
+
}
|
|
101
|
+
export declare function parseSitemapEntries(xml: string): SitemapUrlEntry[];
|
|
102
|
+
export interface SitemapRoute {
|
|
103
|
+
path: string;
|
|
104
|
+
canonicalPath?: string;
|
|
105
|
+
kind?: string;
|
|
106
|
+
indexing: string;
|
|
107
|
+
lastSignificantChange?: string;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Whether the sitemap is split by page family (services, locations,
|
|
111
|
+
* service-in-suburb, blog, projects and the rest) once the catalogue's
|
|
112
|
+
* indexable pages span more than one family, each file holding one family.
|
|
113
|
+
*/
|
|
114
|
+
export declare function sitemapFamilyProblems(input: {
|
|
115
|
+
index: boolean;
|
|
116
|
+
files: readonly SitemapFile[];
|
|
117
|
+
routes: readonly SitemapRoute[];
|
|
118
|
+
origin: string;
|
|
119
|
+
}): string[];
|
|
120
|
+
/**
|
|
121
|
+
* `lastmod` must date the content, never the build: it equals the route's
|
|
122
|
+
* `lastSignificantChange` (and is absent without one), is never in the future,
|
|
123
|
+
* and pages do not share one fresh timestamp.
|
|
124
|
+
*/
|
|
125
|
+
export declare function sitemapLastmodProblems(entries: readonly SitemapUrlEntry[], routes: readonly SitemapRoute[], origin: string, now?: number): string[];
|
|
126
|
+
/** The page's main content: `<main>` when present, else the body. */
|
|
127
|
+
export declare function mainContent(html: string): string;
|
|
128
|
+
/**
|
|
129
|
+
* The links of the main content grouped by the list (or, outside a list, the
|
|
130
|
+
* nearest container) that holds them, in document order; links inside a
|
|
131
|
+
* header, footer or navigation block are left out.
|
|
132
|
+
*/
|
|
133
|
+
export declare function extractLinkGroups(html: string): string[][];
|
|
134
|
+
export interface NeighbourOrderInput {
|
|
135
|
+
html: string;
|
|
136
|
+
/** The page's own place slug. */
|
|
137
|
+
origin: string;
|
|
138
|
+
/** The page's absolute URL, which relative links resolve against. */
|
|
139
|
+
pageUrl: string;
|
|
140
|
+
/** The place slug a link's path names when it is a location page, else undefined. */
|
|
141
|
+
placeOf: (path: string) => string | undefined;
|
|
142
|
+
centreOf: SuburbCentreLookup;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Nearby lists on a location page must be ranked by distance: any list of 3 to
|
|
146
|
+
* 12 links to other places with a centre is checked; a directory longer than
|
|
147
|
+
* that is not a nearby list.
|
|
148
|
+
*/
|
|
149
|
+
export declare function neighbourOrderProblems(input: NeighbourOrderInput): string[];
|
|
150
|
+
/** The main content's text blocks (header, footer and navigation removed), lower-cased with whitespace collapsed. */
|
|
151
|
+
export declare function textBlocks(html: string): string[];
|
|
152
|
+
/** Masks place names and postcodes so name-swapped copy compares as the same text. */
|
|
153
|
+
export declare function createPlaceMask(names: readonly string[]): (text: string) => string;
|
|
154
|
+
export interface SimilarityPage {
|
|
155
|
+
path: string;
|
|
156
|
+
place: string;
|
|
157
|
+
/** Masked text blocks of the page's main content. */
|
|
158
|
+
blocks: readonly string[];
|
|
159
|
+
}
|
|
160
|
+
export interface SimilarityScore {
|
|
161
|
+
path: string;
|
|
162
|
+
/** Share of the page's five-word phrases also on its most similar near sibling: 0 nothing shared, 1 identical. */
|
|
163
|
+
score: number;
|
|
164
|
+
sibling: string | null;
|
|
165
|
+
/** Words of page-specific text left after shared blocks are removed. */
|
|
166
|
+
uniqueWords: number;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Centerpiece similarity: shared blocks (on half or more of the location pages)
|
|
170
|
+
* are removed, place names are masked, and each page's five-word phrases are
|
|
171
|
+
* compared with its three nearest siblings that have a centre. Pages without a
|
|
172
|
+
* centre are not scored.
|
|
173
|
+
*/
|
|
174
|
+
export declare function centerpieceSimilarity(pages: readonly SimilarityPage[], centreOf: SuburbCentreLookup, siblings?: number): SimilarityScore[];
|
|
175
|
+
/** Similarity at or above this is reported as a warning. */
|
|
176
|
+
export declare const SIMILARITY_WARN = 0.5;
|
|
177
|
+
/** Similarity at or above this puts the page on the review list; it stays indexed. */
|
|
178
|
+
export declare const SIMILARITY_REVIEW = 0.7;
|
|
179
|
+
export declare const TITLE_MAX_LENGTH = 60;
|
|
180
|
+
export declare const DESCRIPTION_MIN_LENGTH = 70;
|
|
181
|
+
export declare const DESCRIPTION_MAX_LENGTH = 170;
|
|
182
|
+
export declare const HTML_MAX_BYTES = 1048576;
|
|
183
|
+
/** Title format warnings: over 60 characters, more than one pipe, brackets, emoji, capitals or "near me". */
|
|
184
|
+
export declare function titleFormatProblems(title: string): string[];
|
|
185
|
+
/** The title's primary phrase: the part before its first separator. */
|
|
186
|
+
export declare function primaryTitlePhrase(title: string): string;
|
|
187
|
+
/**
|
|
188
|
+
* Whether the title and the H1 share the page's primary phrase: half or more of
|
|
189
|
+
* the title's primary words appear in the H1, and the page's place (when it has
|
|
190
|
+
* one) appears in both.
|
|
191
|
+
*/
|
|
192
|
+
export declare function titleHeadingProblems(title: string, h1: string, place?: string): string[];
|
|
193
|
+
export declare function descriptionLengthProblem(description: string): string | null;
|
|
194
|
+
/** The text of every H1 in the server HTML. */
|
|
195
|
+
export declare function headingTexts(html: string): string[];
|
|
196
|
+
export declare function normalisePath(path: string): string;
|
|
197
|
+
export declare function decodeXml(value: string): string;
|
|
198
|
+
//# sourceMappingURL=page-standard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-standard.d.ts","sourceRoot":"","sources":["../src/page-standard.ts"],"names":[],"mappings":"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"}
|