@ttt-productions/repo-guards 0.1.32 → 0.1.34

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.
@@ -15,6 +15,8 @@ export declare function literalTexts(file: FileView): Array<{
15
15
  text: string;
16
16
  index: number;
17
17
  }>;
18
+ export declare const routePrefixPattern: (prefix: string) => RegExp;
19
+ export declare function routePrefixProblems(value: unknown, field: string, problems: string[]): void;
18
20
  export declare function routeLiterals(file: FileView, routePrefixes: readonly string[]): Hit[];
19
21
  export declare const appRouteOwnerGuard: GenericGuardDefinition<AppRouteOwnerFacts>;
20
22
  //# sourceMappingURL=app-routes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"app-routes.d.ts","sourceRoot":"","sources":["../../../src/modules/core-definitions/app-routes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAEzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAqB,KAAK,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAkBrE,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,UAAU,EAAE,SAAS,QAAQ,EAAE,CAAC;CACjC;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAiBnF;AAID,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,GAAG,EAAE,CAKrF;AAoID,eAAO,MAAM,kBAAkB,EAAE,sBAAsB,CAAC,kBAAkB,CA2FzE,CAAC"}
1
+ {"version":3,"file":"app-routes.d.ts","sourceRoot":"","sources":["../../../src/modules/core-definitions/app-routes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAEzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAqB,KAAK,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAkBrE,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,UAAU,EAAE,SAAS,QAAQ,EAAE,CAAC;CACjC;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAiBnF;AAED,eAAO,MAAM,kBAAkB,GAAI,QAAQ,MAAM,KAAG,MACD,CAAC;AAEpD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAO3F;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,GAAG,EAAE,CAKrF;AAoID,eAAO,MAAM,kBAAkB,EAAE,sBAAsB,CAAC,kBAAkB,CAsFzE,CAAC"}
@@ -26,9 +26,16 @@ export function literalTexts(file) {
26
26
  visit(sf);
27
27
  return out;
28
28
  }
29
- const prefixPattern = (prefix) => new RegExp(`^${escapeRegExp(prefix)}(?:$|[/?#])`);
29
+ export const routePrefixPattern = (prefix) => new RegExp(`^${escapeRegExp(prefix)}(?:$|[/?#])`);
30
+ export function routePrefixProblems(value, field, problems) {
31
+ if (!Array.isArray(value))
32
+ return;
33
+ for (const prefix of value)
34
+ if (isText(prefix) && !/^\/[^/?#\s]+(?:\/[^/?#\s]+)*$/.test(prefix))
35
+ problems.push(`${field} entry ${prefix} must start with / and name whole segments, with no trailing /`);
36
+ }
30
37
  export function routeLiterals(file, routePrefixes) {
31
- const patterns = routePrefixes.map(prefixPattern);
38
+ const patterns = routePrefixes.map(routePrefixPattern);
32
39
  return literalTexts(file)
33
40
  .filter(({ text }) => patterns.some((p) => p.test(text)))
34
41
  .map(({ text, index }) => ({ index, detail: text.slice(0, 80) }));
@@ -160,10 +167,7 @@ export const appRouteOwnerGuard = {
160
167
  identifierProblem(facts.owner.name, 'owner.name', problems);
161
168
  }
162
169
  namesProblem(facts?.routePrefixes, 'routePrefixes', problems);
163
- if (Array.isArray(facts?.routePrefixes))
164
- for (const prefix of facts.routePrefixes)
165
- if (isText(prefix) && !/^\/[^/?#\s]+(?:\/[^/?#\s]+)*$/.test(prefix))
166
- problems.push(`routePrefixes entry ${prefix} must start with / and name whole segments, with no trailing /`);
170
+ routePrefixProblems(facts?.routePrefixes, 'routePrefixes', problems);
167
171
  if (!Array.isArray(facts?.trees) || !facts.trees.length)
168
172
  problems.push('trees is missing');
169
173
  else
@@ -1 +1 @@
1
- {"version":3,"file":"app-routes.js","sourceRoot":"","sources":["../../../src/modules/core-definitions/app-routes.ts"],"names":[],"mappings":"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","sourcesContent":["import ts from 'typescript';\nimport type { GenericGuardDefinition } from '../../node/suite/config.js';\nimport type { Finding, GuardContext } from '../../guard.js';\nimport type { Reviewed } from '../../node/layout.js';\nimport type { FileView } from '../../reader/view.js';\nimport { reviewedAllowlist, type Hit } from '../../shapes/shapes.js';\nimport {\n identifierProblem,\n isText,\n namesProblem,\n objectProblem,\n pathProblem,\n reviewedProblems,\n textProblem,\n} from '../../support/facts.js';\nimport { escapeRegExp, isUnder } from '../../support/text.js';\nimport { exportedNames } from '../ui/source.js';\nimport { installedManifest, splitBareSpecifier } from '../ui/stylesheets.js';\nimport { kindOfFile } from '../../node/layout.js';\nimport { moduleImports, type ImportKind } from '../../support/imports.js';\nimport { resolveSpecifier } from '../../support/resolve-specifier.js';\nimport { APP_SOURCE } from './shared.js';\n\nexport interface AppRouteOwnerFacts {\n owner: { module: string; name: string };\n routePrefixes: readonly string[];\n trees: readonly string[];\n exceptions: readonly Reviewed[];\n}\n\nexport function literalTexts(file: FileView): Array<{ text: string; index: number }> {\n const sf = file.sourceFile;\n const out: Array<{ text: string; index: number }> = [];\n const visit = (node: ts.Node): void => {\n if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {\n out.push({ text: node.text, index: node.getStart(sf) });\n return;\n }\n if (ts.isTemplateExpression(node)) {\n out.push({ text: node.head.text, index: node.getStart(sf) });\n for (const span of node.templateSpans)\n out.push({ text: span.literal.text, index: span.literal.getStart(sf) });\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n return out;\n}\n\nconst prefixPattern = (prefix: string) => new RegExp(`^${escapeRegExp(prefix)}(?:$|[/?#])`);\n\nexport function routeLiterals(file: FileView, routePrefixes: readonly string[]): Hit[] {\n const patterns = routePrefixes.map(prefixPattern);\n return literalTexts(file)\n .filter(({ text }) => patterns.some((p) => p.test(text)))\n .map(({ text, index }) => ({ index, detail: text.slice(0, 80) }));\n}\n\nfunction pickEntry(entry: unknown): string | null {\n if (typeof entry === 'string') return entry;\n if (entry && typeof entry === 'object') {\n const conditions = entry as Record<string, unknown>;\n for (const key of ['import', 'module', 'default', 'require', 'node']) {\n const found = pickEntry(conditions[key]);\n if (found) return found;\n }\n }\n return null;\n}\n\nfunction installedEntry(context: GuardContext, module: string): string | null {\n const { name, subpath } = splitBareSpecifier(module);\n const manifest = installedManifest(context, name);\n if (!manifest) return null;\n const exportsField = manifest.exports;\n const keyed =\n !!exportsField &&\n typeof exportsField === 'object' &&\n Object.keys(exportsField).some((k) => k.startsWith('.'));\n const fallback =\n typeof manifest.module === 'string'\n ? manifest.module\n : typeof manifest.main === 'string'\n ? manifest.main\n : './index.js';\n const target = keyed\n ? pickEntry((exportsField as Record<string, unknown>)[subpath])\n : exportsField !== undefined\n ? subpath === '.'\n ? pickEntry(exportsField)\n : null\n : subpath !== '.'\n ? subpath\n : fallback;\n if (!target) return null;\n const base = `node_modules/${name}/package.json`;\n const resolved = resolveSpecifier(\n context.reader,\n base,\n target.startsWith('.') ? target : `./${target}`,\n [],\n );\n return context.reader.exists(resolved) ? resolved : null;\n}\n\nfunction localLoads(context: GuardContext, file: FileView, kinds: readonly ImportKind[]) {\n const out: string[] = [];\n for (const site of moduleImports(file.sourceFile, kinds)) {\n if (!site.spec.startsWith('.')) continue;\n const resolved = resolveSpecifier(context.reader, file.path, site.spec, []);\n if (\n context.reader.exists(resolved) &&\n kindOfFile(resolved.slice(resolved.lastIndexOf('/') + 1)) === 'code'\n )\n out.push(resolved);\n }\n return out;\n}\n\nfunction ownerCode(\n context: GuardContext,\n module: string,\n): { files: FileView[]; entry: FileView; where: string } | null {\n const entryPath = context.reader.exists(module) ? module : installedEntry(context, module);\n if (!entryPath) return null;\n const entry = context.file(entryPath);\n const seen = new Map<string, FileView>([[entryPath, entry]]);\n const queue = [entry];\n while (queue.length) {\n const file = queue.shift()!;\n for (const path of localLoads(context, file, ['import', 'export'])) {\n if (seen.has(path)) continue;\n const next = context.file(path);\n seen.set(path, next);\n queue.push(next);\n }\n }\n return { files: [...seen.values()], entry, where: module };\n}\n\nfunction exportsName(\n context: GuardContext,\n file: FileView,\n name: string,\n seen: Set<string> = new Set(),\n): boolean {\n const key = `${file.path}#${name}`;\n if (seen.has(key)) return false;\n seen.add(key);\n const target = (spec: ts.Expression): FileView | null => {\n if (!ts.isStringLiteral(spec) || !spec.text.startsWith('.')) return null;\n const resolved = resolveSpecifier(context.reader, file.path, spec.text, []);\n return context.reader.exists(resolved) ? context.file(resolved) : null;\n };\n for (const statement of file.sourceFile.statements) {\n if (!ts.isExportDeclaration(statement)) continue;\n const clause = statement.exportClause;\n if (!statement.moduleSpecifier) {\n if (clause && ts.isNamedExports(clause) && clause.elements.some((e) => e.name.text === name))\n return true;\n continue;\n }\n if (clause && ts.isNamespaceExport(clause)) {\n if (clause.name.text === name) return true;\n continue;\n }\n const from = target(statement.moduleSpecifier);\n if (!from) continue;\n if (!clause) {\n if (exportsName(context, from, name, seen)) return true;\n continue;\n }\n const element = clause.elements.find((e) => e.name.text === name);\n if (element)\n return exportsName(context, from, (element.propertyName ?? element.name).text, seen);\n }\n const reExported = new Set(\n file.sourceFile.statements\n .filter(ts.isExportDeclaration)\n .flatMap((s) =>\n s.exportClause && ts.isNamedExports(s.exportClause)\n ? s.exportClause.elements.map((e) => e.name.text)\n : [],\n ),\n );\n return !reExported.has(name) && exportedNames(file).has(name);\n}\n\nexport const appRouteOwnerGuard: GenericGuardDefinition<AppRouteOwnerFacts> = {\n id: 'appRouteOwner',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n if (objectProblem(facts?.owner, 'owner', problems)) {\n textProblem(facts.owner.module, 'owner.module', problems);\n identifierProblem(facts.owner.name, 'owner.name', problems);\n }\n namesProblem(facts?.routePrefixes, 'routePrefixes', problems);\n if (Array.isArray(facts?.routePrefixes))\n for (const prefix of facts.routePrefixes)\n if (isText(prefix) && !/^\\/[^/?#\\s]+(?:\\/[^/?#\\s]+)*$/.test(prefix))\n problems.push(\n `routePrefixes entry ${prefix} must start with / and name whole segments, with no trailing /`,\n );\n if (!Array.isArray(facts?.trees) || !facts.trees.length) problems.push('trees is missing');\n else facts.trees.forEach((t, i) => pathProblem(t, `trees[${i}]`, problems));\n reviewedProblems(facts?.exceptions, 'exceptions', problems);\n return problems;\n },\n build(facts) {\n const { module, name } = facts.owner;\n const tree = facts.trees[0];\n const [prefix] = facts.routePrefixes;\n const inTrees = (file: FileView) => facts.trees.some((t) => isUnder(file.path, t));\n const guard = reviewedAllowlist({\n title: 'app routes are built by the one route owner',\n description:\n `An app page path is declared once and built through \\`${name}\\` from ${module}. Under ${facts.trees.join(', ')}, ` +\n `no other code holds a string or template literal that starts with one of the page roots ` +\n `(${facts.routePrefixes.join(', ')}) as a whole segment — in an href, a navigation call, a redirect, a link in a ` +\n 'message, or anywhere else: a route written by hand drifts from its declaration the day the page moves. Build ' +\n `the path with \\`${name}\\`. A framework route file or another genuine non-route literal is a reviewed exception ` +\n 'with its why; an exception that no longer holds such a literal is stale, and so is a page root the owner no ' +\n 'longer builds. The root path `/` is not a page root: every root names at least one whole segment.',\n scope: APP_SOURCE,\n match: (file) =>\n inTrees(file) && file.path !== module ? routeLiterals(file, facts.routePrefixes) : [],\n allowlist: facts.exceptions,\n samples: {\n flags: [\n { path: `${tree}/probe.tsx`, text: `<Link href=\"${prefix}\">Open</Link>` },\n { path: `${tree}/probe.tsx`, text: `router.push(\\`${prefix}/\\${id}/edit\\`);` },\n { path: `${tree}/probe.ts`, text: `redirect('${prefix}?tab=a');` },\n { path: `${tree}/probe.ts`, text: `const url = \\`\\${origin}${prefix}/\\${id}\\`;` },\n ],\n passes: [\n { path: `${tree}/probe.tsx`, text: `<Link href={${name}.home()}>Open</Link>` },\n { path: `${tree}/probe.ts`, text: `const other = '${prefix}x';` },\n { path: `${tree}/probe.ts`, text: `// the page lives at ${prefix}\\nconst n = 1;` },\n ],\n },\n });\n return [\n {\n ...guard,\n async run(context) {\n const findings: Finding[] = [...(await guard.run(context))];\n const scanned = context.files(APP_SOURCE).filter(inTrees);\n for (const t of facts.trees)\n if (!scanned.some((f) => isUnder(f.path, t)))\n findings.push({\n file: t,\n detail: 'the tree holds no production code the guard can read',\n });\n const owner = ownerCode(context, module);\n if (!owner) {\n findings.push({\n file: module,\n detail:\n 'the route owner cannot be read: no such file, and no installed entry for that subpath',\n });\n return findings;\n }\n if (!exportsName(context, owner.entry, name))\n findings.push({\n file: module,\n detail: `the route owner no longer exports ${name} (read from ${owner.where})`,\n });\n for (const p of facts.routePrefixes)\n if (!owner.files.some((f) => routeLiterals(f, [p]).length))\n findings.push({\n file: '(routePrefixes)',\n detail: `stale page root: ${owner.where} no longer builds any path under ${p}`,\n });\n return findings;\n },\n },\n ];\n },\n};\n"]}
1
+ {"version":3,"file":"app-routes.js","sourceRoot":"","sources":["../../../src/modules/core-definitions/app-routes.ts"],"names":[],"mappings":"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","sourcesContent":["import ts from 'typescript';\nimport type { GenericGuardDefinition } from '../../node/suite/config.js';\nimport type { Finding, GuardContext } from '../../guard.js';\nimport type { Reviewed } from '../../node/layout.js';\nimport type { FileView } from '../../reader/view.js';\nimport { reviewedAllowlist, type Hit } from '../../shapes/shapes.js';\nimport {\n identifierProblem,\n isText,\n namesProblem,\n objectProblem,\n pathProblem,\n reviewedProblems,\n textProblem,\n} from '../../support/facts.js';\nimport { escapeRegExp, isUnder } from '../../support/text.js';\nimport { exportedNames } from '../ui/source.js';\nimport { installedManifest, splitBareSpecifier } from '../ui/stylesheets.js';\nimport { kindOfFile } from '../../node/layout.js';\nimport { moduleImports, type ImportKind } from '../../support/imports.js';\nimport { resolveSpecifier } from '../../support/resolve-specifier.js';\nimport { APP_SOURCE } from './shared.js';\n\nexport interface AppRouteOwnerFacts {\n owner: { module: string; name: string };\n routePrefixes: readonly string[];\n trees: readonly string[];\n exceptions: readonly Reviewed[];\n}\n\nexport function literalTexts(file: FileView): Array<{ text: string; index: number }> {\n const sf = file.sourceFile;\n const out: Array<{ text: string; index: number }> = [];\n const visit = (node: ts.Node): void => {\n if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {\n out.push({ text: node.text, index: node.getStart(sf) });\n return;\n }\n if (ts.isTemplateExpression(node)) {\n out.push({ text: node.head.text, index: node.getStart(sf) });\n for (const span of node.templateSpans)\n out.push({ text: span.literal.text, index: span.literal.getStart(sf) });\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n return out;\n}\n\nexport const routePrefixPattern = (prefix: string): RegExp =>\n new RegExp(`^${escapeRegExp(prefix)}(?:$|[/?#])`);\n\nexport function routePrefixProblems(value: unknown, field: string, problems: string[]): void {\n if (!Array.isArray(value)) return;\n for (const prefix of value)\n if (isText(prefix) && !/^\\/[^/?#\\s]+(?:\\/[^/?#\\s]+)*$/.test(prefix))\n problems.push(\n `${field} entry ${prefix} must start with / and name whole segments, with no trailing /`,\n );\n}\n\nexport function routeLiterals(file: FileView, routePrefixes: readonly string[]): Hit[] {\n const patterns = routePrefixes.map(routePrefixPattern);\n return literalTexts(file)\n .filter(({ text }) => patterns.some((p) => p.test(text)))\n .map(({ text, index }) => ({ index, detail: text.slice(0, 80) }));\n}\n\nfunction pickEntry(entry: unknown): string | null {\n if (typeof entry === 'string') return entry;\n if (entry && typeof entry === 'object') {\n const conditions = entry as Record<string, unknown>;\n for (const key of ['import', 'module', 'default', 'require', 'node']) {\n const found = pickEntry(conditions[key]);\n if (found) return found;\n }\n }\n return null;\n}\n\nfunction installedEntry(context: GuardContext, module: string): string | null {\n const { name, subpath } = splitBareSpecifier(module);\n const manifest = installedManifest(context, name);\n if (!manifest) return null;\n const exportsField = manifest.exports;\n const keyed =\n !!exportsField &&\n typeof exportsField === 'object' &&\n Object.keys(exportsField).some((k) => k.startsWith('.'));\n const fallback =\n typeof manifest.module === 'string'\n ? manifest.module\n : typeof manifest.main === 'string'\n ? manifest.main\n : './index.js';\n const target = keyed\n ? pickEntry((exportsField as Record<string, unknown>)[subpath])\n : exportsField !== undefined\n ? subpath === '.'\n ? pickEntry(exportsField)\n : null\n : subpath !== '.'\n ? subpath\n : fallback;\n if (!target) return null;\n const base = `node_modules/${name}/package.json`;\n const resolved = resolveSpecifier(\n context.reader,\n base,\n target.startsWith('.') ? target : `./${target}`,\n [],\n );\n return context.reader.exists(resolved) ? resolved : null;\n}\n\nfunction localLoads(context: GuardContext, file: FileView, kinds: readonly ImportKind[]) {\n const out: string[] = [];\n for (const site of moduleImports(file.sourceFile, kinds)) {\n if (!site.spec.startsWith('.')) continue;\n const resolved = resolveSpecifier(context.reader, file.path, site.spec, []);\n if (\n context.reader.exists(resolved) &&\n kindOfFile(resolved.slice(resolved.lastIndexOf('/') + 1)) === 'code'\n )\n out.push(resolved);\n }\n return out;\n}\n\nfunction ownerCode(\n context: GuardContext,\n module: string,\n): { files: FileView[]; entry: FileView; where: string } | null {\n const entryPath = context.reader.exists(module) ? module : installedEntry(context, module);\n if (!entryPath) return null;\n const entry = context.file(entryPath);\n const seen = new Map<string, FileView>([[entryPath, entry]]);\n const queue = [entry];\n while (queue.length) {\n const file = queue.shift()!;\n for (const path of localLoads(context, file, ['import', 'export'])) {\n if (seen.has(path)) continue;\n const next = context.file(path);\n seen.set(path, next);\n queue.push(next);\n }\n }\n return { files: [...seen.values()], entry, where: module };\n}\n\nfunction exportsName(\n context: GuardContext,\n file: FileView,\n name: string,\n seen: Set<string> = new Set(),\n): boolean {\n const key = `${file.path}#${name}`;\n if (seen.has(key)) return false;\n seen.add(key);\n const target = (spec: ts.Expression): FileView | null => {\n if (!ts.isStringLiteral(spec) || !spec.text.startsWith('.')) return null;\n const resolved = resolveSpecifier(context.reader, file.path, spec.text, []);\n return context.reader.exists(resolved) ? context.file(resolved) : null;\n };\n for (const statement of file.sourceFile.statements) {\n if (!ts.isExportDeclaration(statement)) continue;\n const clause = statement.exportClause;\n if (!statement.moduleSpecifier) {\n if (clause && ts.isNamedExports(clause) && clause.elements.some((e) => e.name.text === name))\n return true;\n continue;\n }\n if (clause && ts.isNamespaceExport(clause)) {\n if (clause.name.text === name) return true;\n continue;\n }\n const from = target(statement.moduleSpecifier);\n if (!from) continue;\n if (!clause) {\n if (exportsName(context, from, name, seen)) return true;\n continue;\n }\n const element = clause.elements.find((e) => e.name.text === name);\n if (element)\n return exportsName(context, from, (element.propertyName ?? element.name).text, seen);\n }\n const reExported = new Set(\n file.sourceFile.statements\n .filter(ts.isExportDeclaration)\n .flatMap((s) =>\n s.exportClause && ts.isNamedExports(s.exportClause)\n ? s.exportClause.elements.map((e) => e.name.text)\n : [],\n ),\n );\n return !reExported.has(name) && exportedNames(file).has(name);\n}\n\nexport const appRouteOwnerGuard: GenericGuardDefinition<AppRouteOwnerFacts> = {\n id: 'appRouteOwner',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n if (objectProblem(facts?.owner, 'owner', problems)) {\n textProblem(facts.owner.module, 'owner.module', problems);\n identifierProblem(facts.owner.name, 'owner.name', problems);\n }\n namesProblem(facts?.routePrefixes, 'routePrefixes', problems);\n routePrefixProblems(facts?.routePrefixes, 'routePrefixes', problems);\n if (!Array.isArray(facts?.trees) || !facts.trees.length) problems.push('trees is missing');\n else facts.trees.forEach((t, i) => pathProblem(t, `trees[${i}]`, problems));\n reviewedProblems(facts?.exceptions, 'exceptions', problems);\n return problems;\n },\n build(facts) {\n const { module, name } = facts.owner;\n const tree = facts.trees[0];\n const [prefix] = facts.routePrefixes;\n const inTrees = (file: FileView) => facts.trees.some((t) => isUnder(file.path, t));\n const guard = reviewedAllowlist({\n title: 'app routes are built by the one route owner',\n description:\n `An app page path is declared once and built through \\`${name}\\` from ${module}. Under ${facts.trees.join(', ')}, ` +\n `no other code holds a string or template literal that starts with one of the page roots ` +\n `(${facts.routePrefixes.join(', ')}) as a whole segment — in an href, a navigation call, a redirect, a link in a ` +\n 'message, or anywhere else: a route written by hand drifts from its declaration the day the page moves. Build ' +\n `the path with \\`${name}\\`. A framework route file or another genuine non-route literal is a reviewed exception ` +\n 'with its why; an exception that no longer holds such a literal is stale, and so is a page root the owner no ' +\n 'longer builds. The root path `/` is not a page root: every root names at least one whole segment.',\n scope: APP_SOURCE,\n match: (file) =>\n inTrees(file) && file.path !== module ? routeLiterals(file, facts.routePrefixes) : [],\n allowlist: facts.exceptions,\n samples: {\n flags: [\n { path: `${tree}/probe.tsx`, text: `<Link href=\"${prefix}\">Open</Link>` },\n { path: `${tree}/probe.tsx`, text: `router.push(\\`${prefix}/\\${id}/edit\\`);` },\n { path: `${tree}/probe.ts`, text: `redirect('${prefix}?tab=a');` },\n { path: `${tree}/probe.ts`, text: `const url = \\`\\${origin}${prefix}/\\${id}\\`;` },\n ],\n passes: [\n { path: `${tree}/probe.tsx`, text: `<Link href={${name}.home()}>Open</Link>` },\n { path: `${tree}/probe.ts`, text: `const other = '${prefix}x';` },\n { path: `${tree}/probe.ts`, text: `// the page lives at ${prefix}\\nconst n = 1;` },\n ],\n },\n });\n return [\n {\n ...guard,\n async run(context) {\n const findings: Finding[] = [...(await guard.run(context))];\n const scanned = context.files(APP_SOURCE).filter(inTrees);\n for (const t of facts.trees)\n if (!scanned.some((f) => isUnder(f.path, t)))\n findings.push({\n file: t,\n detail: 'the tree holds no production code the guard can read',\n });\n const owner = ownerCode(context, module);\n if (!owner) {\n findings.push({\n file: module,\n detail:\n 'the route owner cannot be read: no such file, and no installed entry for that subpath',\n });\n return findings;\n }\n if (!exportsName(context, owner.entry, name))\n findings.push({\n file: module,\n detail: `the route owner no longer exports ${name} (read from ${owner.where})`,\n });\n for (const p of facts.routePrefixes)\n if (!owner.files.some((f) => routeLiterals(f, [p]).length))\n findings.push({\n file: '(routePrefixes)',\n detail: `stale page root: ${owner.where} no longer builds any path under ${p}`,\n });\n return findings;\n },\n },\n ];\n },\n};\n"]}
@@ -16,13 +16,14 @@ export interface RetiredSegmentFacts {
16
16
  name: string;
17
17
  replacement: string;
18
18
  }>;
19
+ routePrefixes: readonly string[];
19
20
  reviewedMatches: ReadonlyArray<{
20
21
  file: string;
21
22
  contains: string;
22
23
  why: string;
23
24
  }>;
24
25
  }
25
- export declare function retiredSegmentHits(file: FileView, names: readonly string[]): Array<NodeHit & {
26
+ export declare function retiredSegmentHits(file: FileView, names: readonly string[], routePrefixes: readonly string[]): Array<NodeHit & {
26
27
  name: string;
27
28
  text: string;
28
29
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"path-guards.d.ts","sourceRoot":"","sources":["../../../src/modules/firestore/path-guards.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAEzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAIrD,OAAO,EAKL,KAAK,OAAO,EACZ,KAAK,OAAO,EACb,MAAM,cAAc,CAAC;AAsCtB,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,EAAE,CAkC5D;AAED,eAAO,MAAM,mBAAmB,EAAE,sBAAsB,CAAC,OAAO,CAmB/D,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,mBAAmB,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,aAAa,EAAE,SAAS,QAAQ,EAAE,CAAC;CACpC;AAYD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,IAAI,CAAC,iBAAiB,EAAE,gBAAgB,GAAG,qBAAqB,CAAC,GACvE,OAAO,EAAE,CAuDX;AAED,eAAO,MAAM,iBAAiB,EAAE,sBAAsB,CAAC,iBAAiB,CA4CvE,CAAC;AAEF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/D,eAAe,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjF;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB,KAAK,CAAC,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAmCjD;AAED,eAAO,MAAM,mBAAmB,EAAE,sBAAsB,CAAC,mBAAmB,CAyE3E,CAAC"}
1
+ {"version":3,"file":"path-guards.d.ts","sourceRoot":"","sources":["../../../src/modules/firestore/path-guards.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAEzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAIrD,OAAO,EAKL,KAAK,OAAO,EACZ,KAAK,OAAO,EACb,MAAM,cAAc,CAAC;AAuCtB,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,EAAE,CAkC5D;AAED,eAAO,MAAM,mBAAmB,EAAE,sBAAsB,CAAC,OAAO,CAmB/D,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,mBAAmB,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,aAAa,EAAE,SAAS,QAAQ,EAAE,CAAC;CACpC;AAYD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,IAAI,CAAC,iBAAiB,EAAE,gBAAgB,GAAG,qBAAqB,CAAC,GACvE,OAAO,EAAE,CAuDX;AAED,eAAO,MAAM,iBAAiB,EAAE,sBAAsB,CAAC,iBAAiB,CA4CvE,CAAC;AAEF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/D,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,eAAe,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjF;AAID,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,aAAa,EAAE,SAAS,MAAM,EAAE,GAC/B,KAAK,CAAC,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CA6CjD;AAED,eAAO,MAAM,mBAAmB,EAAE,sBAAsB,CAAC,mBAAmB,CA+E3E,CAAC"}
@@ -4,6 +4,7 @@ import { namesProblem, reviewedProblems, takesNoFacts, isList } from '../../supp
4
4
  import { escapeRegExp } from '../../support/text.js';
5
5
  import { bannedGuard, findingsOf, isMemberOf, literalBindings, } from './support.js';
6
6
  import { REPOSITORY_GUARD_TIMEOUT_MS } from '../../support/timeouts.js';
7
+ import { routePrefixPattern, routePrefixProblems } from '../core-definitions/app-routes.js';
7
8
  const ACCESSORS = new Set(['collection', 'collectionGroup', 'doc']);
8
9
  const APP_CODE = {
9
10
  roots: ['app', 'functions'],
@@ -196,14 +197,23 @@ export const pathAssemblyGuard = {
196
197
  ];
197
198
  },
198
199
  };
199
- export function retiredSegmentHits(file, names) {
200
+ const SOURCE_FILE = /\.[cm]?[jt]sx?$/;
201
+ export function retiredSegmentHits(file, names, routePrefixes) {
200
202
  const source = file.sourceFile;
201
203
  const retired = new Set(names);
202
204
  const alternation = names.map(escapeRegExp).join('|');
203
205
  const inside = new RegExp(`/(${alternation})(?=/)`, 'g');
204
206
  const closing = new RegExp(`/(${alternation})$`);
207
+ const routes = routePrefixes.map(routePrefixPattern);
208
+ const specifiers = new Set(file.imports.map((site) => site.specifier));
205
209
  const hits = [];
206
210
  const scan = (node, parts) => {
211
+ const opening = parts[0].text;
212
+ const whole = parts.map((p) => p.text).join('');
213
+ if (specifiers.has(node) ||
214
+ routes.some((route) => route.test(opening)) ||
215
+ SOURCE_FILE.test(whole))
216
+ return;
207
217
  const found = [];
208
218
  for (const { text, closes } of parts) {
209
219
  for (const m of text.matchAll(inside))
@@ -246,6 +256,8 @@ export const retiredSegmentGuard = {
246
256
  id: (e) => typeof e.contains === 'string' && e.contains ? `${e.file} ${e.contains}` : undefined,
247
257
  idNames: 'text it contains',
248
258
  });
259
+ namesProblem(facts?.routePrefixes, 'routePrefixes', problems, { nonEmpty: false });
260
+ routePrefixProblems(facts?.routePrefixes, 'routePrefixes', problems);
249
261
  if (!isList(facts?.segments) || !facts.segments.length)
250
262
  return [...problems, 'segments is empty (declare the guard absent instead)'];
251
263
  const names = facts.segments.map((s) => s?.name);
@@ -274,14 +286,18 @@ export const retiredSegmentGuard = {
274
286
  description: 'A segment name inside a string is never type-checked, so a retired name keeps addressing a collection that no ' +
275
287
  'longer exists — a trigger that never fires, a read that returns nothing, a fixture nobody reads. Flagged: a ' +
276
288
  'retired name in path position in any string or template (`/name/`, or `/name` closing it), and a retired name ' +
277
- "as a collectionGroup id. Fix: build the path through the core. A reviewed match names a literal's text that " +
278
- 'is not a Firestore path, with its why; one that matches nothing is stale.',
289
+ 'as a collectionGroup id. Never flagged: a module specifier (an import, re-export, `import()`, `require()`, ' +
290
+ 'test-runner mock, or type import), a string or template that opens with one of the app page roots ' +
291
+ `(${facts.routePrefixes.join(', ') || 'none declared'}) as a whole segment, and a string or template that ` +
292
+ 'names a source file (it ends in a .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, or .cts extension). Fix: build the path ' +
293
+ "through the core. A reviewed match names a literal's text that is not a Firestore path, with its why; one that " +
294
+ 'matches nothing is stale.',
279
295
  timeoutMs: REPOSITORY_GUARD_TIMEOUT_MS,
280
296
  run(context) {
281
297
  const findings = [];
282
298
  const used = new Set();
283
299
  for (const file of context.files(scope)) {
284
- for (const hit of retiredSegmentHits(file, names)) {
300
+ for (const hit of retiredSegmentHits(file, names, facts.routePrefixes)) {
285
301
  const index = facts.reviewedMatches.findIndex((r) => r.file === file.path && hit.text.includes(r.contains));
286
302
  if (index !== -1) {
287
303
  used.add(index);
@@ -1 +1 @@
1
- {"version":3,"file":"path-guards.js","sourceRoot":"","sources":["../../../src/modules/firestore/path-guards.ts"],"names":[],"mappings":"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","sourcesContent":["import ts from 'typescript';\nimport type { Finding } from '../../guard.js';\nimport type { GenericGuardDefinition } from '../../node/suite/config.js';\nimport type { Scope } from '../../node/reader.js';\nimport type { Reviewed } from '../../node/layout.js';\nimport type { FileView } from '../../reader/view.js';\nimport { calleeName, forEachNode, isPlainString, lineOfNode, unwrap } from '../../support/ast.js';\nimport { namesProblem, reviewedProblems, takesNoFacts, isList } from '../../support/facts.js';\nimport { escapeRegExp } from '../../support/text.js';\nimport {\n bannedGuard,\n findingsOf,\n isMemberOf,\n literalBindings,\n type NoFacts,\n type NodeHit,\n} from './support.js';\nimport { REPOSITORY_GUARD_TIMEOUT_MS } from '../../support/timeouts.js';\n\nconst ACCESSORS = new Set(['collection', 'collectionGroup', 'doc']);\n\nconst APP_CODE: Scope = {\n roots: ['app', 'functions'],\n optionalRoots: ['functions'],\n kinds: ['code'],\n tests: false,\n};\n\nfunction isHandle(node: ts.Expression): boolean {\n const plain = (n: ts.Expression): boolean =>\n ts.isIdentifier(n) || (ts.isPropertyAccessExpression(n) && plain(n.expression));\n return (\n plain(node) ||\n (ts.isCallExpression(node) && node.arguments.length === 0 && plain(node.expression))\n );\n}\n\nfunction accessorPathArguments(\n call: ts.CallExpression,\n): { form: 'method' | 'modular'; args: readonly ts.Expression[] } | null {\n const callee = call.expression;\n if (ts.isPropertyAccessExpression(callee) && ACCESSORS.has(callee.name.text))\n return { form: 'method', args: call.arguments };\n if (\n ts.isIdentifier(callee) &&\n ACCESSORS.has(callee.text) &&\n call.arguments.length >= 2 &&\n isHandle(call.arguments[0])\n ) {\n return { form: 'modular', args: call.arguments.slice(1) };\n }\n return null;\n}\n\nexport function literalSegmentHits(file: FileView): NodeHit[] {\n const source = file.sourceFile;\n const bindings = literalBindings(source);\n const typed = (arg: ts.Expression): string | null => {\n const value = unwrap(arg);\n if (isPlainString(value)) return `'${value.text}'`;\n if (ts.isIdentifier(value) && bindings.has(value.text))\n return `${value.text} (bound to '${bindings.get(value.text)}')`;\n return null;\n };\n const hits: NodeHit[] = [];\n forEachNode(source, (node) => {\n if (!ts.isCallExpression(node)) return;\n const accessor = accessorPathArguments(node);\n if (!accessor) return;\n const name = calleeName(node);\n if (accessor.form === 'method') {\n // The Admin SDK accessor takes the whole segment as its one argument.\n if (accessor.args.length !== 1) return;\n const segment = typed(accessor.args[0]);\n if (segment)\n hits.push({\n node: (node.expression as ts.PropertyAccessExpression).name,\n detail: `.${name}(${segment})`,\n });\n return;\n }\n const segments = accessor.args\n .filter((arg) => !ts.isSpreadElement(arg))\n .map(typed)\n .filter((s): s is string => s !== null);\n if (segments.length) hits.push({ node, detail: `${name}(db, …) with ${segments.join(', ')}` });\n });\n return hits;\n}\n\nexport const literalSegmentGuard: GenericGuardDefinition<NoFacts> = {\n id: 'firestoreLiteralSegments',\n absentWhen: 'the app stores nothing in Firestore',\n factProblems: takesNoFacts,\n build() {\n return [\n bannedGuard({\n title: 'no typed path segment reaches a Firestore accessor',\n description:\n 'A collection or document segment comes from the core package, never a string typed at the call. Flagged: a ' +\n 'string literal (or a name bound to one in the same file) as the whole argument of x.collection / ' +\n 'x.collectionGroup / x.doc, on every link of a chain, and in ANY path position after the handle of the ' +\n 'modular collection(db, …) / collectionGroup(db, …) / doc(db, …). A literal whose text equals the constant is ' +\n \"still the violation. Fix: import the owner — the core's collection constant, or its path builder.\",\n scope: APP_CODE,\n match: literalSegmentHits,\n }),\n ];\n },\n};\n\nexport interface PathAssemblyFacts {\n ownerConstants: readonly string[];\n segmentArrayJoiners: readonly string[];\n reviewedSites: readonly Reviewed[];\n}\n\nconst hasSlash = (node: ts.Expression) => isPlainString(node) && node.text.includes('/');\n\nfunction concatenationOperands(node: ts.Expression): ts.Expression[] {\n const value = unwrap(node);\n if (ts.isBinaryExpression(value) && value.operatorToken.kind === ts.SyntaxKind.PlusToken) {\n return [...concatenationOperands(value.left), ...concatenationOperands(value.right)];\n }\n return [value];\n}\n\nexport function pathAssemblyHits(\n file: FileView,\n facts: Pick<PathAssemblyFacts, 'ownerConstants' | 'segmentArrayJoiners'>,\n): NodeHit[] {\n const owners = new Set(facts.ownerConstants);\n const joiners = new Set(facts.segmentArrayJoiners);\n const isOwner = (node: ts.Expression) => isMemberOf(unwrap(node), owners);\n const hits = new Map<number, NodeHit>();\n const hit = (node: ts.Node, detail: string) => {\n const at = node.getStart(file.sourceFile);\n if (!hits.has(at)) hits.set(at, { node, detail });\n };\n forEachNode(file.sourceFile, (node) => {\n if (ts.isCallExpression(node)) {\n const accessor = accessorPathArguments(node);\n for (const raw of accessor?.args ?? []) {\n const arg = unwrap(raw);\n if (ts.isTemplateExpression(arg)) {\n if (arg.templateSpans.some((span) => isOwner(span.expression)))\n hit(arg, 'an owner constant spliced into a template path');\n else if (\n (arg.head.text + arg.templateSpans.map((s) => s.literal.text).join('')).includes('/')\n ) {\n hit(arg, 'a template path built from a `/` and a hole');\n }\n } else if (ts.isBinaryExpression(arg) && concatenationOperands(arg).some(hasSlash)) {\n hit(arg, 'a slash path concatenated at the accessor');\n }\n }\n const name = calleeName(node);\n if (name && joiners.has(name)) {\n for (const arg of node.arguments) {\n const value = unwrap(arg);\n if (\n ts.isArrayLiteralExpression(value) &&\n value.elements.some((e) => !ts.isSpreadElement(e) && isOwner(e))\n ) {\n hit(value, `a segment array handed to ${name}() with an owner constant in it`);\n }\n }\n }\n } else if (ts.isTemplateExpression(node)) {\n node.templateSpans.forEach((span, i) => {\n const followedByHole = i < node.templateSpans.length - 1;\n if (isOwner(span.expression) && span.literal.text === '/' && followedByHole) {\n hit(node, 'an owner constant joined to a hole with a `/`');\n }\n });\n } else if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.PlusToken) {\n const left = unwrap(node.left);\n const right = unwrap(node.right);\n if ((isOwner(left) && hasSlash(right)) || (hasSlash(left) && isOwner(right)))\n hit(node, 'an owner constant concatenated with a slash');\n }\n });\n return [...hits.values()].sort(\n (a, b) => a.node.getStart(file.sourceFile) - b.node.getStart(file.sourceFile),\n );\n}\n\nexport const pathAssemblyGuard: GenericGuardDefinition<PathAssemblyFacts> = {\n id: 'firestorePathAssembly',\n absentWhen: 'the app stores nothing in Firestore',\n factProblems(facts) {\n const problems: string[] = [];\n namesProblem(facts?.ownerConstants, 'ownerConstants', problems);\n namesProblem(facts?.segmentArrayJoiners, 'segmentArrayJoiners', problems, { nonEmpty: false });\n reviewedProblems(facts?.reviewedSites, 'reviewedSites', problems);\n return problems;\n },\n build(facts) {\n const reviewed = new Map(facts.reviewedSites.map((s) => [s.path, s]));\n return [\n {\n title: 'no Firestore path is assembled by hand',\n description:\n \"A path's string form derives from the core's path builder; writing it again at the call is a second spelling. \" +\n 'Flagged: an owner constant spliced into an accessor template; an accessor template holding both a `/` and a ' +\n 'hole, in either order; a slash-bearing literal concatenated in an accessor argument; an owner constant joined ' +\n 'to a hole by a `/` in any template, or concatenated with a slash-bearing literal anywhere; a segment array ' +\n \"holding an owner constant handed to a path joiner. Fix: call the core's path builder. A reviewed site is a file \" +\n 'with its why; an entry whose file no longer assembles a path is stale.',\n timeoutMs: REPOSITORY_GUARD_TIMEOUT_MS,\n run(context) {\n const findings: Finding[] = [];\n const held = new Set<string>();\n for (const file of context.files(APP_CODE)) {\n const hits = pathAssemblyHits(file, facts);\n if (!hits.length) continue;\n if (reviewed.has(file.path)) held.add(file.path);\n else findings.push(...findingsOf(file, hits));\n }\n for (const path of reviewed.keys()) {\n if (!held.has(path))\n findings.push({\n file: path,\n detail: 'stale reviewed site: the file no longer assembles a path (or is gone)',\n });\n }\n return findings;\n },\n },\n ];\n },\n};\n\nexport interface RetiredSegmentFacts {\n segments: ReadonlyArray<{ name: string; replacement: string }>;\n reviewedMatches: ReadonlyArray<{ file: string; contains: string; why: string }>;\n}\n\nexport function retiredSegmentHits(\n file: FileView,\n names: readonly string[],\n): Array<NodeHit & { name: string; text: string }> {\n const source = file.sourceFile;\n const retired = new Set(names);\n const alternation = names.map(escapeRegExp).join('|');\n const inside = new RegExp(`/(${alternation})(?=/)`, 'g');\n const closing = new RegExp(`/(${alternation})$`);\n const hits: Array<NodeHit & { name: string; text: string }> = [];\n const scan = (node: ts.Node, parts: Array<{ text: string; closes: boolean }>) => {\n const found: string[] = [];\n for (const { text, closes } of parts) {\n for (const m of text.matchAll(inside)) found.push(m[1]);\n const end = closes ? closing.exec(text) : null;\n if (end) found.push(end[1]);\n }\n for (const name of found) hits.push({ node, name, text: node.getText(source), detail: '' });\n };\n forEachNode(source, (node) => {\n if (isPlainString(node)) scan(node, [{ text: node.text, closes: true }]);\n else if (ts.isTemplateExpression(node)) {\n scan(node, [\n { text: node.head.text, closes: false },\n ...node.templateSpans.map((s, i) => ({\n text: s.literal.text,\n closes: i === node.templateSpans.length - 1,\n })),\n ]);\n }\n if (ts.isCallExpression(node) && calleeName(node) === 'collectionGroup') {\n for (const arg of node.arguments) {\n if (isPlainString(arg) && retired.has(arg.text))\n hits.push({ node: arg, name: arg.text, text: arg.getText(source), detail: '' });\n }\n }\n });\n return hits;\n}\n\nexport const retiredSegmentGuard: GenericGuardDefinition<RetiredSegmentFacts> = {\n id: 'firestoreRetiredSegments',\n absentWhen: 'the app has retired no Firestore segment name',\n factProblems(facts) {\n const problems: string[] = [];\n reviewedProblems(facts?.reviewedMatches, 'reviewedMatches', problems, {\n key: 'file',\n id: (e) =>\n typeof e.contains === 'string' && e.contains ? `${e.file} ${e.contains}` : undefined,\n idNames: 'text it contains',\n });\n if (!isList(facts?.segments) || !facts.segments.length)\n return [...problems, 'segments is empty (declare the guard absent instead)'];\n const names = facts.segments.map((s) => s?.name);\n for (const s of facts.segments) {\n if (typeof s?.name !== 'string' || !/^[\\w$-]+$/.test(s.name))\n problems.push(`segments: ${String(s?.name)} is not a segment name`);\n if (typeof s?.replacement !== 'string' || !s.replacement.trim())\n problems.push(`segments: ${String(s?.name)} names no replacement`);\n }\n if (new Set(names).size !== names.length) problems.push('segments names one entry twice');\n return problems;\n },\n build(facts) {\n const replacement = new Map(facts.segments.map((s) => [s.name, s.replacement]));\n const names = [...replacement.keys()];\n const scope: Scope = {\n roots: ['app', 'functions', 'scripts', 'e2e', 'hostedE2e', 'workers'],\n optionalRoots: ['functions', 'scripts', 'e2e', 'hostedE2e', 'workers'],\n kinds: ['code'],\n tests: true,\n };\n return [\n {\n title: 'no retired Firestore segment survives in a path string',\n description:\n 'A segment name inside a string is never type-checked, so a retired name keeps addressing a collection that no ' +\n 'longer exists — a trigger that never fires, a read that returns nothing, a fixture nobody reads. Flagged: a ' +\n 'retired name in path position in any string or template (`/name/`, or `/name` closing it), and a retired name ' +\n \"as a collectionGroup id. Fix: build the path through the core. A reviewed match names a literal's text that \" +\n 'is not a Firestore path, with its why; one that matches nothing is stale.',\n timeoutMs: REPOSITORY_GUARD_TIMEOUT_MS,\n run(context) {\n const findings: Finding[] = [];\n const used = new Set<number>();\n for (const file of context.files(scope)) {\n for (const hit of retiredSegmentHits(file, names)) {\n const index = facts.reviewedMatches.findIndex(\n (r) => r.file === file.path && hit.text.includes(r.contains),\n );\n if (index !== -1) {\n used.add(index);\n continue;\n }\n findings.push({\n file: file.path,\n line: lineOfNode(file, hit.node),\n detail: `retired segment '${hit.name}' (now '${replacement.get(hit.name)}') in ${hit.text.slice(0, 80)}`,\n });\n }\n }\n facts.reviewedMatches.forEach((r, i) => {\n if (!used.has(i))\n findings.push({\n file: r.file,\n detail: `stale reviewed match: no retired segment in a literal containing \"${r.contains}\"`,\n });\n });\n return findings;\n },\n },\n ];\n },\n};\n"]}
1
+ {"version":3,"file":"path-guards.js","sourceRoot":"","sources":["../../../src/modules/firestore/path-guards.ts"],"names":[],"mappings":"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","sourcesContent":["import ts from 'typescript';\nimport type { Finding } from '../../guard.js';\nimport type { GenericGuardDefinition } from '../../node/suite/config.js';\nimport type { Scope } from '../../node/reader.js';\nimport type { Reviewed } from '../../node/layout.js';\nimport type { FileView } from '../../reader/view.js';\nimport { calleeName, forEachNode, isPlainString, lineOfNode, unwrap } from '../../support/ast.js';\nimport { namesProblem, reviewedProblems, takesNoFacts, isList } from '../../support/facts.js';\nimport { escapeRegExp } from '../../support/text.js';\nimport {\n bannedGuard,\n findingsOf,\n isMemberOf,\n literalBindings,\n type NoFacts,\n type NodeHit,\n} from './support.js';\nimport { REPOSITORY_GUARD_TIMEOUT_MS } from '../../support/timeouts.js';\nimport { routePrefixPattern, routePrefixProblems } from '../core-definitions/app-routes.js';\n\nconst ACCESSORS = new Set(['collection', 'collectionGroup', 'doc']);\n\nconst APP_CODE: Scope = {\n roots: ['app', 'functions'],\n optionalRoots: ['functions'],\n kinds: ['code'],\n tests: false,\n};\n\nfunction isHandle(node: ts.Expression): boolean {\n const plain = (n: ts.Expression): boolean =>\n ts.isIdentifier(n) || (ts.isPropertyAccessExpression(n) && plain(n.expression));\n return (\n plain(node) ||\n (ts.isCallExpression(node) && node.arguments.length === 0 && plain(node.expression))\n );\n}\n\nfunction accessorPathArguments(\n call: ts.CallExpression,\n): { form: 'method' | 'modular'; args: readonly ts.Expression[] } | null {\n const callee = call.expression;\n if (ts.isPropertyAccessExpression(callee) && ACCESSORS.has(callee.name.text))\n return { form: 'method', args: call.arguments };\n if (\n ts.isIdentifier(callee) &&\n ACCESSORS.has(callee.text) &&\n call.arguments.length >= 2 &&\n isHandle(call.arguments[0])\n ) {\n return { form: 'modular', args: call.arguments.slice(1) };\n }\n return null;\n}\n\nexport function literalSegmentHits(file: FileView): NodeHit[] {\n const source = file.sourceFile;\n const bindings = literalBindings(source);\n const typed = (arg: ts.Expression): string | null => {\n const value = unwrap(arg);\n if (isPlainString(value)) return `'${value.text}'`;\n if (ts.isIdentifier(value) && bindings.has(value.text))\n return `${value.text} (bound to '${bindings.get(value.text)}')`;\n return null;\n };\n const hits: NodeHit[] = [];\n forEachNode(source, (node) => {\n if (!ts.isCallExpression(node)) return;\n const accessor = accessorPathArguments(node);\n if (!accessor) return;\n const name = calleeName(node);\n if (accessor.form === 'method') {\n // The Admin SDK accessor takes the whole segment as its one argument.\n if (accessor.args.length !== 1) return;\n const segment = typed(accessor.args[0]);\n if (segment)\n hits.push({\n node: (node.expression as ts.PropertyAccessExpression).name,\n detail: `.${name}(${segment})`,\n });\n return;\n }\n const segments = accessor.args\n .filter((arg) => !ts.isSpreadElement(arg))\n .map(typed)\n .filter((s): s is string => s !== null);\n if (segments.length) hits.push({ node, detail: `${name}(db, …) with ${segments.join(', ')}` });\n });\n return hits;\n}\n\nexport const literalSegmentGuard: GenericGuardDefinition<NoFacts> = {\n id: 'firestoreLiteralSegments',\n absentWhen: 'the app stores nothing in Firestore',\n factProblems: takesNoFacts,\n build() {\n return [\n bannedGuard({\n title: 'no typed path segment reaches a Firestore accessor',\n description:\n 'A collection or document segment comes from the core package, never a string typed at the call. Flagged: a ' +\n 'string literal (or a name bound to one in the same file) as the whole argument of x.collection / ' +\n 'x.collectionGroup / x.doc, on every link of a chain, and in ANY path position after the handle of the ' +\n 'modular collection(db, …) / collectionGroup(db, …) / doc(db, …). A literal whose text equals the constant is ' +\n \"still the violation. Fix: import the owner — the core's collection constant, or its path builder.\",\n scope: APP_CODE,\n match: literalSegmentHits,\n }),\n ];\n },\n};\n\nexport interface PathAssemblyFacts {\n ownerConstants: readonly string[];\n segmentArrayJoiners: readonly string[];\n reviewedSites: readonly Reviewed[];\n}\n\nconst hasSlash = (node: ts.Expression) => isPlainString(node) && node.text.includes('/');\n\nfunction concatenationOperands(node: ts.Expression): ts.Expression[] {\n const value = unwrap(node);\n if (ts.isBinaryExpression(value) && value.operatorToken.kind === ts.SyntaxKind.PlusToken) {\n return [...concatenationOperands(value.left), ...concatenationOperands(value.right)];\n }\n return [value];\n}\n\nexport function pathAssemblyHits(\n file: FileView,\n facts: Pick<PathAssemblyFacts, 'ownerConstants' | 'segmentArrayJoiners'>,\n): NodeHit[] {\n const owners = new Set(facts.ownerConstants);\n const joiners = new Set(facts.segmentArrayJoiners);\n const isOwner = (node: ts.Expression) => isMemberOf(unwrap(node), owners);\n const hits = new Map<number, NodeHit>();\n const hit = (node: ts.Node, detail: string) => {\n const at = node.getStart(file.sourceFile);\n if (!hits.has(at)) hits.set(at, { node, detail });\n };\n forEachNode(file.sourceFile, (node) => {\n if (ts.isCallExpression(node)) {\n const accessor = accessorPathArguments(node);\n for (const raw of accessor?.args ?? []) {\n const arg = unwrap(raw);\n if (ts.isTemplateExpression(arg)) {\n if (arg.templateSpans.some((span) => isOwner(span.expression)))\n hit(arg, 'an owner constant spliced into a template path');\n else if (\n (arg.head.text + arg.templateSpans.map((s) => s.literal.text).join('')).includes('/')\n ) {\n hit(arg, 'a template path built from a `/` and a hole');\n }\n } else if (ts.isBinaryExpression(arg) && concatenationOperands(arg).some(hasSlash)) {\n hit(arg, 'a slash path concatenated at the accessor');\n }\n }\n const name = calleeName(node);\n if (name && joiners.has(name)) {\n for (const arg of node.arguments) {\n const value = unwrap(arg);\n if (\n ts.isArrayLiteralExpression(value) &&\n value.elements.some((e) => !ts.isSpreadElement(e) && isOwner(e))\n ) {\n hit(value, `a segment array handed to ${name}() with an owner constant in it`);\n }\n }\n }\n } else if (ts.isTemplateExpression(node)) {\n node.templateSpans.forEach((span, i) => {\n const followedByHole = i < node.templateSpans.length - 1;\n if (isOwner(span.expression) && span.literal.text === '/' && followedByHole) {\n hit(node, 'an owner constant joined to a hole with a `/`');\n }\n });\n } else if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.PlusToken) {\n const left = unwrap(node.left);\n const right = unwrap(node.right);\n if ((isOwner(left) && hasSlash(right)) || (hasSlash(left) && isOwner(right)))\n hit(node, 'an owner constant concatenated with a slash');\n }\n });\n return [...hits.values()].sort(\n (a, b) => a.node.getStart(file.sourceFile) - b.node.getStart(file.sourceFile),\n );\n}\n\nexport const pathAssemblyGuard: GenericGuardDefinition<PathAssemblyFacts> = {\n id: 'firestorePathAssembly',\n absentWhen: 'the app stores nothing in Firestore',\n factProblems(facts) {\n const problems: string[] = [];\n namesProblem(facts?.ownerConstants, 'ownerConstants', problems);\n namesProblem(facts?.segmentArrayJoiners, 'segmentArrayJoiners', problems, { nonEmpty: false });\n reviewedProblems(facts?.reviewedSites, 'reviewedSites', problems);\n return problems;\n },\n build(facts) {\n const reviewed = new Map(facts.reviewedSites.map((s) => [s.path, s]));\n return [\n {\n title: 'no Firestore path is assembled by hand',\n description:\n \"A path's string form derives from the core's path builder; writing it again at the call is a second spelling. \" +\n 'Flagged: an owner constant spliced into an accessor template; an accessor template holding both a `/` and a ' +\n 'hole, in either order; a slash-bearing literal concatenated in an accessor argument; an owner constant joined ' +\n 'to a hole by a `/` in any template, or concatenated with a slash-bearing literal anywhere; a segment array ' +\n \"holding an owner constant handed to a path joiner. Fix: call the core's path builder. A reviewed site is a file \" +\n 'with its why; an entry whose file no longer assembles a path is stale.',\n timeoutMs: REPOSITORY_GUARD_TIMEOUT_MS,\n run(context) {\n const findings: Finding[] = [];\n const held = new Set<string>();\n for (const file of context.files(APP_CODE)) {\n const hits = pathAssemblyHits(file, facts);\n if (!hits.length) continue;\n if (reviewed.has(file.path)) held.add(file.path);\n else findings.push(...findingsOf(file, hits));\n }\n for (const path of reviewed.keys()) {\n if (!held.has(path))\n findings.push({\n file: path,\n detail: 'stale reviewed site: the file no longer assembles a path (or is gone)',\n });\n }\n return findings;\n },\n },\n ];\n },\n};\n\nexport interface RetiredSegmentFacts {\n segments: ReadonlyArray<{ name: string; replacement: string }>;\n routePrefixes: readonly string[];\n reviewedMatches: ReadonlyArray<{ file: string; contains: string; why: string }>;\n}\n\nconst SOURCE_FILE = /\\.[cm]?[jt]sx?$/;\n\nexport function retiredSegmentHits(\n file: FileView,\n names: readonly string[],\n routePrefixes: readonly string[],\n): Array<NodeHit & { name: string; text: string }> {\n const source = file.sourceFile;\n const retired = new Set(names);\n const alternation = names.map(escapeRegExp).join('|');\n const inside = new RegExp(`/(${alternation})(?=/)`, 'g');\n const closing = new RegExp(`/(${alternation})$`);\n const routes = routePrefixes.map(routePrefixPattern);\n const specifiers = new Set<ts.Node>(file.imports.map((site) => site.specifier));\n const hits: Array<NodeHit & { name: string; text: string }> = [];\n const scan = (node: ts.Node, parts: Array<{ text: string; closes: boolean }>) => {\n const opening = parts[0].text;\n const whole = parts.map((p) => p.text).join('');\n if (\n specifiers.has(node) ||\n routes.some((route) => route.test(opening)) ||\n SOURCE_FILE.test(whole)\n )\n return;\n const found: string[] = [];\n for (const { text, closes } of parts) {\n for (const m of text.matchAll(inside)) found.push(m[1]);\n const end = closes ? closing.exec(text) : null;\n if (end) found.push(end[1]);\n }\n for (const name of found) hits.push({ node, name, text: node.getText(source), detail: '' });\n };\n forEachNode(source, (node) => {\n if (isPlainString(node)) scan(node, [{ text: node.text, closes: true }]);\n else if (ts.isTemplateExpression(node)) {\n scan(node, [\n { text: node.head.text, closes: false },\n ...node.templateSpans.map((s, i) => ({\n text: s.literal.text,\n closes: i === node.templateSpans.length - 1,\n })),\n ]);\n }\n if (ts.isCallExpression(node) && calleeName(node) === 'collectionGroup') {\n for (const arg of node.arguments) {\n if (isPlainString(arg) && retired.has(arg.text))\n hits.push({ node: arg, name: arg.text, text: arg.getText(source), detail: '' });\n }\n }\n });\n return hits;\n}\n\nexport const retiredSegmentGuard: GenericGuardDefinition<RetiredSegmentFacts> = {\n id: 'firestoreRetiredSegments',\n absentWhen: 'the app has retired no Firestore segment name',\n factProblems(facts) {\n const problems: string[] = [];\n reviewedProblems(facts?.reviewedMatches, 'reviewedMatches', problems, {\n key: 'file',\n id: (e) =>\n typeof e.contains === 'string' && e.contains ? `${e.file} ${e.contains}` : undefined,\n idNames: 'text it contains',\n });\n namesProblem(facts?.routePrefixes, 'routePrefixes', problems, { nonEmpty: false });\n routePrefixProblems(facts?.routePrefixes, 'routePrefixes', problems);\n if (!isList(facts?.segments) || !facts.segments.length)\n return [...problems, 'segments is empty (declare the guard absent instead)'];\n const names = facts.segments.map((s) => s?.name);\n for (const s of facts.segments) {\n if (typeof s?.name !== 'string' || !/^[\\w$-]+$/.test(s.name))\n problems.push(`segments: ${String(s?.name)} is not a segment name`);\n if (typeof s?.replacement !== 'string' || !s.replacement.trim())\n problems.push(`segments: ${String(s?.name)} names no replacement`);\n }\n if (new Set(names).size !== names.length) problems.push('segments names one entry twice');\n return problems;\n },\n build(facts) {\n const replacement = new Map(facts.segments.map((s) => [s.name, s.replacement]));\n const names = [...replacement.keys()];\n const scope: Scope = {\n roots: ['app', 'functions', 'scripts', 'e2e', 'hostedE2e', 'workers'],\n optionalRoots: ['functions', 'scripts', 'e2e', 'hostedE2e', 'workers'],\n kinds: ['code'],\n tests: true,\n };\n return [\n {\n title: 'no retired Firestore segment survives in a path string',\n description:\n 'A segment name inside a string is never type-checked, so a retired name keeps addressing a collection that no ' +\n 'longer exists — a trigger that never fires, a read that returns nothing, a fixture nobody reads. Flagged: a ' +\n 'retired name in path position in any string or template (`/name/`, or `/name` closing it), and a retired name ' +\n 'as a collectionGroup id. Never flagged: a module specifier (an import, re-export, `import()`, `require()`, ' +\n 'test-runner mock, or type import), a string or template that opens with one of the app page roots ' +\n `(${facts.routePrefixes.join(', ') || 'none declared'}) as a whole segment, and a string or template that ` +\n 'names a source file (it ends in a .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, or .cts extension). Fix: build the path ' +\n \"through the core. A reviewed match names a literal's text that is not a Firestore path, with its why; one that \" +\n 'matches nothing is stale.',\n timeoutMs: REPOSITORY_GUARD_TIMEOUT_MS,\n run(context) {\n const findings: Finding[] = [];\n const used = new Set<number>();\n for (const file of context.files(scope)) {\n for (const hit of retiredSegmentHits(file, names, facts.routePrefixes)) {\n const index = facts.reviewedMatches.findIndex(\n (r) => r.file === file.path && hit.text.includes(r.contains),\n );\n if (index !== -1) {\n used.add(index);\n continue;\n }\n findings.push({\n file: file.path,\n line: lineOfNode(file, hit.node),\n detail: `retired segment '${hit.name}' (now '${replacement.get(hit.name)}') in ${hit.text.slice(0, 80)}`,\n });\n }\n }\n facts.reviewedMatches.forEach((r, i) => {\n if (!used.has(i))\n findings.push({\n file: r.file,\n detail: `stale reviewed match: no retired segment in a literal containing \"${r.contains}\"`,\n });\n });\n return findings;\n },\n },\n ];\n },\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"read-failures.d.ts","sourceRoot":"","sources":["../../../src/modules/frontend-reads/read-failures.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAEzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAA8C,KAAK,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAC9F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAiBrD,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAWD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,eAAO,MAAM,mBAAmB,EAAE,sBAAsB,CAAC,mBAAmB,CAoC3E,CAAC;AAEF,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,WAAW,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAmHD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,GAAG,GAAG,EAAE,CAqB1F;AAoHD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,QAAQ,GAAG,GAAG,EAAE,CAuB9D;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,GAAG,GAAG,EAAE,CA6B5E;AAaD,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,QAAQ,GAAG,GAAG,EAAE,CA+BlE;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,GAAG,GAAG,EAAE,CAiBlF;AAED,eAAO,MAAM,mBAAmB,EAAE,sBAAsB,CAAC,mBAAmB,CA2C3E,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAiHD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,QAAQ,EACd,UAAU,EAAE,SAAS,MAAM,EAAE,GAC5B,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAuDzC;AAED,eAAO,MAAM,oBAAoB,EAAE,sBAAsB,CAAC,oBAAoB,CA0B7E,CAAC;AAEF,MAAM,WAAW,yBAAyB;IACxC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,SAAS,EAAE,aAAa,CAAC,QAAQ,GAAG;QAAE,IAAI,EAAE,QAAQ,CAAA;KAAE,CAAC,CAAC;CACzD;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AA2CD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,QAAQ,EAAE,iBAAiB,EAAE,SAAS,MAAM,EAAE,GAAG,GAAG,EAAE,CA2BjG;AAED,eAAO,MAAM,yBAAyB,EAAE,sBAAsB,CAAC,yBAAyB,CAoDvF,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,aAAa,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChE,WAAW,EAAE,MAAM,CAAC;CACrB;AAgBD,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,SAAS,QAAQ,EAAE,EAC1B,KAAK,EAAE,qBAAqB,GAC3B,QAAQ,EAAE,CAYZ;AAED,eAAO,MAAM,qBAAqB,EAAE,sBAAsB,CAAC,qBAAqB,CA8C/E,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,SAAS,QAAQ,EAAE,CAAC;CAChC;AAED,eAAO,MAAM,qBAAqB,QACqH,CAAC;AAExJ,eAAO,MAAM,oBAAoB,EAAE,sBAAsB,CAAC,oBAAoB,CAqC7E,CAAC;AAEF,eAAO,MAAM,mBAAmB,mSAOtB,CAAC"}
1
+ {"version":3,"file":"read-failures.d.ts","sourceRoot":"","sources":["../../../src/modules/frontend-reads/read-failures.ts"],"names":[],"mappings":"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"}
@@ -690,7 +690,7 @@ export const defaultedReadBindingGuard = {
690
690
  ];
691
691
  },
692
692
  };
693
- const PAGES = /\b(?:fetchNextPage|hasNextPage)\b/;
693
+ const LOADS_MORE = /\bfetchNextPage\b/;
694
694
  function routedPattern(routes) {
695
695
  return new RegExp(routes
696
696
  .map(({ component, prop }) => prop
@@ -705,9 +705,12 @@ export function unroutedPagingSurfaces(files, facts) {
705
705
  .flatMap((f) => [...f.code.matchAll(/export function ([A-Z]\w*)/g)].map((m) => m[1])));
706
706
  const handOff = new RegExp(`<([A-Z]\\w*)\\s[^>]*?\\b${escapeRegExp(facts.handOffProp)}=\\{`, 'g');
707
707
  return files.filter((f) => {
708
- if (!PAGES.test(f.code) || routed.test(f.code))
708
+ if (routed.test(f.code))
709
709
  return false;
710
- return ![...f.code.matchAll(handOff)].some((m) => routing.has(m[1]));
710
+ const handedTo = [...f.code.matchAll(handOff)].map((m) => m[1]);
711
+ if (!LOADS_MORE.test(f.code) && !handedTo.length)
712
+ return false;
713
+ return !handedTo.some((component) => routing.has(component));
711
714
  });
712
715
  }
713
716
  export const laterPageFailureGuard = {
@@ -731,10 +734,10 @@ export const laterPageFailureGuard = {
731
734
  build: (facts) => [
732
735
  {
733
736
  title: "an infinite list's later-page failure routes through the read-state module",
734
- description: `Every surface that pages an infinite list (fetchNextPage / hasNextPage) renders it through ` +
737
+ description: `Every surface that loads more of an infinite list (fetchNextPage) or hands a list on (${facts.handOffProp}=…) renders it through ` +
735
738
  `${facts.listRoutes.map((r) => `<${r.component}${r.prop ? ` ${r.prop}=…` : ''}>`).join(' or ')} from ${facts.readStateModule}, ` +
736
- `or hands it (${facts.handOffProp}=…) to a component whose own file does, so a failed load-more retries that page instead of ` +
737
- 'refetching the whole list.',
739
+ 'or hands it to a component whose own file does, so a failed load-more retries that page instead of ' +
740
+ 'refetching the whole list. A page-by-page list, and a count that only reads hasNextPage, load nothing more and are not counted.',
738
741
  run(context) {
739
742
  const { findings, file: module } = requiredFile(context, facts.readStateModule, 'the read-state module');
740
743
  if (!module)
@@ -1 +1 @@
1
- {"version":3,"file":"read-failures.js","sourceRoot":"","sources":["../../../src/modules/frontend-reads/read-failures.ts"],"names":[],"mappings":"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","sourcesContent":["import ts from 'typescript';\nimport type { GenericGuardDefinition } from '../../node/suite/config.js';\nimport type { Finding, GuardContext } from '../../guard.js';\nimport type { FileView } from '../../reader/view.js';\nimport { matchPattern, ownerOnly, reviewedAllowlist, type Hit } from '../../shapes/shapes.js';\nimport type { Reviewed } from '../../node/layout.js';\nimport { forEachNode, lineOfNode } from '../../support/ast.js';\nimport { identifierProblem, pathProblem, reviewedProblems, isList } from '../../support/facts.js';\nimport { escapeRegExp, isUnder } from '../../support/text.js';\nimport {\n APP_CODE,\n filesUnder,\n identifierListProblem,\n isHookName,\n pathListProblem,\n requiredFile,\n} from './shared.js';\n\nconst RETRY_STATE_HELPERS = ['useReadRetryState', 'useReadRetryStates'] as const;\nconst RETRY_STATE_FIELD = 'isRetrying';\nconst HELD_ANSWER_FIELD = 'retrying';\n\nexport interface FailureSeat {\n component: string;\n retryProp: string;\n pendingProp: string;\n}\n\nfunction seatProblems(seat: FailureSeat | undefined): string[] {\n if (!seat || typeof seat !== 'object') return ['seat is missing'];\n const problems: string[] = [];\n identifierProblem(seat.component, 'seat.component', problems);\n identifierProblem(seat.retryProp, 'seat.retryProp', problems);\n identifierProblem(seat.pendingProp, 'seat.pendingProp', problems);\n return problems;\n}\n\nexport interface ReadStateOwnerFacts {\n module: string;\n seatComponent: string;\n laterPageRetry: string;\n}\n\nexport const readStateOwnerGuard: GenericGuardDefinition<ReadStateOwnerFacts> = {\n id: 'readStateOwner',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n pathProblem(facts?.module, 'module', problems);\n identifierProblem(facts?.seatComponent, 'seatComponent', problems);\n identifierProblem(facts?.laterPageRetry, 'laterPageRetry', problems);\n return problems;\n },\n build: (facts) => [\n ownerOnly({\n title: 'read failures render only through the read-state module',\n description:\n `Every read's pending, failed, and empty states render through ${facts.module}, so every failure offers Try again ` +\n `held through its retry. Nothing outside it renders <${facts.seatComponent}> or calls ${facts.laterPageRetry}(); ` +\n 'render the read through the module instead.',\n scope: APP_CODE,\n match: matchPattern(\n new RegExp(\n `<${escapeRegExp(facts.seatComponent)}\\\\b|\\\\b${escapeRegExp(facts.laterPageRetry)}\\\\s*\\\\(`,\n ),\n ),\n owners: [facts.module],\n samples: {\n flags: [\n `return <${facts.seatComponent} thing=\"rows\" />;`,\n `const retry = ${facts.laterPageRetry}(list);`,\n ],\n passes: [\n `// <${facts.seatComponent} /> named in prose only\\nconst rows = 1;`,\n `import { ${facts.seatComponent} } from './seat';`,\n ],\n },\n }),\n ],\n};\n\nexport interface ReadRetryStateFacts {\n seat: FailureSeat;\n controlPendingProp: string;\n}\n\nconst FAILURE_FLAG = String.raw`[\\w$.?]*\\b(?:isError|error)\\b`;\nconst FETCHING = String.raw`[\\w$.?]*\\bisFetching\\b`;\nconst LIVE_FLAG_PAIRS: ReadonlyArray<{ name: string; re: RegExp }> = [\n { name: 'failure flag && isFetching', re: new RegExp(`${FAILURE_FLAG}\\\\s*&&\\\\s*${FETCHING}`) },\n { name: 'isFetching && failure flag', re: new RegExp(`${FETCHING}\\\\s*&&\\\\s*${FAILURE_FLAG}`) },\n];\n\nconst FETCHING_FLAG =\n /^(?:is(?:Re)?[Ff]etching|fetchingCount|useIsFetching|fetchStatus|sourceState)$/;\n\nconst fieldName = (name: ts.Node): string | null =>\n ts.isIdentifier(name) || ts.isStringLiteralLike(name) ? name.text : null;\n\nfunction retryStateExpressions(\n file: FileView,\n fields: readonly string[],\n): Array<{ index: number; expression: ts.Expression }> {\n const sf = file.sourceFile;\n const wanted = new Set(fields);\n const found: Array<{ index: number; expression: ts.Expression }> = [];\n const add = (name: ts.Node, expression: ts.Expression | undefined) => {\n if (expression && wanted.has(fieldName(name) ?? ''))\n found.push({ index: name.getStart(sf), expression });\n };\n forEachNode(sf, (node) => {\n if (ts.isPropertyAssignment(node) || ts.isVariableDeclaration(node))\n add(node.name, node.initializer);\n else if (ts.isJsxAttribute(node) && node.initializer && ts.isJsxExpression(node.initializer))\n add(node.name, node.initializer.expression);\n else if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken) {\n add(ts.isPropertyAccessExpression(node.left) ? node.left.name : node.left, node.right);\n }\n });\n return found;\n}\n\nconst FAILURE_NAME = /^(?:isError|error)$/;\n\nfunction readsFetchingFlag(expression: ts.Node, file: FileView): boolean {\n return readsFlag(expression, file, FETCHING_FLAG);\n}\n\nfunction readsFlag(\n expression: ts.Node,\n file: FileView,\n flag: RegExp,\n seen: Set<string> = new Set(),\n): boolean {\n let reads = false;\n const bound: string[] = [];\n forEachNode(expression, (node) => {\n if (!ts.isIdentifier(node) || reads) return;\n if (flag.test(node.text)) reads = true;\n const parent = node.parent;\n const receiverOrCallee =\n (ts.isPropertyAccessExpression(parent) &&\n (parent.expression === node || parent.name === node)) ||\n (ts.isCallExpression(parent) && parent.expression === node);\n if (!receiverOrCallee) bound.push(node.text);\n });\n if (reads) return true;\n return bound.some((name) => {\n if (seen.has(name)) return false;\n seen.add(name);\n let declared: ts.Expression | undefined;\n let renamed = false;\n forEachNode(file.sourceFile, (node) => {\n if (\n ts.isBindingElement(node) &&\n ts.isIdentifier(node.name) &&\n node.name.text === name &&\n node.propertyName &&\n flag.test(fieldName(node.propertyName) ?? '')\n ) {\n renamed = true;\n } else if (\n !declared &&\n ts.isVariableDeclaration(node) &&\n ts.isIdentifier(node.name) &&\n node.name.text === name &&\n node.initializer\n ) {\n declared = node.initializer;\n }\n });\n if (renamed) return true;\n if (!declared) return false;\n const value = declared;\n const fromHelper =\n ts.isCallExpression(value) &&\n ts.isIdentifier(value.expression) &&\n (RETRY_STATE_HELPERS as readonly string[]).includes(value.expression.text);\n return !fromHelper && readsFlag(value, file, flag, seen);\n });\n}\n\nfunction branchConditionsAbove(node: ts.Node): ts.Expression[] {\n const conditions: ts.Expression[] = [];\n for (let child = node, parent = node.parent; parent; child = parent, parent = parent.parent) {\n if (ts.isIfStatement(parent) && parent.thenStatement === child)\n conditions.push(parent.expression);\n else if (ts.isConditionalExpression(parent) && parent.whenTrue === child)\n conditions.push(parent.condition);\n else if (\n ts.isBinaryExpression(parent) &&\n parent.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken &&\n parent.right === child\n )\n conditions.push(parent.left);\n }\n return conditions;\n}\n\nexport function failureBranchLivePending(file: FileView, controlPendingProp: string): Hit[] {\n const sf = file.sourceFile;\n const hits: Hit[] = [];\n forEachNode(sf, (node) => {\n if (\n !ts.isJsxAttribute(node) ||\n fieldName(node.name) !== controlPendingProp ||\n !node.initializer ||\n !ts.isJsxExpression(node.initializer) ||\n !node.initializer.expression\n )\n return;\n const pending = node.initializer.expression;\n if (!readsFetchingFlag(pending, file)) return;\n if (!branchConditionsAbove(node).some((c) => readsFlag(c, file, FAILURE_NAME))) return;\n hits.push({\n index: node.getStart(sf),\n detail: `a failure's retry pending from a fetching flag: ${pending.getText(sf).replace(/\\s+/g, ' ').slice(0, 120)}`,\n });\n });\n return hits;\n}\n\nconst LOADING_FIELD = 'isLoading';\nconst READ_FAILURE_FIELDS = new Set(['error', 'isError', 'retryState']);\nconst HELD_RECEIVER = /retry/i;\n\ninterface Destructured {\n field: string;\n receiver: string;\n scope: ts.Node;\n}\n\ntype Bindings = Map<string, Destructured[]>;\n\nfunction scopeOf(node: ts.Node): ts.Node {\n return enclosingFunctionOf(node) ?? node.getSourceFile();\n}\n\nfunction destructuredBindings(sf: ts.SourceFile): Bindings {\n const bindings: Bindings = new Map();\n forEachNode(sf, (node) => {\n if (\n !ts.isVariableDeclaration(node) ||\n !ts.isObjectBindingPattern(node.name) ||\n !node.initializer ||\n !ts.isIdentifier(node.initializer)\n )\n return;\n const receiver = node.initializer.text;\n const scope = scopeOf(node);\n for (const element of node.name.elements) {\n if (!ts.isIdentifier(element.name)) continue;\n const field = element.propertyName ? fieldName(element.propertyName) : element.name.text;\n if (!field) continue;\n const named = bindings.get(element.name.text) ?? [];\n named.push({ field, receiver, scope });\n bindings.set(element.name.text, named);\n }\n });\n return bindings;\n}\n\nfunction declaresParameter(fn: ts.SignatureDeclaration, name: string): boolean {\n let declares = false;\n for (const parameter of fn.parameters)\n forEachNode(parameter.name, (node) => {\n if (ts.isIdentifier(node) && node.text === name) declares = true;\n });\n return declares;\n}\n\nfunction bindingFor(use: ts.Identifier, bindings: Bindings): Destructured | undefined {\n const named = bindings.get(use.text);\n if (!named) return undefined;\n for (let scope: ts.Node | undefined = scopeOf(use); scope;) {\n const found = named.find((binding) => binding.scope === scope);\n if (found) return found;\n if (ts.isFunctionLike(scope) && declaresParameter(scope, use.text)) return undefined;\n scope = ts.isSourceFile(scope) ? undefined : scopeOf(scope);\n }\n return undefined;\n}\n\nfunction rootIdentifier(node: ts.Expression): string | null {\n let current: ts.Expression = node;\n while (ts.isPropertyAccessExpression(current) || ts.isNonNullExpression(current))\n current = current.expression;\n return ts.isIdentifier(current) ? current.text : null;\n}\n\ninterface ReadField {\n receiver: string;\n index: number;\n}\n\nfunction readFieldsIn(\n scope: ts.Node,\n bindings: Bindings,\n wanted: (field: string) => boolean,\n): ReadField[] {\n const sf = scope.getSourceFile();\n const found: ReadField[] = [];\n forEachNode(scope, (node) => {\n if (ts.isPropertyAccessExpression(node) && wanted(node.name.text)) {\n const receiver = rootIdentifier(node.expression);\n if (receiver && !HELD_RECEIVER.test(node.expression.getText(sf)))\n found.push({ receiver, index: node.getStart(sf) });\n } else if (\n ts.isIdentifier(node) &&\n !(ts.isPropertyAccessExpression(node.parent) && node.parent.name === node)\n ) {\n const bound = bindingFor(node, bindings);\n if (bound && wanted(bound.field) && !HELD_RECEIVER.test(bound.receiver))\n found.push({ receiver: bound.receiver, index: node.getStart(sf) });\n }\n });\n return found;\n}\n\nfunction enclosingFunctionOf(node: ts.Node): ts.Node | undefined {\n for (let p = node.parent; p; p = p.parent) if (ts.isFunctionLike(p)) return p;\n return undefined;\n}\n\nfunction branchCondition(node: ts.Node): ts.Expression | undefined {\n if (ts.isIfStatement(node)) return node.expression;\n if (ts.isConditionalExpression(node)) return node.condition;\n if (\n ts.isBinaryExpression(node) &&\n node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken &&\n ts.isJsxExpression(node.parent)\n )\n return node.left;\n return undefined;\n}\n\nexport function liveLoadingBeforeFailure(file: FileView): Hit[] {\n const sf = file.sourceFile;\n const bindings = destructuredBindings(sf);\n const isLoading = (field: string) => field === LOADING_FIELD;\n const isFailure = (field: string) => READ_FAILURE_FIELDS.has(field);\n const hits: Hit[] = [];\n forEachNode(sf, (node) => {\n const condition = branchCondition(node);\n const fn = condition && enclosingFunctionOf(node);\n if (!condition || !fn) return;\n const tested = new Set(readFieldsIn(condition, bindings, isFailure).map((r) => r.receiver));\n const end = condition.getEnd();\n const later = readFieldsIn(fn, bindings, isFailure).filter((r) => r.index >= end);\n const loading = readFieldsIn(condition, bindings, isLoading).find(\n (r) => !tested.has(r.receiver) && later.some((f) => f.receiver === r.receiver),\n );\n if (loading)\n hits.push({\n index: loading.index,\n detail: `a live loading flag tested before the read's failure: ${condition.getText(sf).replace(/\\s+/g, ' ').slice(0, 120)}`,\n });\n });\n return hits;\n}\n\nexport function liveFlagRetryStates(file: FileView, seat: FailureSeat): Hit[] {\n const code = file.code;\n const hits = new Map<number, Hit>();\n let offset = 0;\n for (const line of code.split('\\n')) {\n for (const shape of LIVE_FLAG_PAIRS) {\n const m = shape.re.exec(line);\n if (m)\n hits.set(file.lineOf(offset + m.index), {\n index: offset + m.index,\n detail: `${shape.name}: ${line.trim().slice(0, 120)}`,\n });\n }\n offset += line.length + 1;\n }\n for (const { index, expression } of retryStateExpressions(file, [\n RETRY_STATE_FIELD,\n HELD_ANSWER_FIELD,\n seat.pendingProp,\n ])) {\n if (!readsFetchingFlag(expression, file)) continue;\n const line = file.lineOf(index);\n if (!hits.has(line))\n hits.set(line, {\n index,\n detail: `retry state from a fetching flag: ${expression.getText(file.sourceFile).replace(/\\s+/g, ' ').slice(0, 120)}`,\n });\n }\n return [...hits.values()].sort((a, b) => a.index - b.index);\n}\n\nconst isHookFunction = (node: ts.Node, sf: ts.SourceFile): boolean => {\n if ((ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node)) && node.name)\n return isHookName(node.name.text);\n if (\n (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) &&\n ts.isVariableDeclaration(node.parent)\n )\n return isHookName(node.parent.name.getText(sf));\n return false;\n};\n\nexport function failedAnswersWithoutRetrying(file: FileView): Hit[] {\n const sf = file.sourceFile;\n const hits: Hit[] = [];\n forEachNode(sf, (node) => {\n if (!ts.isObjectLiteralExpression(node)) return;\n const named = (name: string) =>\n node.properties.find(\n (p) =>\n (ts.isPropertyAssignment(p) || ts.isShorthandPropertyAssignment(p)) &&\n p.name.getText(sf) === name,\n );\n const status = named('status');\n if (\n !status ||\n !ts.isPropertyAssignment(status) ||\n !ts.isStringLiteralLike(status.initializer) ||\n status.initializer.text !== 'failed'\n )\n return;\n if (!named('error') || named(HELD_ANSWER_FIELD) || node.properties.some(ts.isSpreadAssignment))\n return;\n let inHook = false;\n for (let p: ts.Node | undefined = node.parent; p && !inHook; p = p.parent)\n inHook = isHookFunction(p, sf);\n if (inHook)\n hits.push({\n index: node.getStart(sf),\n detail: `a failed answer with no ${HELD_ANSWER_FIELD}: ${node.getText(sf).replace(/\\s+/g, ' ').slice(0, 120)}`,\n });\n });\n return hits;\n}\n\nexport function seatRetriesWithoutPending(file: FileView, seat: FailureSeat): Hit[] {\n const hits: Hit[] = [];\n const element = new RegExp(`<${escapeRegExp(seat.component)}\\\\b[\\\\s\\\\S]*?\\\\/>`, 'g');\n for (const match of file.code.matchAll(element)) {\n const text = match[0];\n if (\n new RegExp(`\\\\b${escapeRegExp(seat.retryProp)}=`).test(text) &&\n !new RegExp(`\\\\b${escapeRegExp(seat.pendingProp)}=`).test(text) &&\n !/\\{\\s*\\.\\.\\./.test(text)\n ) {\n hits.push({\n index: match.index ?? 0,\n detail: `<${seat.component} ${seat.retryProp}=…> without ${seat.pendingProp}`,\n });\n }\n }\n return hits;\n}\n\nexport const readRetryStateGuard: GenericGuardDefinition<ReadRetryStateFacts> = {\n id: 'readRetryState',\n absentWhen: false,\n factProblems(facts) {\n const problems = seatProblems(facts?.seat);\n identifierProblem(facts?.controlPendingProp, 'controlPendingProp', problems);\n return problems;\n },\n build: (facts) => [\n {\n title: \"a read's retry state comes from its one owner, never the live fetching flags\",\n description:\n 'TanStack Query puts a query that never succeeded back to pending and clears its error the moment a refetch starts, so a retry ' +\n 'state built from isFetching / isRefetching / fetchStatus with isError or error reads false for the retry of a failed first read, ' +\n `and the failure turns into a loading state under the pressed retry. Hold the failure with query-core's ${RETRY_STATE_HELPERS.join(' / ')} ` +\n `(exposed from the read's hook) and pass its ${RETRY_STATE_FIELD}; a lookup hands out its held ${HELD_ANSWER_FIELD}, and a hook ` +\n `that answers with a status gives its failed answer the held ${HELD_ANSWER_FIELD} beside the error, never one built from a ` +\n `fetching flag; and every <${facts.seat.component}> given ${facts.seat.retryProp} also takes ${facts.seat.pendingProp}, so the ` +\n `pressed retry shows it is running. The same live flags decide no failure surface: a control's ${facts.controlPendingProp} ` +\n \"inside a failure branch reads the held isRetrying, never a fetching flag, and a branch never tests a read's live isLoading \" +\n \"ahead of that read's failure — the held retryState decides the failure first, then its isLoading.\",\n run(context: GuardContext): Finding[] {\n const findings: Finding[] = [];\n for (const file of context.files(APP_CODE)) {\n const hits = [\n ...liveFlagRetryStates(file, facts.seat),\n ...seatRetriesWithoutPending(file, facts.seat),\n ...failedAnswersWithoutRetrying(file),\n ...failureBranchLivePending(file, facts.controlPendingProp),\n ...liveLoadingBeforeFailure(file),\n ];\n for (const hit of hits) {\n findings.push({\n file: file.path,\n line: file.lineOf(hit.index),\n detail: hit.detail ?? '',\n });\n }\n }\n return findings;\n },\n },\n ],\n};\n\nexport interface HookReadDefaultFacts {\n hooksTree: string;\n readCollapsers: readonly string[];\n}\n\nconst FAILURE_FIELDS = new Set(['error', 'isError', 'status']);\n\nfunction isEmptyAnswer(node: ts.Expression): boolean {\n return (\n (ts.isArrayLiteralExpression(node) && node.elements.length === 0) ||\n (ts.isObjectLiteralExpression(node) && node.properties.length === 0) ||\n node.kind === ts.SyntaxKind.FalseKeyword ||\n node.kind === ts.SyntaxKind.NullKeyword ||\n (ts.isNumericLiteral(node) && node.text === '0') ||\n (ts.isStringLiteral(node) && node.text === '')\n );\n}\n\nfunction enclosingFunction(node: ts.Node): ts.Node | undefined {\n let current: ts.Node | undefined = node.parent;\n while (current && !ts.isFunctionLike(current)) current = current.parent;\n return current;\n}\n\nfunction readsFailureOf(scope: ts.Node, receiver: string, sf: ts.SourceFile): boolean {\n let found = false;\n forEachNode(scope, (n) => {\n if (\n ts.isPropertyAccessExpression(n) &&\n FAILURE_FIELDS.has(n.name.text) &&\n n.expression.getText(sf) === receiver\n )\n found = true;\n if (\n ts.isCallExpression(n) &&\n n.expression.getText(sf) === RETRY_STATE_HELPERS[0] &&\n n.arguments[0]?.getText(sf) === receiver\n )\n found = true;\n });\n return found;\n}\n\nfunction exportedHookBody(\n node: ts.Node,\n sf: ts.SourceFile,\n): { name: string; body: ts.ConciseBody } | undefined {\n const isExported = (n: ts.Node) =>\n ts.canHaveModifiers(n) &&\n (ts.getModifiers(n) ?? []).some((m) => m.kind === ts.SyntaxKind.ExportKeyword);\n if (\n ts.isFunctionDeclaration(node) &&\n node.name &&\n isHookName(node.name.text) &&\n isExported(node) &&\n node.body\n ) {\n return { name: node.name.text, body: node.body };\n }\n if (\n ts.isVariableDeclaration(node) &&\n ts.isIdentifier(node.name) &&\n isHookName(node.name.text) &&\n node.initializer &&\n (ts.isArrowFunction(node.initializer) || ts.isFunctionExpression(node.initializer)) &&\n isExported(node.parent.parent)\n ) {\n return { name: node.name.getText(sf), body: node.initializer.body };\n }\n return undefined;\n}\n\nfunction returnedExpressions(body: ts.ConciseBody): ts.Expression[] {\n if (!ts.isBlock(body)) return [body];\n const out: ts.Expression[] = [];\n const visit = (n: ts.Node) => {\n if (ts.isFunctionLike(n)) return;\n if (ts.isReturnStatement(n) && n.expression) out.push(n.expression);\n ts.forEachChild(n, visit);\n };\n ts.forEachChild(body, visit);\n return out;\n}\n\nfunction readsData(node: ts.Node): boolean {\n let found = false;\n forEachNode(node, (n) => {\n if (ts.isPropertyAccessExpression(n) && n.name.text === 'data') found = true;\n });\n return found;\n}\n\nconst COMPARISONS = new Set([\n ts.SyntaxKind.EqualsEqualsEqualsToken,\n ts.SyntaxKind.ExclamationEqualsEqualsToken,\n ts.SyntaxKind.GreaterThanToken,\n ts.SyntaxKind.LessThanToken,\n ts.SyntaxKind.GreaterThanEqualsToken,\n ts.SyntaxKind.LessThanEqualsToken,\n]);\n\nfunction collapsesReadToBoolean(\n expr: ts.Expression,\n sf: ts.SourceFile,\n collapsers: ReadonlySet<string>,\n): boolean {\n let e = expr;\n while (ts.isParenthesizedExpression(e)) e = e.expression;\n if (ts.isCallExpression(e) && collapsers.has(e.expression.getText(sf))) return true;\n if (ts.isPrefixUnaryExpression(e) && e.operator === ts.SyntaxKind.ExclamationToken)\n return readsData(e);\n if (ts.isBinaryExpression(e) && COMPARISONS.has(e.operatorToken.kind)) return readsData(e);\n if (ts.isCallExpression(e) && e.expression.getText(sf) === 'Boolean') return readsData(e);\n return false;\n}\n\nexport function hookReadDefaults(\n file: FileView,\n collapsers: readonly string[],\n): Array<{ line: number; detail: string }> {\n const sf = file.sourceFile;\n const names = new Set(collapsers);\n const hits: Array<{ line: number; detail: string }> = [];\n forEachNode(sf, (node) => {\n if (\n ts.isBinaryExpression(node) &&\n (node.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken ||\n node.operatorToken.kind === ts.SyntaxKind.BarBarToken) &&\n ts.isPropertyAccessExpression(node.left) &&\n node.left.name.text === 'data' &&\n isEmptyAnswer(node.right)\n ) {\n const scope = enclosingFunction(node);\n if (!scope || !readsFailureOf(scope, node.left.expression.getText(sf), sf)) {\n hits.push({\n line: lineOfNode(file, node),\n detail: `a defaulted read with no failure beside it: ${node.getText(sf)}`,\n });\n }\n }\n if (\n ts.isVariableDeclaration(node) &&\n node.initializer &&\n ts.isObjectBindingPattern(node.name)\n ) {\n const init = node.initializer;\n if (ts.isCallExpression(init) && isHookName(init.expression.getText(sf))) {\n const keyOf = (el: ts.BindingElement) => (el.propertyName ?? el.name).getText(sf);\n const elements = node.name.elements;\n const defaultsData = elements.some(\n (el) => keyOf(el) === 'data' && el.initializer !== undefined,\n );\n const carriesFailure = elements.some(\n (el) => el.dotDotDotToken || FAILURE_FIELDS.has(keyOf(el)),\n );\n if (defaultsData && !carriesFailure)\n hits.push({\n line: lineOfNode(file, node),\n detail: `a defaulted read with no failure beside it: ${node.name.getText(sf)}`,\n });\n }\n }\n const hook = exportedHookBody(node, sf);\n if (hook) {\n for (const returned of returnedExpressions(hook.body)) {\n if (collapsesReadToBoolean(returned, sf, names))\n hits.push({\n line: lineOfNode(file, returned),\n detail: `${hook.name} returns a boolean from a read`,\n });\n }\n }\n });\n return hits;\n}\n\nexport const hookReadDefaultGuard: GenericGuardDefinition<HookReadDefaultFacts> = {\n id: 'hookReadDefault',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n pathProblem(facts?.hooksTree, 'hooksTree', problems);\n identifierListProblem(facts?.readCollapsers, 'readCollapsers', problems, { nonEmpty: false });\n return problems;\n },\n build: (facts) => [\n {\n title: 'a hook never returns a default its consumers cannot tell from data',\n description:\n `In ${facts.hooksTree}, a read's data defaulted to an empty answer (q.data ?? [], const { data = [] } = useQ()) is allowed only ` +\n `where the same function also carries that read's failure (error / isError / status, or the read handed to ${RETRY_STATE_HELPERS[0]}), ` +\n 'and no exported hook collapses a read into a bare boolean, where an unknown read would read as \"no\". Return the read state ' +\n '(pending / failed / answered) or carry the failure beside the defaulted data.',\n run(context) {\n const { files, findings } = filesUnder(context, [facts.hooksTree]);\n for (const file of files)\n for (const hit of hookReadDefaults(file, facts.readCollapsers))\n findings.push({ file: file.path, ...hit });\n return findings;\n },\n },\n ],\n};\n\nexport interface DefaultedReadBindingFacts {\n surfaceTrees: readonly string[];\n heldFailureFields: readonly string[];\n allowlist: ReadonlyArray<Reviewed & { gate: ReadGate }>;\n}\n\nexport interface ReadGate {\n file: string;\n code: string;\n}\n\nconst squashed = (text: string) => text.replace(/\\s+/g, ' ').trim();\n\nfunction gateProblems(allowlist: unknown): string[] {\n if (!isList(allowlist)) return [];\n const problems: string[] = [];\n for (const entry of allowlist as Array<{ path?: string; gate?: Partial<ReadGate> }>) {\n const what = `allowlist entry ${String(entry?.path)}`;\n if (!entry?.gate || typeof entry.gate !== 'object')\n problems.push(\n `${what} names no gate (the file and the code that hold its surface back until the read answered)`,\n );\n else {\n pathProblem(entry.gate.file, `${what}'s gate file`, problems);\n if (typeof entry.gate.code !== 'string' || !entry.gate.code.trim())\n problems.push(`${what}'s gate names no code`);\n }\n }\n return problems;\n}\n\nfunction missingGates(\n context: GuardContext,\n allowlist: DefaultedReadBindingFacts['allowlist'],\n): Finding[] {\n const findings: Finding[] = [];\n for (const { path, gate } of allowlist) {\n if (!context.reader.exists(gate.file))\n findings.push({\n file: gate.file,\n detail: `the gate ${path} relies on is gone: the file no longer exists`,\n });\n else if (!squashed(context.file(gate.file).code).includes(squashed(gate.code))) {\n findings.push({\n file: gate.file,\n detail: `the gate ${path} relies on is gone: no longer holds ${squashed(gate.code)}`,\n });\n }\n }\n return findings;\n}\n\nexport function unguardedDataDefaults(file: FileView, heldFailureFields: readonly string[]): Hit[] {\n const sf = file.sourceFile;\n const failureBindings = new Set([...FAILURE_FIELDS, ...heldFailureFields]);\n const hits: Hit[] = [];\n forEachNode(sf, (node) => {\n if (\n !ts.isVariableDeclaration(node) ||\n !node.initializer ||\n !ts.isObjectBindingPattern(node.name)\n )\n return;\n let init: ts.Expression = node.initializer;\n if (ts.isAwaitExpression(init)) init = init.expression;\n if (!ts.isCallExpression(init)) return;\n const callee = init.expression.getText(sf);\n if (!isHookName(callee)) return;\n const elements = node.name.elements;\n if (elements.some((el) => el.dotDotDotToken)) return;\n const keyOf = (el: ts.BindingElement) => (el.propertyName ?? el.name).getText(sf);\n if (!elements.some((el) => keyOf(el) === 'data' && el.initializer !== undefined)) return;\n if (elements.some((el) => failureBindings.has(keyOf(el)))) return;\n hits.push({\n index: node.getStart(sf),\n detail: `${callee}() defaults data with no failure bound`,\n });\n });\n return hits;\n}\n\nexport const defaultedReadBindingGuard: GenericGuardDefinition<DefaultedReadBindingFacts> = {\n id: 'defaultedReadBinding',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n pathListProblem(facts?.surfaceTrees, 'surfaceTrees', problems);\n identifierListProblem(facts?.heldFailureFields, 'heldFailureFields', problems, {\n nonEmpty: false,\n });\n reviewedProblems(facts?.allowlist, 'allowlist', problems);\n return [...problems, ...gateProblems(facts?.allowlist)];\n },\n build: (facts) => {\n const held = facts.heldFailureFields.length ? ` / ${facts.heldFailureFields.join(' / ')}` : '';\n const guard = reviewedAllowlist({\n title: 'a render surface that defaults a read binds its failure',\n description:\n `A render surface (${facts.surfaceTrees.join(', ')}) that defaults a read's data (const { data: rows = [] } = useRows()) binds ` +\n `that same read's failure (error / isError / status${held}) in the same destructure, and renders the pending and failed states ` +\n 'before the default is used; otherwise a failed read renders as an empty list, a zero, or a negative answer that decides a control. ' +\n 'A reviewed default names the gate that holds its surface back until the read answered, and that gate must still be there.',\n scope: APP_CODE,\n match: (file) =>\n facts.surfaceTrees.some((tree) => isUnder(file.path, tree))\n ? unguardedDataDefaults(file, facts.heldFailureFields)\n : [],\n allowlist: facts.allowlist,\n samples: {\n flags: [\n {\n path: `${facts.surfaceTrees[0]}/sample.tsx`,\n text: 'const { data: rows = [] } = useRows(id);',\n },\n ],\n passes: [\n {\n path: `${facts.surfaceTrees[0]}/sample.tsx`,\n text: 'const { data: rows = [], isError } = useRows(id);',\n },\n ],\n },\n });\n return [\n {\n ...guard,\n run: async (context) => [\n ...(await guard.run(context)),\n ...missingGates(context, facts.allowlist),\n ],\n },\n ];\n },\n};\n\nexport interface LaterPageFailureFacts {\n hooksTree: string;\n readStateModule: string;\n listRoutes: ReadonlyArray<{ component: string; prop?: string }>;\n handOffProp: string;\n}\n\nconst PAGES = /\\b(?:fetchNextPage|hasNextPage)\\b/;\n\nfunction routedPattern(routes: LaterPageFailureFacts['listRoutes']): RegExp {\n return new RegExp(\n routes\n .map(({ component, prop }) =>\n prop\n ? `<${escapeRegExp(component)}\\\\s[^>]*?\\\\b${escapeRegExp(prop)}=`\n : `<${escapeRegExp(component)}\\\\b`,\n )\n .join('|'),\n );\n}\n\nexport function unroutedPagingSurfaces(\n files: readonly FileView[],\n facts: LaterPageFailureFacts,\n): FileView[] {\n const routed = routedPattern(facts.listRoutes);\n const routing = new Set(\n files\n .filter((f) => routed.test(f.code))\n .flatMap((f) => [...f.code.matchAll(/export function ([A-Z]\\w*)/g)].map((m) => m[1])),\n );\n const handOff = new RegExp(`<([A-Z]\\\\w*)\\\\s[^>]*?\\\\b${escapeRegExp(facts.handOffProp)}=\\\\{`, 'g');\n return files.filter((f) => {\n if (!PAGES.test(f.code) || routed.test(f.code)) return false;\n return ![...f.code.matchAll(handOff)].some((m) => routing.has(m[1]));\n });\n}\n\nexport const laterPageFailureGuard: GenericGuardDefinition<LaterPageFailureFacts> = {\n id: 'laterPageFailure',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n pathProblem(facts?.hooksTree, 'hooksTree', problems);\n pathProblem(facts?.readStateModule, 'readStateModule', problems);\n identifierProblem(facts?.handOffProp, 'handOffProp', problems);\n if (!isList(facts?.listRoutes) || !facts.listRoutes.length)\n problems.push('listRoutes names no component');\n else\n facts.listRoutes.forEach((r, i) => {\n identifierProblem(r?.component, `listRoutes[${i}].component`, problems);\n if (r?.prop !== undefined) identifierProblem(r.prop, `listRoutes[${i}].prop`, problems);\n });\n return problems;\n },\n build: (facts) => [\n {\n title: \"an infinite list's later-page failure routes through the read-state module\",\n description:\n `Every surface that pages an infinite list (fetchNextPage / hasNextPage) renders it through ` +\n `${facts.listRoutes.map((r) => `<${r.component}${r.prop ? ` ${r.prop}=…` : ''}>`).join(' or ')} from ${facts.readStateModule}, ` +\n `or hands it (${facts.handOffProp}=…) to a component whose own file does, so a failed load-more retries that page instead of ` +\n 'refetching the whole list.',\n run(context) {\n const { findings, file: module } = requiredFile(\n context,\n facts.readStateModule,\n 'the read-state module',\n );\n if (!module) return findings;\n const surfaces = context\n .files(APP_CODE)\n .filter((f) => !isUnder(f.path, facts.hooksTree) && f.path !== facts.readStateModule);\n for (const file of unroutedPagingSurfaces(surfaces, facts)) {\n findings.push({\n file: file.path,\n detail:\n 'pages an infinite list without routing its later-page failure through the read-state module',\n });\n }\n return findings;\n },\n },\n ],\n};\n\nexport interface ReadFailureCopyFacts {\n owner: string;\n allowlist: readonly Reviewed[];\n}\n\nexport const READ_FAILURE_SENTENCE =\n /(?:could not|couldn['’]?t|failed to|unable to)\\s+(?:load|search|fetch|read|retrieve|check|find)\\b|error\\s+(?:loading|searching|fetching|reading)\\b/i;\n\nexport const readFailureCopyGuard: GenericGuardDefinition<ReadFailureCopyFacts> = {\n id: 'readFailureCopy',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n pathProblem(facts?.owner, 'owner', problems);\n reviewedProblems(facts?.allowlist, 'allowlist', problems);\n if (isList(facts?.allowlist) && facts.allowlist.some((e) => e?.path === facts.owner))\n problems.push('the owner is listed in the allowlist');\n return problems;\n },\n build: (facts) => [\n reviewedAllowlist({\n title: \"a read failure's copy comes from its one owner\",\n description:\n `Every read-failure sentence a person sees is built by ${facts.owner} from the short noun the surface names; no other file ` +\n 'hand-writes one (\"could not load\", \"failed to load\", \"error loading\", or the same around another read verb, in any casing). ' +\n 'Render the owner (with surface-specific guidance as its hint), or — for text never shown to a person — add a reviewed entry with its why.',\n scope: APP_CODE,\n match: matchPattern(READ_FAILURE_SENTENCE),\n allowlist: [\n { path: facts.owner, why: 'the one owner of read-failure copy' },\n ...facts.allowlist,\n ],\n samples: {\n flags: [\n '<p>Could not load the rows.</p>',\n '<AlertTitle>Error Loading Rows</AlertTitle>',\n 'const m = \"Couldn\\'t fetch the list.\";',\n ],\n passes: [\n 'hint=\"a list that could not be read is not an empty list.\"',\n '<LoadingState label=\"Loading rows\" />',\n ],\n },\n }),\n ],\n};\n\nexport const READ_FAILURE_GUARDS = [\n readStateOwnerGuard,\n readRetryStateGuard,\n hookReadDefaultGuard,\n defaultedReadBindingGuard,\n laterPageFailureGuard,\n readFailureCopyGuard,\n] as const;\n"]}
1
+ {"version":3,"file":"read-failures.js","sourceRoot":"","sources":["../../../src/modules/frontend-reads/read-failures.ts"],"names":[],"mappings":"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","sourcesContent":["import ts from 'typescript';\nimport type { GenericGuardDefinition } from '../../node/suite/config.js';\nimport type { Finding, GuardContext } from '../../guard.js';\nimport type { FileView } from '../../reader/view.js';\nimport { matchPattern, ownerOnly, reviewedAllowlist, type Hit } from '../../shapes/shapes.js';\nimport type { Reviewed } from '../../node/layout.js';\nimport { forEachNode, lineOfNode } from '../../support/ast.js';\nimport { identifierProblem, pathProblem, reviewedProblems, isList } from '../../support/facts.js';\nimport { escapeRegExp, isUnder } from '../../support/text.js';\nimport {\n APP_CODE,\n filesUnder,\n identifierListProblem,\n isHookName,\n pathListProblem,\n requiredFile,\n} from './shared.js';\n\nconst RETRY_STATE_HELPERS = ['useReadRetryState', 'useReadRetryStates'] as const;\nconst RETRY_STATE_FIELD = 'isRetrying';\nconst HELD_ANSWER_FIELD = 'retrying';\n\nexport interface FailureSeat {\n component: string;\n retryProp: string;\n pendingProp: string;\n}\n\nfunction seatProblems(seat: FailureSeat | undefined): string[] {\n if (!seat || typeof seat !== 'object') return ['seat is missing'];\n const problems: string[] = [];\n identifierProblem(seat.component, 'seat.component', problems);\n identifierProblem(seat.retryProp, 'seat.retryProp', problems);\n identifierProblem(seat.pendingProp, 'seat.pendingProp', problems);\n return problems;\n}\n\nexport interface ReadStateOwnerFacts {\n module: string;\n seatComponent: string;\n laterPageRetry: string;\n}\n\nexport const readStateOwnerGuard: GenericGuardDefinition<ReadStateOwnerFacts> = {\n id: 'readStateOwner',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n pathProblem(facts?.module, 'module', problems);\n identifierProblem(facts?.seatComponent, 'seatComponent', problems);\n identifierProblem(facts?.laterPageRetry, 'laterPageRetry', problems);\n return problems;\n },\n build: (facts) => [\n ownerOnly({\n title: 'read failures render only through the read-state module',\n description:\n `Every read's pending, failed, and empty states render through ${facts.module}, so every failure offers Try again ` +\n `held through its retry. Nothing outside it renders <${facts.seatComponent}> or calls ${facts.laterPageRetry}(); ` +\n 'render the read through the module instead.',\n scope: APP_CODE,\n match: matchPattern(\n new RegExp(\n `<${escapeRegExp(facts.seatComponent)}\\\\b|\\\\b${escapeRegExp(facts.laterPageRetry)}\\\\s*\\\\(`,\n ),\n ),\n owners: [facts.module],\n samples: {\n flags: [\n `return <${facts.seatComponent} thing=\"rows\" />;`,\n `const retry = ${facts.laterPageRetry}(list);`,\n ],\n passes: [\n `// <${facts.seatComponent} /> named in prose only\\nconst rows = 1;`,\n `import { ${facts.seatComponent} } from './seat';`,\n ],\n },\n }),\n ],\n};\n\nexport interface ReadRetryStateFacts {\n seat: FailureSeat;\n controlPendingProp: string;\n}\n\nconst FAILURE_FLAG = String.raw`[\\w$.?]*\\b(?:isError|error)\\b`;\nconst FETCHING = String.raw`[\\w$.?]*\\bisFetching\\b`;\nconst LIVE_FLAG_PAIRS: ReadonlyArray<{ name: string; re: RegExp }> = [\n { name: 'failure flag && isFetching', re: new RegExp(`${FAILURE_FLAG}\\\\s*&&\\\\s*${FETCHING}`) },\n { name: 'isFetching && failure flag', re: new RegExp(`${FETCHING}\\\\s*&&\\\\s*${FAILURE_FLAG}`) },\n];\n\nconst FETCHING_FLAG =\n /^(?:is(?:Re)?[Ff]etching|fetchingCount|useIsFetching|fetchStatus|sourceState)$/;\n\nconst fieldName = (name: ts.Node): string | null =>\n ts.isIdentifier(name) || ts.isStringLiteralLike(name) ? name.text : null;\n\nfunction retryStateExpressions(\n file: FileView,\n fields: readonly string[],\n): Array<{ index: number; expression: ts.Expression }> {\n const sf = file.sourceFile;\n const wanted = new Set(fields);\n const found: Array<{ index: number; expression: ts.Expression }> = [];\n const add = (name: ts.Node, expression: ts.Expression | undefined) => {\n if (expression && wanted.has(fieldName(name) ?? ''))\n found.push({ index: name.getStart(sf), expression });\n };\n forEachNode(sf, (node) => {\n if (ts.isPropertyAssignment(node) || ts.isVariableDeclaration(node))\n add(node.name, node.initializer);\n else if (ts.isJsxAttribute(node) && node.initializer && ts.isJsxExpression(node.initializer))\n add(node.name, node.initializer.expression);\n else if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken) {\n add(ts.isPropertyAccessExpression(node.left) ? node.left.name : node.left, node.right);\n }\n });\n return found;\n}\n\nconst FAILURE_NAME = /^(?:isError|error)$/;\n\nfunction readsFetchingFlag(expression: ts.Node, file: FileView): boolean {\n return readsFlag(expression, file, FETCHING_FLAG);\n}\n\nfunction readsFlag(\n expression: ts.Node,\n file: FileView,\n flag: RegExp,\n seen: Set<string> = new Set(),\n): boolean {\n let reads = false;\n const bound: string[] = [];\n forEachNode(expression, (node) => {\n if (!ts.isIdentifier(node) || reads) return;\n if (flag.test(node.text)) reads = true;\n const parent = node.parent;\n const receiverOrCallee =\n (ts.isPropertyAccessExpression(parent) &&\n (parent.expression === node || parent.name === node)) ||\n (ts.isCallExpression(parent) && parent.expression === node);\n if (!receiverOrCallee) bound.push(node.text);\n });\n if (reads) return true;\n return bound.some((name) => {\n if (seen.has(name)) return false;\n seen.add(name);\n let declared: ts.Expression | undefined;\n let renamed = false;\n forEachNode(file.sourceFile, (node) => {\n if (\n ts.isBindingElement(node) &&\n ts.isIdentifier(node.name) &&\n node.name.text === name &&\n node.propertyName &&\n flag.test(fieldName(node.propertyName) ?? '')\n ) {\n renamed = true;\n } else if (\n !declared &&\n ts.isVariableDeclaration(node) &&\n ts.isIdentifier(node.name) &&\n node.name.text === name &&\n node.initializer\n ) {\n declared = node.initializer;\n }\n });\n if (renamed) return true;\n if (!declared) return false;\n const value = declared;\n const fromHelper =\n ts.isCallExpression(value) &&\n ts.isIdentifier(value.expression) &&\n (RETRY_STATE_HELPERS as readonly string[]).includes(value.expression.text);\n return !fromHelper && readsFlag(value, file, flag, seen);\n });\n}\n\nfunction branchConditionsAbove(node: ts.Node): ts.Expression[] {\n const conditions: ts.Expression[] = [];\n for (let child = node, parent = node.parent; parent; child = parent, parent = parent.parent) {\n if (ts.isIfStatement(parent) && parent.thenStatement === child)\n conditions.push(parent.expression);\n else if (ts.isConditionalExpression(parent) && parent.whenTrue === child)\n conditions.push(parent.condition);\n else if (\n ts.isBinaryExpression(parent) &&\n parent.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken &&\n parent.right === child\n )\n conditions.push(parent.left);\n }\n return conditions;\n}\n\nexport function failureBranchLivePending(file: FileView, controlPendingProp: string): Hit[] {\n const sf = file.sourceFile;\n const hits: Hit[] = [];\n forEachNode(sf, (node) => {\n if (\n !ts.isJsxAttribute(node) ||\n fieldName(node.name) !== controlPendingProp ||\n !node.initializer ||\n !ts.isJsxExpression(node.initializer) ||\n !node.initializer.expression\n )\n return;\n const pending = node.initializer.expression;\n if (!readsFetchingFlag(pending, file)) return;\n if (!branchConditionsAbove(node).some((c) => readsFlag(c, file, FAILURE_NAME))) return;\n hits.push({\n index: node.getStart(sf),\n detail: `a failure's retry pending from a fetching flag: ${pending.getText(sf).replace(/\\s+/g, ' ').slice(0, 120)}`,\n });\n });\n return hits;\n}\n\nconst LOADING_FIELD = 'isLoading';\nconst READ_FAILURE_FIELDS = new Set(['error', 'isError', 'retryState']);\nconst HELD_RECEIVER = /retry/i;\n\ninterface Destructured {\n field: string;\n receiver: string;\n scope: ts.Node;\n}\n\ntype Bindings = Map<string, Destructured[]>;\n\nfunction scopeOf(node: ts.Node): ts.Node {\n return enclosingFunctionOf(node) ?? node.getSourceFile();\n}\n\nfunction destructuredBindings(sf: ts.SourceFile): Bindings {\n const bindings: Bindings = new Map();\n forEachNode(sf, (node) => {\n if (\n !ts.isVariableDeclaration(node) ||\n !ts.isObjectBindingPattern(node.name) ||\n !node.initializer ||\n !ts.isIdentifier(node.initializer)\n )\n return;\n const receiver = node.initializer.text;\n const scope = scopeOf(node);\n for (const element of node.name.elements) {\n if (!ts.isIdentifier(element.name)) continue;\n const field = element.propertyName ? fieldName(element.propertyName) : element.name.text;\n if (!field) continue;\n const named = bindings.get(element.name.text) ?? [];\n named.push({ field, receiver, scope });\n bindings.set(element.name.text, named);\n }\n });\n return bindings;\n}\n\nfunction declaresParameter(fn: ts.SignatureDeclaration, name: string): boolean {\n let declares = false;\n for (const parameter of fn.parameters)\n forEachNode(parameter.name, (node) => {\n if (ts.isIdentifier(node) && node.text === name) declares = true;\n });\n return declares;\n}\n\nfunction bindingFor(use: ts.Identifier, bindings: Bindings): Destructured | undefined {\n const named = bindings.get(use.text);\n if (!named) return undefined;\n for (let scope: ts.Node | undefined = scopeOf(use); scope;) {\n const found = named.find((binding) => binding.scope === scope);\n if (found) return found;\n if (ts.isFunctionLike(scope) && declaresParameter(scope, use.text)) return undefined;\n scope = ts.isSourceFile(scope) ? undefined : scopeOf(scope);\n }\n return undefined;\n}\n\nfunction rootIdentifier(node: ts.Expression): string | null {\n let current: ts.Expression = node;\n while (ts.isPropertyAccessExpression(current) || ts.isNonNullExpression(current))\n current = current.expression;\n return ts.isIdentifier(current) ? current.text : null;\n}\n\ninterface ReadField {\n receiver: string;\n index: number;\n}\n\nfunction readFieldsIn(\n scope: ts.Node,\n bindings: Bindings,\n wanted: (field: string) => boolean,\n): ReadField[] {\n const sf = scope.getSourceFile();\n const found: ReadField[] = [];\n forEachNode(scope, (node) => {\n if (ts.isPropertyAccessExpression(node) && wanted(node.name.text)) {\n const receiver = rootIdentifier(node.expression);\n if (receiver && !HELD_RECEIVER.test(node.expression.getText(sf)))\n found.push({ receiver, index: node.getStart(sf) });\n } else if (\n ts.isIdentifier(node) &&\n !(ts.isPropertyAccessExpression(node.parent) && node.parent.name === node)\n ) {\n const bound = bindingFor(node, bindings);\n if (bound && wanted(bound.field) && !HELD_RECEIVER.test(bound.receiver))\n found.push({ receiver: bound.receiver, index: node.getStart(sf) });\n }\n });\n return found;\n}\n\nfunction enclosingFunctionOf(node: ts.Node): ts.Node | undefined {\n for (let p = node.parent; p; p = p.parent) if (ts.isFunctionLike(p)) return p;\n return undefined;\n}\n\nfunction branchCondition(node: ts.Node): ts.Expression | undefined {\n if (ts.isIfStatement(node)) return node.expression;\n if (ts.isConditionalExpression(node)) return node.condition;\n if (\n ts.isBinaryExpression(node) &&\n node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken &&\n ts.isJsxExpression(node.parent)\n )\n return node.left;\n return undefined;\n}\n\nexport function liveLoadingBeforeFailure(file: FileView): Hit[] {\n const sf = file.sourceFile;\n const bindings = destructuredBindings(sf);\n const isLoading = (field: string) => field === LOADING_FIELD;\n const isFailure = (field: string) => READ_FAILURE_FIELDS.has(field);\n const hits: Hit[] = [];\n forEachNode(sf, (node) => {\n const condition = branchCondition(node);\n const fn = condition && enclosingFunctionOf(node);\n if (!condition || !fn) return;\n const tested = new Set(readFieldsIn(condition, bindings, isFailure).map((r) => r.receiver));\n const end = condition.getEnd();\n const later = readFieldsIn(fn, bindings, isFailure).filter((r) => r.index >= end);\n const loading = readFieldsIn(condition, bindings, isLoading).find(\n (r) => !tested.has(r.receiver) && later.some((f) => f.receiver === r.receiver),\n );\n if (loading)\n hits.push({\n index: loading.index,\n detail: `a live loading flag tested before the read's failure: ${condition.getText(sf).replace(/\\s+/g, ' ').slice(0, 120)}`,\n });\n });\n return hits;\n}\n\nexport function liveFlagRetryStates(file: FileView, seat: FailureSeat): Hit[] {\n const code = file.code;\n const hits = new Map<number, Hit>();\n let offset = 0;\n for (const line of code.split('\\n')) {\n for (const shape of LIVE_FLAG_PAIRS) {\n const m = shape.re.exec(line);\n if (m)\n hits.set(file.lineOf(offset + m.index), {\n index: offset + m.index,\n detail: `${shape.name}: ${line.trim().slice(0, 120)}`,\n });\n }\n offset += line.length + 1;\n }\n for (const { index, expression } of retryStateExpressions(file, [\n RETRY_STATE_FIELD,\n HELD_ANSWER_FIELD,\n seat.pendingProp,\n ])) {\n if (!readsFetchingFlag(expression, file)) continue;\n const line = file.lineOf(index);\n if (!hits.has(line))\n hits.set(line, {\n index,\n detail: `retry state from a fetching flag: ${expression.getText(file.sourceFile).replace(/\\s+/g, ' ').slice(0, 120)}`,\n });\n }\n return [...hits.values()].sort((a, b) => a.index - b.index);\n}\n\nconst isHookFunction = (node: ts.Node, sf: ts.SourceFile): boolean => {\n if ((ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node)) && node.name)\n return isHookName(node.name.text);\n if (\n (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) &&\n ts.isVariableDeclaration(node.parent)\n )\n return isHookName(node.parent.name.getText(sf));\n return false;\n};\n\nexport function failedAnswersWithoutRetrying(file: FileView): Hit[] {\n const sf = file.sourceFile;\n const hits: Hit[] = [];\n forEachNode(sf, (node) => {\n if (!ts.isObjectLiteralExpression(node)) return;\n const named = (name: string) =>\n node.properties.find(\n (p) =>\n (ts.isPropertyAssignment(p) || ts.isShorthandPropertyAssignment(p)) &&\n p.name.getText(sf) === name,\n );\n const status = named('status');\n if (\n !status ||\n !ts.isPropertyAssignment(status) ||\n !ts.isStringLiteralLike(status.initializer) ||\n status.initializer.text !== 'failed'\n )\n return;\n if (!named('error') || named(HELD_ANSWER_FIELD) || node.properties.some(ts.isSpreadAssignment))\n return;\n let inHook = false;\n for (let p: ts.Node | undefined = node.parent; p && !inHook; p = p.parent)\n inHook = isHookFunction(p, sf);\n if (inHook)\n hits.push({\n index: node.getStart(sf),\n detail: `a failed answer with no ${HELD_ANSWER_FIELD}: ${node.getText(sf).replace(/\\s+/g, ' ').slice(0, 120)}`,\n });\n });\n return hits;\n}\n\nexport function seatRetriesWithoutPending(file: FileView, seat: FailureSeat): Hit[] {\n const hits: Hit[] = [];\n const element = new RegExp(`<${escapeRegExp(seat.component)}\\\\b[\\\\s\\\\S]*?\\\\/>`, 'g');\n for (const match of file.code.matchAll(element)) {\n const text = match[0];\n if (\n new RegExp(`\\\\b${escapeRegExp(seat.retryProp)}=`).test(text) &&\n !new RegExp(`\\\\b${escapeRegExp(seat.pendingProp)}=`).test(text) &&\n !/\\{\\s*\\.\\.\\./.test(text)\n ) {\n hits.push({\n index: match.index ?? 0,\n detail: `<${seat.component} ${seat.retryProp}=…> without ${seat.pendingProp}`,\n });\n }\n }\n return hits;\n}\n\nexport const readRetryStateGuard: GenericGuardDefinition<ReadRetryStateFacts> = {\n id: 'readRetryState',\n absentWhen: false,\n factProblems(facts) {\n const problems = seatProblems(facts?.seat);\n identifierProblem(facts?.controlPendingProp, 'controlPendingProp', problems);\n return problems;\n },\n build: (facts) => [\n {\n title: \"a read's retry state comes from its one owner, never the live fetching flags\",\n description:\n 'TanStack Query puts a query that never succeeded back to pending and clears its error the moment a refetch starts, so a retry ' +\n 'state built from isFetching / isRefetching / fetchStatus with isError or error reads false for the retry of a failed first read, ' +\n `and the failure turns into a loading state under the pressed retry. Hold the failure with query-core's ${RETRY_STATE_HELPERS.join(' / ')} ` +\n `(exposed from the read's hook) and pass its ${RETRY_STATE_FIELD}; a lookup hands out its held ${HELD_ANSWER_FIELD}, and a hook ` +\n `that answers with a status gives its failed answer the held ${HELD_ANSWER_FIELD} beside the error, never one built from a ` +\n `fetching flag; and every <${facts.seat.component}> given ${facts.seat.retryProp} also takes ${facts.seat.pendingProp}, so the ` +\n `pressed retry shows it is running. The same live flags decide no failure surface: a control's ${facts.controlPendingProp} ` +\n \"inside a failure branch reads the held isRetrying, never a fetching flag, and a branch never tests a read's live isLoading \" +\n \"ahead of that read's failure — the held retryState decides the failure first, then its isLoading.\",\n run(context: GuardContext): Finding[] {\n const findings: Finding[] = [];\n for (const file of context.files(APP_CODE)) {\n const hits = [\n ...liveFlagRetryStates(file, facts.seat),\n ...seatRetriesWithoutPending(file, facts.seat),\n ...failedAnswersWithoutRetrying(file),\n ...failureBranchLivePending(file, facts.controlPendingProp),\n ...liveLoadingBeforeFailure(file),\n ];\n for (const hit of hits) {\n findings.push({\n file: file.path,\n line: file.lineOf(hit.index),\n detail: hit.detail ?? '',\n });\n }\n }\n return findings;\n },\n },\n ],\n};\n\nexport interface HookReadDefaultFacts {\n hooksTree: string;\n readCollapsers: readonly string[];\n}\n\nconst FAILURE_FIELDS = new Set(['error', 'isError', 'status']);\n\nfunction isEmptyAnswer(node: ts.Expression): boolean {\n return (\n (ts.isArrayLiteralExpression(node) && node.elements.length === 0) ||\n (ts.isObjectLiteralExpression(node) && node.properties.length === 0) ||\n node.kind === ts.SyntaxKind.FalseKeyword ||\n node.kind === ts.SyntaxKind.NullKeyword ||\n (ts.isNumericLiteral(node) && node.text === '0') ||\n (ts.isStringLiteral(node) && node.text === '')\n );\n}\n\nfunction enclosingFunction(node: ts.Node): ts.Node | undefined {\n let current: ts.Node | undefined = node.parent;\n while (current && !ts.isFunctionLike(current)) current = current.parent;\n return current;\n}\n\nfunction readsFailureOf(scope: ts.Node, receiver: string, sf: ts.SourceFile): boolean {\n let found = false;\n forEachNode(scope, (n) => {\n if (\n ts.isPropertyAccessExpression(n) &&\n FAILURE_FIELDS.has(n.name.text) &&\n n.expression.getText(sf) === receiver\n )\n found = true;\n if (\n ts.isCallExpression(n) &&\n n.expression.getText(sf) === RETRY_STATE_HELPERS[0] &&\n n.arguments[0]?.getText(sf) === receiver\n )\n found = true;\n });\n return found;\n}\n\nfunction exportedHookBody(\n node: ts.Node,\n sf: ts.SourceFile,\n): { name: string; body: ts.ConciseBody } | undefined {\n const isExported = (n: ts.Node) =>\n ts.canHaveModifiers(n) &&\n (ts.getModifiers(n) ?? []).some((m) => m.kind === ts.SyntaxKind.ExportKeyword);\n if (\n ts.isFunctionDeclaration(node) &&\n node.name &&\n isHookName(node.name.text) &&\n isExported(node) &&\n node.body\n ) {\n return { name: node.name.text, body: node.body };\n }\n if (\n ts.isVariableDeclaration(node) &&\n ts.isIdentifier(node.name) &&\n isHookName(node.name.text) &&\n node.initializer &&\n (ts.isArrowFunction(node.initializer) || ts.isFunctionExpression(node.initializer)) &&\n isExported(node.parent.parent)\n ) {\n return { name: node.name.getText(sf), body: node.initializer.body };\n }\n return undefined;\n}\n\nfunction returnedExpressions(body: ts.ConciseBody): ts.Expression[] {\n if (!ts.isBlock(body)) return [body];\n const out: ts.Expression[] = [];\n const visit = (n: ts.Node) => {\n if (ts.isFunctionLike(n)) return;\n if (ts.isReturnStatement(n) && n.expression) out.push(n.expression);\n ts.forEachChild(n, visit);\n };\n ts.forEachChild(body, visit);\n return out;\n}\n\nfunction readsData(node: ts.Node): boolean {\n let found = false;\n forEachNode(node, (n) => {\n if (ts.isPropertyAccessExpression(n) && n.name.text === 'data') found = true;\n });\n return found;\n}\n\nconst COMPARISONS = new Set([\n ts.SyntaxKind.EqualsEqualsEqualsToken,\n ts.SyntaxKind.ExclamationEqualsEqualsToken,\n ts.SyntaxKind.GreaterThanToken,\n ts.SyntaxKind.LessThanToken,\n ts.SyntaxKind.GreaterThanEqualsToken,\n ts.SyntaxKind.LessThanEqualsToken,\n]);\n\nfunction collapsesReadToBoolean(\n expr: ts.Expression,\n sf: ts.SourceFile,\n collapsers: ReadonlySet<string>,\n): boolean {\n let e = expr;\n while (ts.isParenthesizedExpression(e)) e = e.expression;\n if (ts.isCallExpression(e) && collapsers.has(e.expression.getText(sf))) return true;\n if (ts.isPrefixUnaryExpression(e) && e.operator === ts.SyntaxKind.ExclamationToken)\n return readsData(e);\n if (ts.isBinaryExpression(e) && COMPARISONS.has(e.operatorToken.kind)) return readsData(e);\n if (ts.isCallExpression(e) && e.expression.getText(sf) === 'Boolean') return readsData(e);\n return false;\n}\n\nexport function hookReadDefaults(\n file: FileView,\n collapsers: readonly string[],\n): Array<{ line: number; detail: string }> {\n const sf = file.sourceFile;\n const names = new Set(collapsers);\n const hits: Array<{ line: number; detail: string }> = [];\n forEachNode(sf, (node) => {\n if (\n ts.isBinaryExpression(node) &&\n (node.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken ||\n node.operatorToken.kind === ts.SyntaxKind.BarBarToken) &&\n ts.isPropertyAccessExpression(node.left) &&\n node.left.name.text === 'data' &&\n isEmptyAnswer(node.right)\n ) {\n const scope = enclosingFunction(node);\n if (!scope || !readsFailureOf(scope, node.left.expression.getText(sf), sf)) {\n hits.push({\n line: lineOfNode(file, node),\n detail: `a defaulted read with no failure beside it: ${node.getText(sf)}`,\n });\n }\n }\n if (\n ts.isVariableDeclaration(node) &&\n node.initializer &&\n ts.isObjectBindingPattern(node.name)\n ) {\n const init = node.initializer;\n if (ts.isCallExpression(init) && isHookName(init.expression.getText(sf))) {\n const keyOf = (el: ts.BindingElement) => (el.propertyName ?? el.name).getText(sf);\n const elements = node.name.elements;\n const defaultsData = elements.some(\n (el) => keyOf(el) === 'data' && el.initializer !== undefined,\n );\n const carriesFailure = elements.some(\n (el) => el.dotDotDotToken || FAILURE_FIELDS.has(keyOf(el)),\n );\n if (defaultsData && !carriesFailure)\n hits.push({\n line: lineOfNode(file, node),\n detail: `a defaulted read with no failure beside it: ${node.name.getText(sf)}`,\n });\n }\n }\n const hook = exportedHookBody(node, sf);\n if (hook) {\n for (const returned of returnedExpressions(hook.body)) {\n if (collapsesReadToBoolean(returned, sf, names))\n hits.push({\n line: lineOfNode(file, returned),\n detail: `${hook.name} returns a boolean from a read`,\n });\n }\n }\n });\n return hits;\n}\n\nexport const hookReadDefaultGuard: GenericGuardDefinition<HookReadDefaultFacts> = {\n id: 'hookReadDefault',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n pathProblem(facts?.hooksTree, 'hooksTree', problems);\n identifierListProblem(facts?.readCollapsers, 'readCollapsers', problems, { nonEmpty: false });\n return problems;\n },\n build: (facts) => [\n {\n title: 'a hook never returns a default its consumers cannot tell from data',\n description:\n `In ${facts.hooksTree}, a read's data defaulted to an empty answer (q.data ?? [], const { data = [] } = useQ()) is allowed only ` +\n `where the same function also carries that read's failure (error / isError / status, or the read handed to ${RETRY_STATE_HELPERS[0]}), ` +\n 'and no exported hook collapses a read into a bare boolean, where an unknown read would read as \"no\". Return the read state ' +\n '(pending / failed / answered) or carry the failure beside the defaulted data.',\n run(context) {\n const { files, findings } = filesUnder(context, [facts.hooksTree]);\n for (const file of files)\n for (const hit of hookReadDefaults(file, facts.readCollapsers))\n findings.push({ file: file.path, ...hit });\n return findings;\n },\n },\n ],\n};\n\nexport interface DefaultedReadBindingFacts {\n surfaceTrees: readonly string[];\n heldFailureFields: readonly string[];\n allowlist: ReadonlyArray<Reviewed & { gate: ReadGate }>;\n}\n\nexport interface ReadGate {\n file: string;\n code: string;\n}\n\nconst squashed = (text: string) => text.replace(/\\s+/g, ' ').trim();\n\nfunction gateProblems(allowlist: unknown): string[] {\n if (!isList(allowlist)) return [];\n const problems: string[] = [];\n for (const entry of allowlist as Array<{ path?: string; gate?: Partial<ReadGate> }>) {\n const what = `allowlist entry ${String(entry?.path)}`;\n if (!entry?.gate || typeof entry.gate !== 'object')\n problems.push(\n `${what} names no gate (the file and the code that hold its surface back until the read answered)`,\n );\n else {\n pathProblem(entry.gate.file, `${what}'s gate file`, problems);\n if (typeof entry.gate.code !== 'string' || !entry.gate.code.trim())\n problems.push(`${what}'s gate names no code`);\n }\n }\n return problems;\n}\n\nfunction missingGates(\n context: GuardContext,\n allowlist: DefaultedReadBindingFacts['allowlist'],\n): Finding[] {\n const findings: Finding[] = [];\n for (const { path, gate } of allowlist) {\n if (!context.reader.exists(gate.file))\n findings.push({\n file: gate.file,\n detail: `the gate ${path} relies on is gone: the file no longer exists`,\n });\n else if (!squashed(context.file(gate.file).code).includes(squashed(gate.code))) {\n findings.push({\n file: gate.file,\n detail: `the gate ${path} relies on is gone: no longer holds ${squashed(gate.code)}`,\n });\n }\n }\n return findings;\n}\n\nexport function unguardedDataDefaults(file: FileView, heldFailureFields: readonly string[]): Hit[] {\n const sf = file.sourceFile;\n const failureBindings = new Set([...FAILURE_FIELDS, ...heldFailureFields]);\n const hits: Hit[] = [];\n forEachNode(sf, (node) => {\n if (\n !ts.isVariableDeclaration(node) ||\n !node.initializer ||\n !ts.isObjectBindingPattern(node.name)\n )\n return;\n let init: ts.Expression = node.initializer;\n if (ts.isAwaitExpression(init)) init = init.expression;\n if (!ts.isCallExpression(init)) return;\n const callee = init.expression.getText(sf);\n if (!isHookName(callee)) return;\n const elements = node.name.elements;\n if (elements.some((el) => el.dotDotDotToken)) return;\n const keyOf = (el: ts.BindingElement) => (el.propertyName ?? el.name).getText(sf);\n if (!elements.some((el) => keyOf(el) === 'data' && el.initializer !== undefined)) return;\n if (elements.some((el) => failureBindings.has(keyOf(el)))) return;\n hits.push({\n index: node.getStart(sf),\n detail: `${callee}() defaults data with no failure bound`,\n });\n });\n return hits;\n}\n\nexport const defaultedReadBindingGuard: GenericGuardDefinition<DefaultedReadBindingFacts> = {\n id: 'defaultedReadBinding',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n pathListProblem(facts?.surfaceTrees, 'surfaceTrees', problems);\n identifierListProblem(facts?.heldFailureFields, 'heldFailureFields', problems, {\n nonEmpty: false,\n });\n reviewedProblems(facts?.allowlist, 'allowlist', problems);\n return [...problems, ...gateProblems(facts?.allowlist)];\n },\n build: (facts) => {\n const held = facts.heldFailureFields.length ? ` / ${facts.heldFailureFields.join(' / ')}` : '';\n const guard = reviewedAllowlist({\n title: 'a render surface that defaults a read binds its failure',\n description:\n `A render surface (${facts.surfaceTrees.join(', ')}) that defaults a read's data (const { data: rows = [] } = useRows()) binds ` +\n `that same read's failure (error / isError / status${held}) in the same destructure, and renders the pending and failed states ` +\n 'before the default is used; otherwise a failed read renders as an empty list, a zero, or a negative answer that decides a control. ' +\n 'A reviewed default names the gate that holds its surface back until the read answered, and that gate must still be there.',\n scope: APP_CODE,\n match: (file) =>\n facts.surfaceTrees.some((tree) => isUnder(file.path, tree))\n ? unguardedDataDefaults(file, facts.heldFailureFields)\n : [],\n allowlist: facts.allowlist,\n samples: {\n flags: [\n {\n path: `${facts.surfaceTrees[0]}/sample.tsx`,\n text: 'const { data: rows = [] } = useRows(id);',\n },\n ],\n passes: [\n {\n path: `${facts.surfaceTrees[0]}/sample.tsx`,\n text: 'const { data: rows = [], isError } = useRows(id);',\n },\n ],\n },\n });\n return [\n {\n ...guard,\n run: async (context) => [\n ...(await guard.run(context)),\n ...missingGates(context, facts.allowlist),\n ],\n },\n ];\n },\n};\n\nexport interface LaterPageFailureFacts {\n hooksTree: string;\n readStateModule: string;\n listRoutes: ReadonlyArray<{ component: string; prop?: string }>;\n handOffProp: string;\n}\n\nconst LOADS_MORE = /\\bfetchNextPage\\b/;\n\nfunction routedPattern(routes: LaterPageFailureFacts['listRoutes']): RegExp {\n return new RegExp(\n routes\n .map(({ component, prop }) =>\n prop\n ? `<${escapeRegExp(component)}\\\\s[^>]*?\\\\b${escapeRegExp(prop)}=`\n : `<${escapeRegExp(component)}\\\\b`,\n )\n .join('|'),\n );\n}\n\nexport function unroutedPagingSurfaces(\n files: readonly FileView[],\n facts: LaterPageFailureFacts,\n): FileView[] {\n const routed = routedPattern(facts.listRoutes);\n const routing = new Set(\n files\n .filter((f) => routed.test(f.code))\n .flatMap((f) => [...f.code.matchAll(/export function ([A-Z]\\w*)/g)].map((m) => m[1])),\n );\n const handOff = new RegExp(`<([A-Z]\\\\w*)\\\\s[^>]*?\\\\b${escapeRegExp(facts.handOffProp)}=\\\\{`, 'g');\n return files.filter((f) => {\n if (routed.test(f.code)) return false;\n const handedTo = [...f.code.matchAll(handOff)].map((m) => m[1]);\n if (!LOADS_MORE.test(f.code) && !handedTo.length) return false;\n return !handedTo.some((component) => routing.has(component));\n });\n}\n\nexport const laterPageFailureGuard: GenericGuardDefinition<LaterPageFailureFacts> = {\n id: 'laterPageFailure',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n pathProblem(facts?.hooksTree, 'hooksTree', problems);\n pathProblem(facts?.readStateModule, 'readStateModule', problems);\n identifierProblem(facts?.handOffProp, 'handOffProp', problems);\n if (!isList(facts?.listRoutes) || !facts.listRoutes.length)\n problems.push('listRoutes names no component');\n else\n facts.listRoutes.forEach((r, i) => {\n identifierProblem(r?.component, `listRoutes[${i}].component`, problems);\n if (r?.prop !== undefined) identifierProblem(r.prop, `listRoutes[${i}].prop`, problems);\n });\n return problems;\n },\n build: (facts) => [\n {\n title: \"an infinite list's later-page failure routes through the read-state module\",\n description:\n `Every surface that loads more of an infinite list (fetchNextPage) or hands a list on (${facts.handOffProp}=…) renders it through ` +\n `${facts.listRoutes.map((r) => `<${r.component}${r.prop ? ` ${r.prop}=…` : ''}>`).join(' or ')} from ${facts.readStateModule}, ` +\n 'or hands it to a component whose own file does, so a failed load-more retries that page instead of ' +\n 'refetching the whole list. A page-by-page list, and a count that only reads hasNextPage, load nothing more and are not counted.',\n run(context) {\n const { findings, file: module } = requiredFile(\n context,\n facts.readStateModule,\n 'the read-state module',\n );\n if (!module) return findings;\n const surfaces = context\n .files(APP_CODE)\n .filter((f) => !isUnder(f.path, facts.hooksTree) && f.path !== facts.readStateModule);\n for (const file of unroutedPagingSurfaces(surfaces, facts)) {\n findings.push({\n file: file.path,\n detail:\n 'pages an infinite list without routing its later-page failure through the read-state module',\n });\n }\n return findings;\n },\n },\n ],\n};\n\nexport interface ReadFailureCopyFacts {\n owner: string;\n allowlist: readonly Reviewed[];\n}\n\nexport const READ_FAILURE_SENTENCE =\n /(?:could not|couldn['’]?t|failed to|unable to)\\s+(?:load|search|fetch|read|retrieve|check|find)\\b|error\\s+(?:loading|searching|fetching|reading)\\b/i;\n\nexport const readFailureCopyGuard: GenericGuardDefinition<ReadFailureCopyFacts> = {\n id: 'readFailureCopy',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n pathProblem(facts?.owner, 'owner', problems);\n reviewedProblems(facts?.allowlist, 'allowlist', problems);\n if (isList(facts?.allowlist) && facts.allowlist.some((e) => e?.path === facts.owner))\n problems.push('the owner is listed in the allowlist');\n return problems;\n },\n build: (facts) => [\n reviewedAllowlist({\n title: \"a read failure's copy comes from its one owner\",\n description:\n `Every read-failure sentence a person sees is built by ${facts.owner} from the short noun the surface names; no other file ` +\n 'hand-writes one (\"could not load\", \"failed to load\", \"error loading\", or the same around another read verb, in any casing). ' +\n 'Render the owner (with surface-specific guidance as its hint), or — for text never shown to a person — add a reviewed entry with its why.',\n scope: APP_CODE,\n match: matchPattern(READ_FAILURE_SENTENCE),\n allowlist: [\n { path: facts.owner, why: 'the one owner of read-failure copy' },\n ...facts.allowlist,\n ],\n samples: {\n flags: [\n '<p>Could not load the rows.</p>',\n '<AlertTitle>Error Loading Rows</AlertTitle>',\n 'const m = \"Couldn\\'t fetch the list.\";',\n ],\n passes: [\n 'hint=\"a list that could not be read is not an empty list.\"',\n '<LoadingState label=\"Loading rows\" />',\n ],\n },\n }),\n ],\n};\n\nexport const READ_FAILURE_GUARDS = [\n readStateOwnerGuard,\n readRetryStateGuard,\n hookReadDefaultGuard,\n defaultedReadBindingGuard,\n laterPageFailureGuard,\n readFailureCopyGuard,\n] as const;\n"]}
@@ -2,6 +2,7 @@ import type { GenericGuardDefinition } from '../../node/suite/config.js';
2
2
  import type { FileView } from '../../reader/view.js';
3
3
  import { type AllowlistEntry, type Hit } from '../../shapes/shapes.js';
4
4
  export interface SharedTruncationFacts {
5
+ entryStylesheet: string;
5
6
  trees: readonly string[];
6
7
  sharedClass: string;
7
8
  clampOwners: ReadonlyArray<{
@@ -1 +1 @@
1
- {"version":3,"file":"truncation.d.ts","sourceRoot":"","sources":["../../../src/modules/ui/truncation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAGzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAqB,KAAK,cAAc,EAAE,KAAK,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAoB1F,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9D,UAAU,EAAE,SAAS,cAAc,EAAE,CAAC;CACvC;AAID,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,KAAG,OACS,CAAC;AAsB5D,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,GAAG,eAAe,EAAE,CA4BlE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,GAAG,GAAG,EAAE,CAcrD;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,IAAI,CAAC,qBAAqB,EAAE,OAAO,GAAG,aAAa,CAAC,GAC1D,GAAG,EAAE,CAQP;AAED,eAAO,MAAM,qBAAqB,EAAE,sBAAsB,CAAC,qBAAqB,CA+F/E,CAAC"}
1
+ {"version":3,"file":"truncation.d.ts","sourceRoot":"","sources":["../../../src/modules/ui/truncation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAGzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAqB,KAAK,cAAc,EAAE,KAAK,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAqB1F,MAAM,WAAW,qBAAqB;IACpC,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9D,UAAU,EAAE,SAAS,cAAc,EAAE,CAAC;CACvC;AAID,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,KAAG,OACS,CAAC;AAsB5D,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,GAAG,eAAe,EAAE,CA4BlE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,GAAG,GAAG,EAAE,CAcrD;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,IAAI,CAAC,qBAAqB,EAAE,OAAO,GAAG,aAAa,CAAC,GAC1D,GAAG,EAAE,CAQP;AAED,eAAO,MAAM,qBAAqB,EAAE,sBAAsB,CAAC,qBAAqB,CAoG/E,CAAC"}
@@ -4,6 +4,7 @@ import { forEachNode } from '../../support/ast.js';
4
4
  import { allowlistProblems, isText, pathProblem, reviewedProblems, textProblem, isList, } from '../../support/facts.js';
5
5
  import { isUnder } from '../../support/text.js';
6
6
  import { cssBlocks, selectorsOf, splitTopLevel } from './css.js';
7
+ import { loadedStylesheets } from './stylesheets.js';
7
8
  import { bareToken, codeStrings, tokensOf } from './source.js';
8
9
  const APP_CODE_AND_STYLES = { roots: ['app'], kinds: ['code', 'stylesheet'], tests: false };
9
10
  const TRUNCATION_TOKEN = /^(?:truncate|text-ellipsis|line-clamp-(?:\d+|none|\[[^\]]+\]))$/;
@@ -93,6 +94,7 @@ export const sharedTruncationGuard = {
93
94
  absentWhen: false,
94
95
  factProblems(facts) {
95
96
  const problems = [];
97
+ pathProblem(facts?.entryStylesheet, 'entryStylesheet', problems);
96
98
  if (!isList(facts?.trees) || !facts.trees.length)
97
99
  problems.push('trees is missing');
98
100
  else
@@ -122,7 +124,9 @@ export const sharedTruncationGuard = {
122
124
  '`WebkitLineClamp`, or `lineClamp` style. A stylesheet sets `text-overflow: ellipsis`, `-webkit-line-clamp`, or ' +
123
125
  '`line-clamp` (or applies one of ' +
124
126
  `those utilities) only in a rule whose every selector is a clamp owner (${facts.clampOwners.map((o) => o.selector).join(', ')}). ` +
125
- 'Use the shared class, or add a clamp owner or a reviewed exception with its why.',
127
+ `A clamp owner is declared by a stylesheet ${facts.entryStylesheet} loads — the theme package's or the app's — ` +
128
+ 'and one no loaded stylesheet declares as a clamp any more is stale. Use the shared class, or add a clamp owner ' +
129
+ 'or a reviewed exception with its why.',
126
130
  scope: APP_CODE_AND_STYLES,
127
131
  match: (file) => truncationHits(file, facts),
128
132
  allowlist: facts.exceptions,
@@ -166,8 +170,10 @@ export const sharedTruncationGuard = {
166
170
  file: t,
167
171
  detail: 'the tree holds no production code or stylesheet the guard can read',
168
172
  });
173
+ const loaded = loadedStylesheets(context, facts.entryStylesheet);
174
+ findings.push(...loaded.findings);
169
175
  const held = new Set();
170
- for (const file of files)
176
+ for (const file of [...loaded.sheets.map((sheet) => sheet.file), ...files])
171
177
  if (file.kind === 'stylesheet')
172
178
  for (const clamp of stylesheetClamps(file))
173
179
  for (const s of clamp.selectors)
@@ -1 +1 @@
1
- {"version":3,"file":"truncation.js","sourceRoot":"","sources":["../../../src/modules/ui/truncation.ts"],"names":[],"mappings":"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","sourcesContent":["import ts from 'typescript';\nimport type { GenericGuardDefinition } from '../../node/suite/config.js';\nimport type { Finding } from '../../guard.js';\nimport type { Scope } from '../../node/reader.js';\nimport type { FileView } from '../../reader/view.js';\nimport { reviewedAllowlist, type AllowlistEntry, type Hit } from '../../shapes/shapes.js';\nimport { forEachNode } from '../../support/ast.js';\nimport {\n allowlistProblems,\n isText,\n pathProblem,\n reviewedProblems,\n textProblem,\n isList,\n} from '../../support/facts.js';\nimport { isUnder } from '../../support/text.js';\nimport { cssBlocks, selectorsOf, splitTopLevel } from './css.js';\nimport { bareToken, codeStrings, tokensOf } from './source.js';\n\nconst APP_CODE_AND_STYLES: Scope = { roots: ['app'], kinds: ['code', 'stylesheet'], tests: false };\n\nconst TRUNCATION_TOKEN = /^(?:truncate|text-ellipsis|line-clamp-(?:\\d+|none|\\[[^\\]]+\\]))$/;\nconst INLINE_STYLE_KEYS = new Set(['textOverflow', 'WebkitLineClamp', 'lineClamp']);\nconst APPLY = /@apply\\s+([^;{}]+)/g;\n\nexport interface SharedTruncationFacts {\n trees: readonly string[];\n sharedClass: string;\n clampOwners: ReadonlyArray<{ selector: string; why: string }>;\n exceptions: readonly AllowlistEntry[];\n}\n\nconst squash = (text: string) => text.replace(/\\s+/g, ' ').trim();\n\nexport const isTruncationToken = (token: string): boolean =>\n TRUNCATION_TOKEN.test(bareToken(token).replace(/^!/, ''));\n\nfunction enclosingSelectors(code: string, at: number): string[] {\n let depth = 0;\n let open = -1;\n for (let i = at - 1; i >= 0; i -= 1) {\n if (code[i] === '}') depth += 1;\n else if (code[i] === '{') {\n if (depth === 0) {\n open = i;\n break;\n }\n depth -= 1;\n }\n }\n if (open === -1) return [];\n let start = open - 1;\n while (start >= 0 && !'{};'.includes(code[start])) start -= 1;\n const prelude = squash(code.slice(start + 1, open));\n return prelude.startsWith('@') ? [] : splitTopLevel(prelude, ',').map(squash);\n}\n\ninterface StylesheetClamp {\n index: number;\n selectors: string[];\n detail: string;\n}\n\nexport function stylesheetClamps(file: FileView): StylesheetClamp[] {\n const out: StylesheetClamp[] = [];\n for (const block of cssBlocks(file.code)) {\n if (block.atRule) continue;\n for (const d of block.declarations) {\n const clamps =\n (d.property === 'text-overflow' && /\\bellipsis\\b/.test(d.value)) ||\n d.property === '-webkit-line-clamp' ||\n d.property === 'line-clamp';\n if (clamps)\n out.push({\n index: d.index,\n selectors: selectorsOf(block).map(squash),\n detail: `${d.property}: ${d.value}`,\n });\n }\n }\n const re = new RegExp(APPLY.source, APPLY.flags);\n for (let m = re.exec(file.code); m; m = re.exec(file.code)) {\n const tokens = tokensOf(m[1]).filter(isTruncationToken);\n if (tokens.length)\n out.push({\n index: m.index,\n selectors: enclosingSelectors(file.code, m.index),\n detail: `@apply ${tokens.join(' ')}`,\n });\n }\n return out.sort((a, b) => a.index - b.index);\n}\n\nexport function codeTruncations(file: FileView): Hit[] {\n const hits: Hit[] = [];\n for (const { text, index } of codeStrings(file))\n for (const token of tokensOf(text))\n if (isTruncationToken(token)) hits.push({ index, detail: token });\n forEachNode(file.sourceFile, (node) => {\n if (\n (ts.isPropertyAssignment(node) || ts.isShorthandPropertyAssignment(node)) &&\n (ts.isIdentifier(node.name) || ts.isStringLiteral(node.name)) &&\n INLINE_STYLE_KEYS.has(node.name.text)\n )\n hits.push({ index: node.getStart(file.sourceFile), detail: `inline ${node.name.text}` });\n });\n return hits.sort((a, b) => a.index - b.index);\n}\n\nexport function truncationHits(\n file: FileView,\n facts: Pick<SharedTruncationFacts, 'trees' | 'clampOwners'>,\n): Hit[] {\n if (!facts.trees.some((tree) => isUnder(file.path, tree))) return [];\n if (file.kind === 'code') return codeTruncations(file);\n if (file.kind !== 'stylesheet') return [];\n const owners = new Set(facts.clampOwners.map((o) => squash(o.selector)));\n return stylesheetClamps(file)\n .filter((c) => !c.selectors.length || !c.selectors.every((s) => owners.has(s)))\n .map((c) => ({ index: c.index, detail: c.detail }));\n}\n\nexport const sharedTruncationGuard: GenericGuardDefinition<SharedTruncationFacts> = {\n id: 'sharedTruncation',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n if (!isList(facts?.trees) || !facts.trees.length) problems.push('trees is missing');\n else facts.trees.forEach((t, i) => pathProblem(t, `trees[${i}]`, problems));\n textProblem(facts?.sharedClass, 'sharedClass', problems);\n if (isText(facts?.sharedClass) && isTruncationToken(facts.sharedClass))\n problems.push(`sharedClass ${facts.sharedClass} is itself a per-call-site utility`);\n reviewedProblems(facts?.clampOwners, 'clampOwners', problems, {\n key: 'selector',\n nonEmpty: true,\n });\n if (\n isList(facts?.clampOwners) &&\n isText(facts?.sharedClass) &&\n !facts.clampOwners.some((o) => squash(String(o?.selector)) === `.${facts.sharedClass}`)\n )\n problems.push(`clampOwners does not hold the shared class's selector .${facts.sharedClass}`);\n allowlistProblems(facts?.exceptions, 'exceptions', problems);\n return problems;\n },\n build(facts) {\n const tree = facts.trees[0];\n const owner = facts.clampOwners[0].selector;\n const guard = reviewedAllowlist({\n title: 'titles and names truncate through the one shared class',\n description:\n `Under ${facts.trees.join(', ')}, text truncates only through the shared class \\`${facts.sharedClass}\\`. Code ` +\n 'never names a per-call-site truncation utility (`truncate`, `line-clamp-<n|none|[…]>`, `text-ellipsis`, with ' +\n 'or without a variant prefix) in a string, template, or className, and never sets an inline `textOverflow`, ' +\n '`WebkitLineClamp`, or `lineClamp` style. A stylesheet sets `text-overflow: ellipsis`, `-webkit-line-clamp`, or ' +\n '`line-clamp` (or applies one of ' +\n `those utilities) only in a rule whose every selector is a clamp owner (${facts.clampOwners.map((o) => o.selector).join(', ')}). ` +\n 'Use the shared class, or add a clamp owner or a reviewed exception with its why.',\n scope: APP_CODE_AND_STYLES,\n match: (file) => truncationHits(file, facts),\n allowlist: facts.exceptions,\n samples: {\n flags: [\n { path: `${tree}/sample.tsx`, text: '<h2 className=\"font-bold truncate\">{title}</h2>' },\n { path: `${tree}/sample.tsx`, text: 'const c = cn(`md:line-clamp-2 ${x}`);' },\n {\n path: `${tree}/sample.tsx`,\n text: \"<p className={open ? 'line-clamp-none' : 'text-ellipsis'} />\",\n },\n { path: `${tree}/sample.tsx`, text: \"<p style={{ textOverflow: 'ellipsis' }} />\" },\n { path: `${tree}/sample.css`, text: '.card-title { text-overflow: ellipsis; }' },\n { path: `${tree}/sample.css`, text: '.card-title { @apply line-clamp-3; }' },\n ],\n passes: [\n {\n path: `${tree}/sample.tsx`,\n text: `<h2 className=\"font-bold ${facts.sharedClass}\">{title}</h2>`,\n },\n {\n path: `${tree}/sample.tsx`,\n text: '// a truncate class would go here\\nconst mode = \"truncated\";',\n },\n { path: `${tree}/sample.css`, text: `${owner} { text-overflow: ellipsis; }` },\n { path: `${tree}/sample.css`, text: '.card { text-overflow: clip; }' },\n ],\n },\n });\n return [\n {\n ...guard,\n async run(context) {\n const findings: Finding[] = [...(await guard.run(context))];\n const files = context\n .files(APP_CODE_AND_STYLES)\n .filter((f) => facts.trees.some((t) => isUnder(f.path, t)));\n for (const t of facts.trees)\n if (!files.some((f) => isUnder(f.path, t)))\n findings.push({\n file: t,\n detail: 'the tree holds no production code or stylesheet the guard can read',\n });\n const held = new Set<string>();\n for (const file of files)\n if (file.kind === 'stylesheet')\n for (const clamp of stylesheetClamps(file))\n for (const s of clamp.selectors) held.add(s);\n for (const { selector } of facts.clampOwners)\n if (!held.has(squash(selector)))\n findings.push({\n file: '(clampOwners)',\n detail: `stale clamp owner: no stylesheet rule for ${selector} truncates any more`,\n });\n return findings;\n },\n },\n ];\n },\n};\n"]}
1
+ {"version":3,"file":"truncation.js","sourceRoot":"","sources":["../../../src/modules/ui/truncation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAK5B,OAAO,EAAE,iBAAiB,EAAiC,MAAM,wBAAwB,CAAC;AAC1F,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EACL,iBAAiB,EACjB,MAAM,EACN,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,MAAM,GACP,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE/D,MAAM,mBAAmB,GAAU,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAEnG,MAAM,gBAAgB,GAAG,iEAAiE,CAAC;AAC3F,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,cAAc,EAAE,iBAAiB,EAAE,WAAW,CAAC,CAAC,CAAC;AACpF,MAAM,KAAK,GAAG,qBAAqB,CAAC;AAUpC,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AAElE,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAa,EAAW,EAAE,CAC1D,gBAAgB,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;AAE5D,SAAS,kBAAkB,CAAC,IAAY,EAAE,EAAU;IAClD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG;YAAE,KAAK,IAAI,CAAC,CAAC;aAC3B,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACzB,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;gBAChB,IAAI,GAAG,CAAC,CAAC;gBACT,MAAM;YACR,CAAC;YACD,KAAK,IAAI,CAAC,CAAC;QACb,CAAC;IACH,CAAC;IACD,IAAI,IAAI,KAAK,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IAC3B,IAAI,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC;IACrB,OAAO,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAAE,KAAK,IAAI,CAAC,CAAC;IAC9D,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;IACpD,OAAO,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAChF,CAAC;AAQD,MAAM,UAAU,gBAAgB,CAAC,IAAc;IAC7C,MAAM,GAAG,GAAsB,EAAE,CAAC;IAClC,KAAK,MAAM,KAAK,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,IAAI,KAAK,CAAC,MAAM;YAAE,SAAS;QAC3B,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;YACnC,MAAM,MAAM,GACV,CAAC,CAAC,CAAC,QAAQ,KAAK,eAAe,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;gBAChE,CAAC,CAAC,QAAQ,KAAK,oBAAoB;gBACnC,CAAC,CAAC,QAAQ,KAAK,YAAY,CAAC;YAC9B,IAAI,MAAM;gBACR,GAAG,CAAC,IAAI,CAAC;oBACP,KAAK,EAAE,CAAC,CAAC,KAAK;oBACd,SAAS,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;oBACzC,MAAM,EAAE,GAAG,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,KAAK,EAAE;iBACpC,CAAC,CAAC;QACP,CAAC;IACH,CAAC;IACD,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IACjD,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3D,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;QACxD,IAAI,MAAM,CAAC,MAAM;YACf,GAAG,CAAC,IAAI,CAAC;gBACP,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,SAAS,EAAE,kBAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC;gBACjD,MAAM,EAAE,UAAU,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;aACrC,CAAC,CAAC;IACP,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAc;IAC5C,MAAM,IAAI,GAAU,EAAE,CAAC;IACvB,KAAK,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,WAAW,CAAC,IAAI,CAAC;QAC7C,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,IAAI,CAAC;YAChC,IAAI,iBAAiB,CAAC,KAAK,CAAC;gBAAE,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IACtE,WAAW,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE;QACpC,IACE,CAAC,EAAE,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,6BAA6B,CAAC,IAAI,CAAC,CAAC;YACzE,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7D,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;YAErC,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,UAAU,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC7F,CAAC,CAAC,CAAC;IACH,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,IAAc,EACd,KAA2D;IAE3D,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IACrE,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;IACvD,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY;QAAE,OAAO,EAAE,CAAC;IAC1C,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACzE,OAAO,gBAAgB,CAAC,IAAI,CAAC;SAC1B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;SAC9E,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAkD;IAClF,EAAE,EAAE,kBAAkB;IACtB,UAAU,EAAE,KAAK;IACjB,YAAY,CAAC,KAAK;QAChB,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,WAAW,CAAC,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,QAAQ,CAAC,CAAC;QACjE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM;YAAE,QAAQ,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;;YAC/E,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC5E,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAC;QACzD,IAAI,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,IAAI,iBAAiB,CAAC,KAAK,CAAC,WAAW,CAAC;YACpE,QAAQ,CAAC,IAAI,CAAC,eAAe,KAAK,CAAC,WAAW,oCAAoC,CAAC,CAAC;QACtF,gBAAgB,CAAC,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE;YAC5D,GAAG,EAAE,UAAU;YACf,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;QACH,IACE,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC;YAC1B,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC;YAC1B,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;YAEvF,QAAQ,CAAC,IAAI,CAAC,0DAA0D,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;QAC/F,iBAAiB,CAAC,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;QAC7D,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC5C,MAAM,KAAK,GAAG,iBAAiB,CAAC;YAC9B,KAAK,EAAE,wDAAwD;YAC/D,WAAW,EACT,SAAS,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,oDAAoD,KAAK,CAAC,WAAW,WAAW;gBAC/G,+GAA+G;gBAC/G,6GAA6G;gBAC7G,iHAAiH;gBACjH,kCAAkC;gBAClC,0EAA0E,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK;gBAClI,6CAA6C,KAAK,CAAC,eAAe,8CAA8C;gBAChH,iHAAiH;gBACjH,uCAAuC;YACzC,KAAK,EAAE,mBAAmB;YAC1B,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC;YAC5C,SAAS,EAAE,KAAK,CAAC,UAAU;YAC3B,OAAO,EAAE;gBACP,KAAK,EAAE;oBACL,EAAE,IAAI,EAAE,GAAG,IAAI,aAAa,EAAE,IAAI,EAAE,iDAAiD,EAAE;oBACvF,EAAE,IAAI,EAAE,GAAG,IAAI,aAAa,EAAE,IAAI,EAAE,uCAAuC,EAAE;oBAC7E;wBACE,IAAI,EAAE,GAAG,IAAI,aAAa;wBAC1B,IAAI,EAAE,8DAA8D;qBACrE;oBACD,EAAE,IAAI,EAAE,GAAG,IAAI,aAAa,EAAE,IAAI,EAAE,4CAA4C,EAAE;oBAClF,EAAE,IAAI,EAAE,GAAG,IAAI,aAAa,EAAE,IAAI,EAAE,0CAA0C,EAAE;oBAChF,EAAE,IAAI,EAAE,GAAG,IAAI,aAAa,EAAE,IAAI,EAAE,sCAAsC,EAAE;iBAC7E;gBACD,MAAM,EAAE;oBACN;wBACE,IAAI,EAAE,GAAG,IAAI,aAAa;wBAC1B,IAAI,EAAE,4BAA4B,KAAK,CAAC,WAAW,gBAAgB;qBACpE;oBACD;wBACE,IAAI,EAAE,GAAG,IAAI,aAAa;wBAC1B,IAAI,EAAE,8DAA8D;qBACrE;oBACD,EAAE,IAAI,EAAE,GAAG,IAAI,aAAa,EAAE,IAAI,EAAE,GAAG,KAAK,+BAA+B,EAAE;oBAC7E,EAAE,IAAI,EAAE,GAAG,IAAI,aAAa,EAAE,IAAI,EAAE,gCAAgC,EAAE;iBACvE;aACF;SACF,CAAC,CAAC;QACH,OAAO;YACL;gBACE,GAAG,KAAK;gBACR,KAAK,CAAC,GAAG,CAAC,OAAO;oBACf,MAAM,QAAQ,GAAc,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;oBAC5D,MAAM,KAAK,GAAG,OAAO;yBAClB,KAAK,CAAC,mBAAmB,CAAC;yBAC1B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;oBAC9D,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK;wBACzB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;4BACxC,QAAQ,CAAC,IAAI,CAAC;gCACZ,IAAI,EAAE,CAAC;gCACP,MAAM,EAAE,oEAAoE;6BAC7E,CAAC,CAAC;oBACP,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;oBACjE,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;oBAClC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;oBAC/B,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,CAAC;wBACxE,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY;4BAC5B,KAAK,MAAM,KAAK,IAAI,gBAAgB,CAAC,IAAI,CAAC;gCACxC,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS;oCAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;oBACnD,KAAK,MAAM,EAAE,QAAQ,EAAE,IAAI,KAAK,CAAC,WAAW;wBAC1C,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;4BAC7B,QAAQ,CAAC,IAAI,CAAC;gCACZ,IAAI,EAAE,eAAe;gCACrB,MAAM,EAAE,6CAA6C,QAAQ,qBAAqB;6BACnF,CAAC,CAAC;oBACP,OAAO,QAAQ,CAAC;gBAClB,CAAC;aACF;SACF,CAAC;IACJ,CAAC;CACF,CAAC","sourcesContent":["import ts from 'typescript';\nimport type { GenericGuardDefinition } from '../../node/suite/config.js';\nimport type { Finding } from '../../guard.js';\nimport type { Scope } from '../../node/reader.js';\nimport type { FileView } from '../../reader/view.js';\nimport { reviewedAllowlist, type AllowlistEntry, type Hit } from '../../shapes/shapes.js';\nimport { forEachNode } from '../../support/ast.js';\nimport {\n allowlistProblems,\n isText,\n pathProblem,\n reviewedProblems,\n textProblem,\n isList,\n} from '../../support/facts.js';\nimport { isUnder } from '../../support/text.js';\nimport { cssBlocks, selectorsOf, splitTopLevel } from './css.js';\nimport { loadedStylesheets } from './stylesheets.js';\nimport { bareToken, codeStrings, tokensOf } from './source.js';\n\nconst APP_CODE_AND_STYLES: Scope = { roots: ['app'], kinds: ['code', 'stylesheet'], tests: false };\n\nconst TRUNCATION_TOKEN = /^(?:truncate|text-ellipsis|line-clamp-(?:\\d+|none|\\[[^\\]]+\\]))$/;\nconst INLINE_STYLE_KEYS = new Set(['textOverflow', 'WebkitLineClamp', 'lineClamp']);\nconst APPLY = /@apply\\s+([^;{}]+)/g;\n\nexport interface SharedTruncationFacts {\n entryStylesheet: string;\n trees: readonly string[];\n sharedClass: string;\n clampOwners: ReadonlyArray<{ selector: string; why: string }>;\n exceptions: readonly AllowlistEntry[];\n}\n\nconst squash = (text: string) => text.replace(/\\s+/g, ' ').trim();\n\nexport const isTruncationToken = (token: string): boolean =>\n TRUNCATION_TOKEN.test(bareToken(token).replace(/^!/, ''));\n\nfunction enclosingSelectors(code: string, at: number): string[] {\n let depth = 0;\n let open = -1;\n for (let i = at - 1; i >= 0; i -= 1) {\n if (code[i] === '}') depth += 1;\n else if (code[i] === '{') {\n if (depth === 0) {\n open = i;\n break;\n }\n depth -= 1;\n }\n }\n if (open === -1) return [];\n let start = open - 1;\n while (start >= 0 && !'{};'.includes(code[start])) start -= 1;\n const prelude = squash(code.slice(start + 1, open));\n return prelude.startsWith('@') ? [] : splitTopLevel(prelude, ',').map(squash);\n}\n\ninterface StylesheetClamp {\n index: number;\n selectors: string[];\n detail: string;\n}\n\nexport function stylesheetClamps(file: FileView): StylesheetClamp[] {\n const out: StylesheetClamp[] = [];\n for (const block of cssBlocks(file.code)) {\n if (block.atRule) continue;\n for (const d of block.declarations) {\n const clamps =\n (d.property === 'text-overflow' && /\\bellipsis\\b/.test(d.value)) ||\n d.property === '-webkit-line-clamp' ||\n d.property === 'line-clamp';\n if (clamps)\n out.push({\n index: d.index,\n selectors: selectorsOf(block).map(squash),\n detail: `${d.property}: ${d.value}`,\n });\n }\n }\n const re = new RegExp(APPLY.source, APPLY.flags);\n for (let m = re.exec(file.code); m; m = re.exec(file.code)) {\n const tokens = tokensOf(m[1]).filter(isTruncationToken);\n if (tokens.length)\n out.push({\n index: m.index,\n selectors: enclosingSelectors(file.code, m.index),\n detail: `@apply ${tokens.join(' ')}`,\n });\n }\n return out.sort((a, b) => a.index - b.index);\n}\n\nexport function codeTruncations(file: FileView): Hit[] {\n const hits: Hit[] = [];\n for (const { text, index } of codeStrings(file))\n for (const token of tokensOf(text))\n if (isTruncationToken(token)) hits.push({ index, detail: token });\n forEachNode(file.sourceFile, (node) => {\n if (\n (ts.isPropertyAssignment(node) || ts.isShorthandPropertyAssignment(node)) &&\n (ts.isIdentifier(node.name) || ts.isStringLiteral(node.name)) &&\n INLINE_STYLE_KEYS.has(node.name.text)\n )\n hits.push({ index: node.getStart(file.sourceFile), detail: `inline ${node.name.text}` });\n });\n return hits.sort((a, b) => a.index - b.index);\n}\n\nexport function truncationHits(\n file: FileView,\n facts: Pick<SharedTruncationFacts, 'trees' | 'clampOwners'>,\n): Hit[] {\n if (!facts.trees.some((tree) => isUnder(file.path, tree))) return [];\n if (file.kind === 'code') return codeTruncations(file);\n if (file.kind !== 'stylesheet') return [];\n const owners = new Set(facts.clampOwners.map((o) => squash(o.selector)));\n return stylesheetClamps(file)\n .filter((c) => !c.selectors.length || !c.selectors.every((s) => owners.has(s)))\n .map((c) => ({ index: c.index, detail: c.detail }));\n}\n\nexport const sharedTruncationGuard: GenericGuardDefinition<SharedTruncationFacts> = {\n id: 'sharedTruncation',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n pathProblem(facts?.entryStylesheet, 'entryStylesheet', problems);\n if (!isList(facts?.trees) || !facts.trees.length) problems.push('trees is missing');\n else facts.trees.forEach((t, i) => pathProblem(t, `trees[${i}]`, problems));\n textProblem(facts?.sharedClass, 'sharedClass', problems);\n if (isText(facts?.sharedClass) && isTruncationToken(facts.sharedClass))\n problems.push(`sharedClass ${facts.sharedClass} is itself a per-call-site utility`);\n reviewedProblems(facts?.clampOwners, 'clampOwners', problems, {\n key: 'selector',\n nonEmpty: true,\n });\n if (\n isList(facts?.clampOwners) &&\n isText(facts?.sharedClass) &&\n !facts.clampOwners.some((o) => squash(String(o?.selector)) === `.${facts.sharedClass}`)\n )\n problems.push(`clampOwners does not hold the shared class's selector .${facts.sharedClass}`);\n allowlistProblems(facts?.exceptions, 'exceptions', problems);\n return problems;\n },\n build(facts) {\n const tree = facts.trees[0];\n const owner = facts.clampOwners[0].selector;\n const guard = reviewedAllowlist({\n title: 'titles and names truncate through the one shared class',\n description:\n `Under ${facts.trees.join(', ')}, text truncates only through the shared class \\`${facts.sharedClass}\\`. Code ` +\n 'never names a per-call-site truncation utility (`truncate`, `line-clamp-<n|none|[…]>`, `text-ellipsis`, with ' +\n 'or without a variant prefix) in a string, template, or className, and never sets an inline `textOverflow`, ' +\n '`WebkitLineClamp`, or `lineClamp` style. A stylesheet sets `text-overflow: ellipsis`, `-webkit-line-clamp`, or ' +\n '`line-clamp` (or applies one of ' +\n `those utilities) only in a rule whose every selector is a clamp owner (${facts.clampOwners.map((o) => o.selector).join(', ')}). ` +\n `A clamp owner is declared by a stylesheet ${facts.entryStylesheet} loads — the theme package's or the app's — ` +\n 'and one no loaded stylesheet declares as a clamp any more is stale. Use the shared class, or add a clamp owner ' +\n 'or a reviewed exception with its why.',\n scope: APP_CODE_AND_STYLES,\n match: (file) => truncationHits(file, facts),\n allowlist: facts.exceptions,\n samples: {\n flags: [\n { path: `${tree}/sample.tsx`, text: '<h2 className=\"font-bold truncate\">{title}</h2>' },\n { path: `${tree}/sample.tsx`, text: 'const c = cn(`md:line-clamp-2 ${x}`);' },\n {\n path: `${tree}/sample.tsx`,\n text: \"<p className={open ? 'line-clamp-none' : 'text-ellipsis'} />\",\n },\n { path: `${tree}/sample.tsx`, text: \"<p style={{ textOverflow: 'ellipsis' }} />\" },\n { path: `${tree}/sample.css`, text: '.card-title { text-overflow: ellipsis; }' },\n { path: `${tree}/sample.css`, text: '.card-title { @apply line-clamp-3; }' },\n ],\n passes: [\n {\n path: `${tree}/sample.tsx`,\n text: `<h2 className=\"font-bold ${facts.sharedClass}\">{title}</h2>`,\n },\n {\n path: `${tree}/sample.tsx`,\n text: '// a truncate class would go here\\nconst mode = \"truncated\";',\n },\n { path: `${tree}/sample.css`, text: `${owner} { text-overflow: ellipsis; }` },\n { path: `${tree}/sample.css`, text: '.card { text-overflow: clip; }' },\n ],\n },\n });\n return [\n {\n ...guard,\n async run(context) {\n const findings: Finding[] = [...(await guard.run(context))];\n const files = context\n .files(APP_CODE_AND_STYLES)\n .filter((f) => facts.trees.some((t) => isUnder(f.path, t)));\n for (const t of facts.trees)\n if (!files.some((f) => isUnder(f.path, t)))\n findings.push({\n file: t,\n detail: 'the tree holds no production code or stylesheet the guard can read',\n });\n const loaded = loadedStylesheets(context, facts.entryStylesheet);\n findings.push(...loaded.findings);\n const held = new Set<string>();\n for (const file of [...loaded.sheets.map((sheet) => sheet.file), ...files])\n if (file.kind === 'stylesheet')\n for (const clamp of stylesheetClamps(file))\n for (const s of clamp.selectors) held.add(s);\n for (const { selector } of facts.clampOwners)\n if (!held.has(squash(selector)))\n findings.push({\n file: '(clampOwners)',\n detail: `stale clamp owner: no stylesheet rule for ${selector} truncates any more`,\n });\n return findings;\n },\n },\n ];\n },\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttt-productions/repo-guards",
3
- "version": "0.1.32",
3
+ "version": "0.1.34",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/ttt-productions/ttt-packages.git",