@ttt-productions/repo-guards 0.1.27 → 0.1.28

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.
@@ -13,4 +13,9 @@ export interface FirestoreRuntimeInUiFacts {
13
13
  }
14
14
  export declare function firestoreRuntimeImports(file: FileView): Hit[];
15
15
  export declare const firestoreRuntimeInUiGuard: GenericGuardDefinition<FirestoreRuntimeInUiFacts>;
16
+ export interface FirestoreClientWritesFacts {
17
+ sanctioned: readonly Reviewed[];
18
+ }
19
+ export declare function firestoreClientWriteHits(file: FileView): Hit[];
20
+ export declare const firestoreClientWritesGuard: GenericGuardDefinition<FirestoreClientWritesFacts>;
16
21
  //# sourceMappingURL=client-guards.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-guards.d.ts","sourceRoot":"","sources":["../../../src/modules/firestore/client-guards.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;AASrE,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,QAAQ,GAAG,GAAG,EAAE,CA4B1D;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,SAAS,QAAQ,EAAE,CAAC;CAChC;AAED,eAAO,MAAM,qBAAqB,EAAE,sBAAsB,CAAC,qBAAqB,CAwC/E,CAAC;AAEF,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,UAAU,EAAE,SAAS,QAAQ,EAAE,CAAC;CACjC;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,QAAQ,GAAG,GAAG,EAAE,CAoB7D;AAED,eAAO,MAAM,yBAAyB,EAAE,sBAAsB,CAAC,yBAAyB,CA+CvF,CAAC"}
1
+ {"version":3,"file":"client-guards.d.ts","sourceRoot":"","sources":["../../../src/modules/firestore/client-guards.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;AASrE,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,QAAQ,GAAG,GAAG,EAAE,CA4B1D;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,SAAS,QAAQ,EAAE,CAAC;CAChC;AAED,eAAO,MAAM,qBAAqB,EAAE,sBAAsB,CAAC,qBAAqB,CAwC/E,CAAC;AAEF,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,UAAU,EAAE,SAAS,QAAQ,EAAE,CAAC;CACjC;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,QAAQ,GAAG,GAAG,EAAE,CAoB7D;AAED,eAAO,MAAM,yBAAyB,EAAE,sBAAsB,CAAC,yBAAyB,CA+CvF,CAAC;AAWF,MAAM,WAAW,0BAA0B;IACzC,UAAU,EAAE,SAAS,QAAQ,EAAE,CAAC;CACjC;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,QAAQ,GAAG,GAAG,EAAE,CAwB9D;AAED,eAAO,MAAM,0BAA0B,EAAE,sBAAsB,CAAC,0BAA0B,CAoCzF,CAAC"}
@@ -153,4 +153,73 @@ export const firestoreRuntimeInUiGuard = {
153
153
  ];
154
154
  },
155
155
  };
156
+ const CLIENT_WRITES = new Set([
157
+ 'setDoc',
158
+ 'updateDoc',
159
+ 'deleteDoc',
160
+ 'addDoc',
161
+ 'writeBatch',
162
+ 'runTransaction',
163
+ ]);
164
+ export function firestoreClientWriteHits(file) {
165
+ const source = file.sourceFile;
166
+ const hits = [];
167
+ const namespaces = new Set();
168
+ for (const site of moduleImports(source, ['import', 'export'])) {
169
+ if (!FIRESTORE_SDK.test(site.spec) || site.typeOnly)
170
+ continue;
171
+ if (site.namespace)
172
+ namespaces.add(site.namespace);
173
+ for (const name of site.named)
174
+ if (!name.typeOnly && CLIENT_WRITES.has(name.imported))
175
+ hits.push({
176
+ index: site.node.getStart(source),
177
+ detail: `${name.imported} from '${site.spec}'`,
178
+ });
179
+ }
180
+ forEachNode(source, (node) => {
181
+ if (ts.isPropertyAccessExpression(node) &&
182
+ ts.isIdentifier(node.expression) &&
183
+ namespaces.has(node.expression.text) &&
184
+ CLIENT_WRITES.has(node.name.text))
185
+ hits.push({ index: node.getStart(source), detail: node.getText(source) });
186
+ });
187
+ return hits;
188
+ }
189
+ export const firestoreClientWritesGuard = {
190
+ id: 'firestoreClientWrites',
191
+ absentWhen: 'the app stores nothing in Firestore',
192
+ factProblems(facts) {
193
+ const problems = [];
194
+ reviewedProblems(facts?.sanctioned, 'sanctioned', problems);
195
+ return problems;
196
+ },
197
+ build(facts) {
198
+ return [
199
+ reviewedAllowlist({
200
+ title: 'the client never writes Firestore',
201
+ description: 'Every write goes through a callable that checks it on the server; a client SDK write skips that check and ' +
202
+ 'every rule the callable enforces. Flagged: a runtime import of a Firestore write function (' +
203
+ `${[...CLIENT_WRITES].join(', ')}) from the Firestore SDK, or a call to one through a namespace import, in ` +
204
+ "the app's client source. Fix: call the callable that owns the write. A sanctioned site is a reviewed entry " +
205
+ 'with its why; one that no longer writes is stale.',
206
+ scope: APP_SOURCE,
207
+ match: firestoreClientWriteHits,
208
+ allowlist: facts.sanctioned,
209
+ samples: {
210
+ flags: [
211
+ "import { doc, setDoc } from 'firebase/firestore';",
212
+ "import { writeBatch as batchOf } from 'firebase/firestore';",
213
+ "import * as fs from 'firebase/firestore';\nawait fs.updateDoc(ref, patch);",
214
+ ],
215
+ passes: [
216
+ "import { doc, getDoc, onSnapshot } from 'firebase/firestore';",
217
+ "import { type WriteBatch } from 'firebase/firestore';",
218
+ 'await callable({ id });',
219
+ ],
220
+ },
221
+ }),
222
+ ];
223
+ },
224
+ };
156
225
  //# sourceMappingURL=client-guards.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-guards.js","sourceRoot":"","sources":["../../../src/modules/firestore/client-guards.ts"],"names":[],"mappings":"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","sourcesContent":["import ts from 'typescript';\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 { reviewedAllowlist, type Hit } from '../../shapes/shapes.js';\nimport { forEachNode } from '../../support/ast.js';\nimport { namesProblem, reviewedProblems } from '../../support/facts.js';\nimport { moduleImports } from '../../support/imports.js';\nimport { isUnder } from '../../support/text.js';\n\nconst FIRESTORE_SDK = /^firebase\\/firestore(?:\\/|$)/;\nconst APP_SOURCE: Scope = { roots: ['app'], kinds: ['code'], tests: false };\n\nexport function liveSubscriptionHits(file: FileView): Hit[] {\n const source = file.sourceFile;\n const snapshotNames = new Set(['onSnapshot']);\n const namespaces = new Set<string>();\n for (const site of moduleImports(source, ['import'])) {\n if (!site.topLevel || !FIRESTORE_SDK.test(site.spec)) continue;\n if (site.namespace) namespaces.add(site.namespace);\n for (const name of site.named)\n if (name.imported === 'onSnapshot') snapshotNames.add(name.local);\n }\n const hits: Hit[] = [];\n const at = (node: ts.Node, detail: string) => hits.push({ index: node.getStart(source), detail });\n forEachNode(source, (node) => {\n if (ts.isPropertyAssignment(node) && ts.isObjectLiteralExpression(node.parent)) {\n const key =\n ts.isIdentifier(node.name) || ts.isStringLiteral(node.name) ? node.name.text : null;\n if (key === 'subscribe' && node.initializer.kind !== ts.SyntaxKind.FalseKeyword)\n at(node, `subscribe: ${node.initializer.getText(source)}`);\n } else if (ts.isShorthandPropertyAssignment(node) && node.name.text === 'subscribe') {\n at(node, '{ subscribe }');\n } else if (ts.isCallExpression(node)) {\n const callee = node.expression;\n if (ts.isIdentifier(callee) && snapshotNames.has(callee.text)) at(node, `${callee.text}(…)`);\n else if (ts.isPropertyAccessExpression(callee) && callee.name.text === 'onSnapshot')\n at(node, `${callee.getText(source)}(…)`);\n }\n });\n return hits;\n}\n\nexport interface LiveSubscriptionFacts {\n allowlist: readonly Reviewed[];\n}\n\nexport const liveSubscriptionGuard: GenericGuardDefinition<LiveSubscriptionFacts> = {\n id: 'firestoreLiveSubscriptions',\n absentWhen: 'the app stores nothing in Firestore',\n factProblems(facts) {\n const problems: string[] = [];\n reviewedProblems(facts?.allowlist, 'allowlist', problems);\n return problems;\n },\n build(facts) {\n return [\n reviewedAllowlist({\n title: 'every live Firestore subscription is on the reviewed list',\n description:\n 'A live read bills a document read on every change for as long as it is mounted, so it is a reviewed exception: ' +\n 'a file that declares live mode — a subscribe option set to anything but a literal false, the { subscribe } ' +\n \"shorthand, or an onSnapshot call under any name the file bound the Firestore SDK's to — is on the reviewed \" +\n 'list with why it needs real-time delivery. Fix: read once and keep it fresh through the cache, or add the ' +\n 'reviewed entry. An entry whose file no longer subscribes is stale.',\n scope: APP_SOURCE,\n match: liveSubscriptionHits,\n allowlist: facts.allowlist,\n samples: {\n flags: [\n 'useFirestoreDoc({ docPath, queryKey, subscribe: true });',\n 'useBatchFirestoreDocs({ ids, subscribe: isLive });',\n 'useFirestoreCollection({ collectionPath, subscribe, enabled });',\n \"import { doc, onSnapshot as listen } from 'firebase/firestore';\\nconst stop = listen(doc(db, p), render);\",\n \"import * as fs from 'firebase/firestore';\\nconst stop = fs.onSnapshot(ref, handle);\",\n ],\n passes: [\n \"useBatchFirestoreDocs({ db, collectionPath, ids, transport: 'get' });\",\n 'useFirestoreDoc({ docPath, queryKey, subscribe: false });',\n 'const unsubscribe = cache.subscribe((event) => handle(event));',\n 'return useSyncExternalStore(subscribe, readValue, getServerValue);',\n '// subscribe: true is a reviewed exception\\nconst x = 1;',\n ],\n },\n }),\n ];\n },\n};\n\nexport interface FirestoreRuntimeInUiFacts {\n uiFolders: readonly string[];\n sanctioned: readonly Reviewed[];\n}\n\nexport function firestoreRuntimeImports(file: FileView): Hit[] {\n const source = file.sourceFile;\n const hits: Hit[] = [];\n for (const site of moduleImports(source, ['import', 'export', 'dynamic'])) {\n if (!FIRESTORE_SDK.test(site.spec)) continue;\n const at = site.node.getStart(source);\n if (site.kind === 'import') {\n const typeOnly =\n !site.sideEffect &&\n (site.typeOnly ||\n (!site.defaultName &&\n !site.namespace &&\n site.named.length > 0 &&\n site.named.every((n) => n.typeOnly)));\n if (!typeOnly) hits.push({ index: at, detail: `import from '${site.spec}'` });\n } else if (site.kind === 'export') {\n if (!site.typeOnly) hits.push({ index: at, detail: `re-export from '${site.spec}'` });\n } else hits.push({ index: at, detail: `import('${site.spec}')` });\n }\n return hits;\n}\n\nexport const firestoreRuntimeInUiGuard: GenericGuardDefinition<FirestoreRuntimeInUiFacts> = {\n id: 'firestoreRuntimeInUi',\n absentWhen: 'the app stores nothing in Firestore',\n factProblems(facts) {\n const problems: string[] = [];\n namesProblem(facts?.uiFolders, 'uiFolders', problems);\n reviewedProblems(facts?.sanctioned, 'sanctioned', problems);\n return problems;\n },\n build(facts) {\n const inUi = (path: string) => facts.uiFolders.some((folder) => isUnder(path, folder));\n return [\n reviewedAllowlist({\n title: 'no component or route imports the Firestore runtime',\n description:\n 'A component or route that reaches into Firestore bypasses the cache, the query keys, and every server check ' +\n 'at once. Flagged: a runtime import, re-export, or dynamic import of the Firestore SDK (a type-only import ' +\n 'passes) in the UI folders. Fix: read through a hook, write through a callable. A sanctioned root provider is ' +\n 'a reviewed entry with its why; one that no longer imports the runtime is stale.',\n scope: APP_SOURCE,\n match: (file) => (inUi(file.path) ? firestoreRuntimeImports(file) : []),\n allowlist: facts.sanctioned,\n samples: {\n flags: [\n {\n path: `${facts.uiFolders[0]}/probe.tsx`,\n text: \"import { doc, getDoc } from 'firebase/firestore';\",\n },\n {\n path: `${facts.uiFolders[0]}/probe.tsx`,\n text: 'import {\\n updateDoc,\\n} from \"firebase/firestore\";',\n },\n ],\n passes: [\n {\n path: `${facts.uiFolders[0]}/typed.tsx`,\n text: \"import type { Timestamp } from 'firebase/firestore';\",\n },\n {\n path: `${facts.uiFolders[0]}/typed.tsx`,\n text: \"import { type Timestamp } from 'firebase/firestore';\",\n },\n ],\n },\n }),\n ];\n },\n};\n"]}
1
+ {"version":3,"file":"client-guards.js","sourceRoot":"","sources":["../../../src/modules/firestore/client-guards.ts"],"names":[],"mappings":"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","sourcesContent":["import ts from 'typescript';\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 { reviewedAllowlist, type Hit } from '../../shapes/shapes.js';\nimport { forEachNode } from '../../support/ast.js';\nimport { namesProblem, reviewedProblems } from '../../support/facts.js';\nimport { moduleImports } from '../../support/imports.js';\nimport { isUnder } from '../../support/text.js';\n\nconst FIRESTORE_SDK = /^firebase\\/firestore(?:\\/|$)/;\nconst APP_SOURCE: Scope = { roots: ['app'], kinds: ['code'], tests: false };\n\nexport function liveSubscriptionHits(file: FileView): Hit[] {\n const source = file.sourceFile;\n const snapshotNames = new Set(['onSnapshot']);\n const namespaces = new Set<string>();\n for (const site of moduleImports(source, ['import'])) {\n if (!site.topLevel || !FIRESTORE_SDK.test(site.spec)) continue;\n if (site.namespace) namespaces.add(site.namespace);\n for (const name of site.named)\n if (name.imported === 'onSnapshot') snapshotNames.add(name.local);\n }\n const hits: Hit[] = [];\n const at = (node: ts.Node, detail: string) => hits.push({ index: node.getStart(source), detail });\n forEachNode(source, (node) => {\n if (ts.isPropertyAssignment(node) && ts.isObjectLiteralExpression(node.parent)) {\n const key =\n ts.isIdentifier(node.name) || ts.isStringLiteral(node.name) ? node.name.text : null;\n if (key === 'subscribe' && node.initializer.kind !== ts.SyntaxKind.FalseKeyword)\n at(node, `subscribe: ${node.initializer.getText(source)}`);\n } else if (ts.isShorthandPropertyAssignment(node) && node.name.text === 'subscribe') {\n at(node, '{ subscribe }');\n } else if (ts.isCallExpression(node)) {\n const callee = node.expression;\n if (ts.isIdentifier(callee) && snapshotNames.has(callee.text)) at(node, `${callee.text}(…)`);\n else if (ts.isPropertyAccessExpression(callee) && callee.name.text === 'onSnapshot')\n at(node, `${callee.getText(source)}(…)`);\n }\n });\n return hits;\n}\n\nexport interface LiveSubscriptionFacts {\n allowlist: readonly Reviewed[];\n}\n\nexport const liveSubscriptionGuard: GenericGuardDefinition<LiveSubscriptionFacts> = {\n id: 'firestoreLiveSubscriptions',\n absentWhen: 'the app stores nothing in Firestore',\n factProblems(facts) {\n const problems: string[] = [];\n reviewedProblems(facts?.allowlist, 'allowlist', problems);\n return problems;\n },\n build(facts) {\n return [\n reviewedAllowlist({\n title: 'every live Firestore subscription is on the reviewed list',\n description:\n 'A live read bills a document read on every change for as long as it is mounted, so it is a reviewed exception: ' +\n 'a file that declares live mode — a subscribe option set to anything but a literal false, the { subscribe } ' +\n \"shorthand, or an onSnapshot call under any name the file bound the Firestore SDK's to — is on the reviewed \" +\n 'list with why it needs real-time delivery. Fix: read once and keep it fresh through the cache, or add the ' +\n 'reviewed entry. An entry whose file no longer subscribes is stale.',\n scope: APP_SOURCE,\n match: liveSubscriptionHits,\n allowlist: facts.allowlist,\n samples: {\n flags: [\n 'useFirestoreDoc({ docPath, queryKey, subscribe: true });',\n 'useBatchFirestoreDocs({ ids, subscribe: isLive });',\n 'useFirestoreCollection({ collectionPath, subscribe, enabled });',\n \"import { doc, onSnapshot as listen } from 'firebase/firestore';\\nconst stop = listen(doc(db, p), render);\",\n \"import * as fs from 'firebase/firestore';\\nconst stop = fs.onSnapshot(ref, handle);\",\n ],\n passes: [\n \"useBatchFirestoreDocs({ db, collectionPath, ids, transport: 'get' });\",\n 'useFirestoreDoc({ docPath, queryKey, subscribe: false });',\n 'const unsubscribe = cache.subscribe((event) => handle(event));',\n 'return useSyncExternalStore(subscribe, readValue, getServerValue);',\n '// subscribe: true is a reviewed exception\\nconst x = 1;',\n ],\n },\n }),\n ];\n },\n};\n\nexport interface FirestoreRuntimeInUiFacts {\n uiFolders: readonly string[];\n sanctioned: readonly Reviewed[];\n}\n\nexport function firestoreRuntimeImports(file: FileView): Hit[] {\n const source = file.sourceFile;\n const hits: Hit[] = [];\n for (const site of moduleImports(source, ['import', 'export', 'dynamic'])) {\n if (!FIRESTORE_SDK.test(site.spec)) continue;\n const at = site.node.getStart(source);\n if (site.kind === 'import') {\n const typeOnly =\n !site.sideEffect &&\n (site.typeOnly ||\n (!site.defaultName &&\n !site.namespace &&\n site.named.length > 0 &&\n site.named.every((n) => n.typeOnly)));\n if (!typeOnly) hits.push({ index: at, detail: `import from '${site.spec}'` });\n } else if (site.kind === 'export') {\n if (!site.typeOnly) hits.push({ index: at, detail: `re-export from '${site.spec}'` });\n } else hits.push({ index: at, detail: `import('${site.spec}')` });\n }\n return hits;\n}\n\nexport const firestoreRuntimeInUiGuard: GenericGuardDefinition<FirestoreRuntimeInUiFacts> = {\n id: 'firestoreRuntimeInUi',\n absentWhen: 'the app stores nothing in Firestore',\n factProblems(facts) {\n const problems: string[] = [];\n namesProblem(facts?.uiFolders, 'uiFolders', problems);\n reviewedProblems(facts?.sanctioned, 'sanctioned', problems);\n return problems;\n },\n build(facts) {\n const inUi = (path: string) => facts.uiFolders.some((folder) => isUnder(path, folder));\n return [\n reviewedAllowlist({\n title: 'no component or route imports the Firestore runtime',\n description:\n 'A component or route that reaches into Firestore bypasses the cache, the query keys, and every server check ' +\n 'at once. Flagged: a runtime import, re-export, or dynamic import of the Firestore SDK (a type-only import ' +\n 'passes) in the UI folders. Fix: read through a hook, write through a callable. A sanctioned root provider is ' +\n 'a reviewed entry with its why; one that no longer imports the runtime is stale.',\n scope: APP_SOURCE,\n match: (file) => (inUi(file.path) ? firestoreRuntimeImports(file) : []),\n allowlist: facts.sanctioned,\n samples: {\n flags: [\n {\n path: `${facts.uiFolders[0]}/probe.tsx`,\n text: \"import { doc, getDoc } from 'firebase/firestore';\",\n },\n {\n path: `${facts.uiFolders[0]}/probe.tsx`,\n text: 'import {\\n updateDoc,\\n} from \"firebase/firestore\";',\n },\n ],\n passes: [\n {\n path: `${facts.uiFolders[0]}/typed.tsx`,\n text: \"import type { Timestamp } from 'firebase/firestore';\",\n },\n {\n path: `${facts.uiFolders[0]}/typed.tsx`,\n text: \"import { type Timestamp } from 'firebase/firestore';\",\n },\n ],\n },\n }),\n ];\n },\n};\n\nconst CLIENT_WRITES = new Set([\n 'setDoc',\n 'updateDoc',\n 'deleteDoc',\n 'addDoc',\n 'writeBatch',\n 'runTransaction',\n]);\n\nexport interface FirestoreClientWritesFacts {\n sanctioned: readonly Reviewed[];\n}\n\nexport function firestoreClientWriteHits(file: FileView): Hit[] {\n const source = file.sourceFile;\n const hits: Hit[] = [];\n const namespaces = new Set<string>();\n for (const site of moduleImports(source, ['import', 'export'])) {\n if (!FIRESTORE_SDK.test(site.spec) || site.typeOnly) continue;\n if (site.namespace) namespaces.add(site.namespace);\n for (const name of site.named)\n if (!name.typeOnly && CLIENT_WRITES.has(name.imported))\n hits.push({\n index: site.node.getStart(source),\n detail: `${name.imported} from '${site.spec}'`,\n });\n }\n forEachNode(source, (node) => {\n if (\n ts.isPropertyAccessExpression(node) &&\n ts.isIdentifier(node.expression) &&\n namespaces.has(node.expression.text) &&\n CLIENT_WRITES.has(node.name.text)\n )\n hits.push({ index: node.getStart(source), detail: node.getText(source) });\n });\n return hits;\n}\n\nexport const firestoreClientWritesGuard: GenericGuardDefinition<FirestoreClientWritesFacts> = {\n id: 'firestoreClientWrites',\n absentWhen: 'the app stores nothing in Firestore',\n factProblems(facts) {\n const problems: string[] = [];\n reviewedProblems(facts?.sanctioned, 'sanctioned', problems);\n return problems;\n },\n build(facts) {\n return [\n reviewedAllowlist({\n title: 'the client never writes Firestore',\n description:\n 'Every write goes through a callable that checks it on the server; a client SDK write skips that check and ' +\n 'every rule the callable enforces. Flagged: a runtime import of a Firestore write function (' +\n `${[...CLIENT_WRITES].join(', ')}) from the Firestore SDK, or a call to one through a namespace import, in ` +\n \"the app's client source. Fix: call the callable that owns the write. A sanctioned site is a reviewed entry \" +\n 'with its why; one that no longer writes is stale.',\n scope: APP_SOURCE,\n match: firestoreClientWriteHits,\n allowlist: facts.sanctioned,\n samples: {\n flags: [\n \"import { doc, setDoc } from 'firebase/firestore';\",\n \"import { writeBatch as batchOf } from 'firebase/firestore';\",\n \"import * as fs from 'firebase/firestore';\\nawait fs.updateDoc(ref, patch);\",\n ],\n passes: [\n \"import { doc, getDoc, onSnapshot } from 'firebase/firestore';\",\n \"import { type WriteBatch } from 'firebase/firestore';\",\n 'await callable({ id });',\n ],\n },\n }),\n ];\n },\n};\n"]}
@@ -1,5 +1,5 @@
1
1
  import type { Absent, GenericGuardDefinition } from '../../node/suite/config.js';
2
- import { type FirestoreRuntimeInUiFacts, type LiveSubscriptionFacts } from './client-guards.js';
2
+ import { type FirestoreClientWritesFacts, type FirestoreRuntimeInUiFacts, type LiveSubscriptionFacts } from './client-guards.js';
3
3
  import { type TestPathFacts, type WriteGuardFacts } from './guard.js';
4
4
  import { type CollectionGroupIndexFacts } from './index-guard.js';
5
5
  import { type PathAssemblyFacts, type RetiredSegmentFacts } from './path-guards.js';
@@ -21,6 +21,7 @@ export type FirestoreGuardFacts = {
21
21
  firestoreCounterDecrements: NoFacts | Absent;
22
22
  firestoreLiveSubscriptions: LiveSubscriptionFacts | Absent;
23
23
  firestoreRuntimeInUi: FirestoreRuntimeInUiFacts | Absent;
24
+ firestoreClientWrites: FirestoreClientWritesFacts | Absent;
24
25
  firestoreRandomUuidSites: RandomUuidFacts | Absent;
25
26
  firestoreTimestampNow: NoFacts | Absent;
26
27
  rulesClaimNames: RulesClaimFacts;
@@ -1 +1 @@
1
- {"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../../../src/modules/firestore/guards.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACjF,OAAO,EAGL,KAAK,yBAAyB,EAC9B,KAAK,qBAAqB,EAC3B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAA6B,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AACjG,OAAO,EAA6B,KAAK,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAC7F,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC/E,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAKL,KAAK,eAAe,EACrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAGL,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,EAC9B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,MAAM,mBAAmB,GAAG;IAChC,eAAe,EAAE,eAAe,GAAG,MAAM,CAAC;IAC1C,kBAAkB,EAAE,aAAa,GAAG,MAAM,CAAC;IAC3C,wBAAwB,EAAE,OAAO,GAAG,MAAM,CAAC;IAC3C,qBAAqB,EAAE,iBAAiB,GAAG,MAAM,CAAC;IAClD,wBAAwB,EAAE,mBAAmB,GAAG,MAAM,CAAC;IACvD,+BAA+B,EAAE,yBAAyB,GAAG,MAAM,CAAC;IACpE,oBAAoB,EAAE,wBAAwB,GAAG,MAAM,CAAC;IACxD,qBAAqB,EAAE,0BAA0B,GAAG,MAAM,CAAC;IAC3D,yBAAyB,EAAE,OAAO,GAAG,MAAM,CAAC;IAC5C,0BAA0B,EAAE,OAAO,GAAG,MAAM,CAAC;IAC7C,0BAA0B,EAAE,qBAAqB,GAAG,MAAM,CAAC;IAC3D,oBAAoB,EAAE,yBAAyB,GAAG,MAAM,CAAC;IACzD,wBAAwB,EAAE,eAAe,GAAG,MAAM,CAAC;IACnD,qBAAqB,EAAE,OAAO,GAAG,MAAM,CAAC;IACxC,eAAe,EAAE,eAAe,CAAC;IACjC,eAAe,EAAE,gBAAgB,CAAC;CACnC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,aAAa,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAiBxB,CAAC"}
1
+ {"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../../../src/modules/firestore/guards.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACjF,OAAO,EAIL,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAC9B,KAAK,qBAAqB,EAC3B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAA6B,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AACjG,OAAO,EAA6B,KAAK,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAC7F,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC/E,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAKL,KAAK,eAAe,EACrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAGL,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,EAC9B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,MAAM,mBAAmB,GAAG;IAChC,eAAe,EAAE,eAAe,GAAG,MAAM,CAAC;IAC1C,kBAAkB,EAAE,aAAa,GAAG,MAAM,CAAC;IAC3C,wBAAwB,EAAE,OAAO,GAAG,MAAM,CAAC;IAC3C,qBAAqB,EAAE,iBAAiB,GAAG,MAAM,CAAC;IAClD,wBAAwB,EAAE,mBAAmB,GAAG,MAAM,CAAC;IACvD,+BAA+B,EAAE,yBAAyB,GAAG,MAAM,CAAC;IACpE,oBAAoB,EAAE,wBAAwB,GAAG,MAAM,CAAC;IACxD,qBAAqB,EAAE,0BAA0B,GAAG,MAAM,CAAC;IAC3D,yBAAyB,EAAE,OAAO,GAAG,MAAM,CAAC;IAC5C,0BAA0B,EAAE,OAAO,GAAG,MAAM,CAAC;IAC7C,0BAA0B,EAAE,qBAAqB,GAAG,MAAM,CAAC;IAC3D,oBAAoB,EAAE,yBAAyB,GAAG,MAAM,CAAC;IACzD,qBAAqB,EAAE,0BAA0B,GAAG,MAAM,CAAC;IAC3D,wBAAwB,EAAE,eAAe,GAAG,MAAM,CAAC;IACnD,qBAAqB,EAAE,OAAO,GAAG,MAAM,CAAC;IACxC,eAAe,EAAE,eAAe,CAAC;IACjC,eAAe,EAAE,gBAAgB,CAAC;CACnC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,aAAa,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAkBxB,CAAC"}
@@ -1,4 +1,4 @@
1
- import { firestoreRuntimeInUiGuard, liveSubscriptionGuard, } from './client-guards.js';
1
+ import { firestoreClientWritesGuard, firestoreRuntimeInUiGuard, liveSubscriptionGuard, } from './client-guards.js';
2
2
  import { testPathGuard, writeGuard } from './guard.js';
3
3
  import { collectionGroupIndexGuard } from './index-guard.js';
4
4
  import { literalSegmentGuard, pathAssemblyGuard, retiredSegmentGuard, } from './path-guards.js';
@@ -19,6 +19,7 @@ export const FIRESTORE_GUARDS = Object.freeze([
19
19
  counterDecrementGuard,
20
20
  liveSubscriptionGuard,
21
21
  firestoreRuntimeInUiGuard,
22
+ firestoreClientWritesGuard,
22
23
  randomUuidGuard,
23
24
  timestampNowGuard,
24
25
  rulesClaimGuard,
@@ -1 +1 @@
1
- {"version":3,"file":"guards.js","sourceRoot":"","sources":["../../../src/modules/firestore/guards.ts"],"names":[],"mappings":"AACA,OAAO,EACL,yBAAyB,EACzB,qBAAqB,GAGtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,UAAU,EAA4C,MAAM,YAAY,CAAC;AACjG,OAAO,EAAE,yBAAyB,EAAkC,MAAM,kBAAkB,CAAC;AAC7F,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,GAGpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAwB,MAAM,wBAAwB,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAyB,MAAM,yBAAyB,CAAC;AAClF,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,iBAAiB,EACjB,oBAAoB,GAErB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,GAGzB,MAAM,qBAAqB,CAAC;AAsB7B,MAAM,CAAC,MAAM,gBAAgB,GAAiD,MAAM,CAAC,MAAM,CAAC;IAC1F,UAAU;IACV,aAAa;IACb,mBAAmB;IACnB,iBAAiB;IACjB,mBAAmB;IACnB,yBAAyB;IACzB,wBAAwB;IACxB,0BAA0B;IAC1B,oBAAoB;IACpB,qBAAqB;IACrB,qBAAqB;IACrB,yBAAyB;IACzB,eAAe;IACf,iBAAiB;IACjB,eAAe;IACf,gBAAgB;CAC+B,CAAC,CAAC","sourcesContent":["import type { Absent, GenericGuardDefinition } from '../../node/suite/config.js';\nimport {\n firestoreRuntimeInUiGuard,\n liveSubscriptionGuard,\n type FirestoreRuntimeInUiFacts,\n type LiveSubscriptionFacts,\n} from './client-guards.js';\nimport { testPathGuard, writeGuard, type TestPathFacts, type WriteGuardFacts } from './guard.js';\nimport { collectionGroupIndexGuard, type CollectionGroupIndexFacts } from './index-guard.js';\nimport {\n literalSegmentGuard,\n pathAssemblyGuard,\n retiredSegmentGuard,\n type PathAssemblyFacts,\n type RetiredSegmentFacts,\n} from './path-guards.js';\nimport { rulesClaimGuard, type RulesClaimFacts } from './rules-claim-guard.js';\nimport { rulesMirrorGuard, type RulesMirrorFacts } from './rules-mirror-guard.js';\nimport {\n counterDecrementGuard,\n randomUuidGuard,\n timestampNowGuard,\n transactionReadGuard,\n type RandomUuidFacts,\n} from './server-guards.js';\nimport {\n storageObjectMetadataGuard,\n storageUploadOriginGuard,\n type StorageObjectMetadataFacts,\n type StorageUploadOriginFacts,\n} from './storage-guards.js';\nimport type { NoFacts } from './support.js';\n\nexport type FirestoreGuardFacts = {\n firestoreWrites: WriteGuardFacts | Absent;\n firestoreTestPaths: TestPathFacts | Absent;\n firestoreLiteralSegments: NoFacts | Absent;\n firestorePathAssembly: PathAssemblyFacts | Absent;\n firestoreRetiredSegments: RetiredSegmentFacts | Absent;\n firestoreCollectionGroupIndexes: CollectionGroupIndexFacts | Absent;\n storageUploadOrigins: StorageUploadOriginFacts | Absent;\n storageObjectMetadata: StorageObjectMetadataFacts | Absent;\n firestoreTransactionReads: NoFacts | Absent;\n firestoreCounterDecrements: NoFacts | Absent;\n firestoreLiveSubscriptions: LiveSubscriptionFacts | Absent;\n firestoreRuntimeInUi: FirestoreRuntimeInUiFacts | Absent;\n firestoreRandomUuidSites: RandomUuidFacts | Absent;\n firestoreTimestampNow: NoFacts | Absent;\n rulesClaimNames: RulesClaimFacts;\n rulesMirrorCore: RulesMirrorFacts;\n};\n\nexport const FIRESTORE_GUARDS: ReadonlyArray<GenericGuardDefinition<never>> = Object.freeze([\n writeGuard,\n testPathGuard,\n literalSegmentGuard,\n pathAssemblyGuard,\n retiredSegmentGuard,\n collectionGroupIndexGuard,\n storageUploadOriginGuard,\n storageObjectMetadataGuard,\n transactionReadGuard,\n counterDecrementGuard,\n liveSubscriptionGuard,\n firestoreRuntimeInUiGuard,\n randomUuidGuard,\n timestampNowGuard,\n rulesClaimGuard,\n rulesMirrorGuard,\n] as ReadonlyArray<GenericGuardDefinition<never>>);\n"]}
1
+ {"version":3,"file":"guards.js","sourceRoot":"","sources":["../../../src/modules/firestore/guards.ts"],"names":[],"mappings":"AACA,OAAO,EACL,0BAA0B,EAC1B,yBAAyB,EACzB,qBAAqB,GAItB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,UAAU,EAA4C,MAAM,YAAY,CAAC;AACjG,OAAO,EAAE,yBAAyB,EAAkC,MAAM,kBAAkB,CAAC;AAC7F,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,GAGpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAwB,MAAM,wBAAwB,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAyB,MAAM,yBAAyB,CAAC;AAClF,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,iBAAiB,EACjB,oBAAoB,GAErB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,GAGzB,MAAM,qBAAqB,CAAC;AAuB7B,MAAM,CAAC,MAAM,gBAAgB,GAAiD,MAAM,CAAC,MAAM,CAAC;IAC1F,UAAU;IACV,aAAa;IACb,mBAAmB;IACnB,iBAAiB;IACjB,mBAAmB;IACnB,yBAAyB;IACzB,wBAAwB;IACxB,0BAA0B;IAC1B,oBAAoB;IACpB,qBAAqB;IACrB,qBAAqB;IACrB,yBAAyB;IACzB,0BAA0B;IAC1B,eAAe;IACf,iBAAiB;IACjB,eAAe;IACf,gBAAgB;CAC+B,CAAC,CAAC","sourcesContent":["import type { Absent, GenericGuardDefinition } from '../../node/suite/config.js';\nimport {\n firestoreClientWritesGuard,\n firestoreRuntimeInUiGuard,\n liveSubscriptionGuard,\n type FirestoreClientWritesFacts,\n type FirestoreRuntimeInUiFacts,\n type LiveSubscriptionFacts,\n} from './client-guards.js';\nimport { testPathGuard, writeGuard, type TestPathFacts, type WriteGuardFacts } from './guard.js';\nimport { collectionGroupIndexGuard, type CollectionGroupIndexFacts } from './index-guard.js';\nimport {\n literalSegmentGuard,\n pathAssemblyGuard,\n retiredSegmentGuard,\n type PathAssemblyFacts,\n type RetiredSegmentFacts,\n} from './path-guards.js';\nimport { rulesClaimGuard, type RulesClaimFacts } from './rules-claim-guard.js';\nimport { rulesMirrorGuard, type RulesMirrorFacts } from './rules-mirror-guard.js';\nimport {\n counterDecrementGuard,\n randomUuidGuard,\n timestampNowGuard,\n transactionReadGuard,\n type RandomUuidFacts,\n} from './server-guards.js';\nimport {\n storageObjectMetadataGuard,\n storageUploadOriginGuard,\n type StorageObjectMetadataFacts,\n type StorageUploadOriginFacts,\n} from './storage-guards.js';\nimport type { NoFacts } from './support.js';\n\nexport type FirestoreGuardFacts = {\n firestoreWrites: WriteGuardFacts | Absent;\n firestoreTestPaths: TestPathFacts | Absent;\n firestoreLiteralSegments: NoFacts | Absent;\n firestorePathAssembly: PathAssemblyFacts | Absent;\n firestoreRetiredSegments: RetiredSegmentFacts | Absent;\n firestoreCollectionGroupIndexes: CollectionGroupIndexFacts | Absent;\n storageUploadOrigins: StorageUploadOriginFacts | Absent;\n storageObjectMetadata: StorageObjectMetadataFacts | Absent;\n firestoreTransactionReads: NoFacts | Absent;\n firestoreCounterDecrements: NoFacts | Absent;\n firestoreLiveSubscriptions: LiveSubscriptionFacts | Absent;\n firestoreRuntimeInUi: FirestoreRuntimeInUiFacts | Absent;\n firestoreClientWrites: FirestoreClientWritesFacts | Absent;\n firestoreRandomUuidSites: RandomUuidFacts | Absent;\n firestoreTimestampNow: NoFacts | Absent;\n rulesClaimNames: RulesClaimFacts;\n rulesMirrorCore: RulesMirrorFacts;\n};\n\nexport const FIRESTORE_GUARDS: ReadonlyArray<GenericGuardDefinition<never>> = Object.freeze([\n writeGuard,\n testPathGuard,\n literalSegmentGuard,\n pathAssemblyGuard,\n retiredSegmentGuard,\n collectionGroupIndexGuard,\n storageUploadOriginGuard,\n storageObjectMetadataGuard,\n transactionReadGuard,\n counterDecrementGuard,\n liveSubscriptionGuard,\n firestoreRuntimeInUiGuard,\n firestoreClientWritesGuard,\n randomUuidGuard,\n timestampNowGuard,\n rulesClaimGuard,\n rulesMirrorGuard,\n] as ReadonlyArray<GenericGuardDefinition<never>>);\n"]}
@@ -15,7 +15,10 @@ export interface ReadStateOwnerFacts {
15
15
  export declare const readStateOwnerGuard: GenericGuardDefinition<ReadStateOwnerFacts>;
16
16
  export interface ReadRetryStateFacts {
17
17
  seat: FailureSeat;
18
+ controlPendingProp: string;
18
19
  }
20
+ export declare function failureBranchLivePending(file: FileView, controlPendingProp: string): Hit[];
21
+ export declare function liveLoadingBeforeFailure(file: FileView): Hit[];
19
22
  export declare function liveFlagRetryStates(file: FileView, seat: FailureSeat): Hit[];
20
23
  export declare function failedAnswersWithoutRetrying(file: FileView): Hit[];
21
24
  export declare function seatRetriesWithoutPending(file: FileView, seat: FailureSeat): Hit[];
@@ -1 +1 @@
1
- {"version":3,"file":"read-failures.d.ts","sourceRoot":"","sources":["../../../src/modules/frontend-reads/read-failures.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"read-failures.d.ts","sourceRoot":"","sources":["../../../src/modules/frontend-reads/read-failures.ts"],"names":[],"mappings":"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"}
@@ -75,13 +75,17 @@ function retryStateExpressions(file, fields) {
75
75
  });
76
76
  return found;
77
77
  }
78
- function readsFetchingFlag(expression, file, seen = new Set()) {
78
+ const FAILURE_NAME = /^(?:isError|error)$/;
79
+ function readsFetchingFlag(expression, file) {
80
+ return readsFlag(expression, file, FETCHING_FLAG);
81
+ }
82
+ function readsFlag(expression, file, flag, seen = new Set()) {
79
83
  let reads = false;
80
84
  const bound = [];
81
85
  forEachNode(expression, (node) => {
82
86
  if (!ts.isIdentifier(node) || reads)
83
87
  return;
84
- if (FETCHING_FLAG.test(node.text))
88
+ if (flag.test(node.text))
85
89
  reads = true;
86
90
  const parent = node.parent;
87
91
  const receiverOrCallee = (ts.isPropertyAccessExpression(parent) &&
@@ -103,7 +107,7 @@ function readsFetchingFlag(expression, file, seen = new Set()) {
103
107
  ts.isIdentifier(node.name) &&
104
108
  node.name.text === name &&
105
109
  node.propertyName &&
106
- FETCHING_FLAG.test(fieldName(node.propertyName) ?? '')) {
110
+ flag.test(fieldName(node.propertyName) ?? '')) {
107
111
  renamed = true;
108
112
  }
109
113
  else if (!declared &&
@@ -122,8 +126,160 @@ function readsFetchingFlag(expression, file, seen = new Set()) {
122
126
  const fromHelper = ts.isCallExpression(value) &&
123
127
  ts.isIdentifier(value.expression) &&
124
128
  RETRY_STATE_HELPERS.includes(value.expression.text);
125
- return !fromHelper && readsFetchingFlag(value, file, seen);
129
+ return !fromHelper && readsFlag(value, file, flag, seen);
130
+ });
131
+ }
132
+ function branchConditionsAbove(node) {
133
+ const conditions = [];
134
+ for (let child = node, parent = node.parent; parent; child = parent, parent = parent.parent) {
135
+ if (ts.isIfStatement(parent) && parent.thenStatement === child)
136
+ conditions.push(parent.expression);
137
+ else if (ts.isConditionalExpression(parent) && parent.whenTrue === child)
138
+ conditions.push(parent.condition);
139
+ else if (ts.isBinaryExpression(parent) &&
140
+ parent.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken &&
141
+ parent.right === child)
142
+ conditions.push(parent.left);
143
+ }
144
+ return conditions;
145
+ }
146
+ export function failureBranchLivePending(file, controlPendingProp) {
147
+ const sf = file.sourceFile;
148
+ const hits = [];
149
+ forEachNode(sf, (node) => {
150
+ if (!ts.isJsxAttribute(node) ||
151
+ fieldName(node.name) !== controlPendingProp ||
152
+ !node.initializer ||
153
+ !ts.isJsxExpression(node.initializer) ||
154
+ !node.initializer.expression)
155
+ return;
156
+ const pending = node.initializer.expression;
157
+ if (!readsFetchingFlag(pending, file))
158
+ return;
159
+ if (!branchConditionsAbove(node).some((c) => readsFlag(c, file, FAILURE_NAME)))
160
+ return;
161
+ hits.push({
162
+ index: node.getStart(sf),
163
+ detail: `a failure's retry pending from a fetching flag: ${pending.getText(sf).replace(/\s+/g, ' ').slice(0, 120)}`,
164
+ });
165
+ });
166
+ return hits;
167
+ }
168
+ const LOADING_FIELD = 'isLoading';
169
+ const READ_FAILURE_FIELDS = new Set(['error', 'isError', 'retryState']);
170
+ const HELD_RECEIVER = /retry/i;
171
+ function scopeOf(node) {
172
+ return enclosingFunctionOf(node) ?? node.getSourceFile();
173
+ }
174
+ function destructuredBindings(sf) {
175
+ const bindings = new Map();
176
+ forEachNode(sf, (node) => {
177
+ if (!ts.isVariableDeclaration(node) ||
178
+ !ts.isObjectBindingPattern(node.name) ||
179
+ !node.initializer ||
180
+ !ts.isIdentifier(node.initializer))
181
+ return;
182
+ const receiver = node.initializer.text;
183
+ const scope = scopeOf(node);
184
+ for (const element of node.name.elements) {
185
+ if (!ts.isIdentifier(element.name))
186
+ continue;
187
+ const field = element.propertyName ? fieldName(element.propertyName) : element.name.text;
188
+ if (!field)
189
+ continue;
190
+ const named = bindings.get(element.name.text) ?? [];
191
+ named.push({ field, receiver, scope });
192
+ bindings.set(element.name.text, named);
193
+ }
194
+ });
195
+ return bindings;
196
+ }
197
+ function declaresParameter(fn, name) {
198
+ let declares = false;
199
+ for (const parameter of fn.parameters)
200
+ forEachNode(parameter.name, (node) => {
201
+ if (ts.isIdentifier(node) && node.text === name)
202
+ declares = true;
203
+ });
204
+ return declares;
205
+ }
206
+ function bindingFor(use, bindings) {
207
+ const named = bindings.get(use.text);
208
+ if (!named)
209
+ return undefined;
210
+ for (let scope = scopeOf(use); scope;) {
211
+ const found = named.find((binding) => binding.scope === scope);
212
+ if (found)
213
+ return found;
214
+ if (ts.isFunctionLike(scope) && declaresParameter(scope, use.text))
215
+ return undefined;
216
+ scope = ts.isSourceFile(scope) ? undefined : scopeOf(scope);
217
+ }
218
+ return undefined;
219
+ }
220
+ function rootIdentifier(node) {
221
+ let current = node;
222
+ while (ts.isPropertyAccessExpression(current) || ts.isNonNullExpression(current))
223
+ current = current.expression;
224
+ return ts.isIdentifier(current) ? current.text : null;
225
+ }
226
+ function readFieldsIn(scope, bindings, wanted) {
227
+ const sf = scope.getSourceFile();
228
+ const found = [];
229
+ forEachNode(scope, (node) => {
230
+ if (ts.isPropertyAccessExpression(node) && wanted(node.name.text)) {
231
+ const receiver = rootIdentifier(node.expression);
232
+ if (receiver && !HELD_RECEIVER.test(node.expression.getText(sf)))
233
+ found.push({ receiver, index: node.getStart(sf) });
234
+ }
235
+ else if (ts.isIdentifier(node) &&
236
+ !(ts.isPropertyAccessExpression(node.parent) && node.parent.name === node)) {
237
+ const bound = bindingFor(node, bindings);
238
+ if (bound && wanted(bound.field) && !HELD_RECEIVER.test(bound.receiver))
239
+ found.push({ receiver: bound.receiver, index: node.getStart(sf) });
240
+ }
241
+ });
242
+ return found;
243
+ }
244
+ function enclosingFunctionOf(node) {
245
+ for (let p = node.parent; p; p = p.parent)
246
+ if (ts.isFunctionLike(p))
247
+ return p;
248
+ return undefined;
249
+ }
250
+ function branchCondition(node) {
251
+ if (ts.isIfStatement(node))
252
+ return node.expression;
253
+ if (ts.isConditionalExpression(node))
254
+ return node.condition;
255
+ if (ts.isBinaryExpression(node) &&
256
+ node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken &&
257
+ ts.isJsxExpression(node.parent))
258
+ return node.left;
259
+ return undefined;
260
+ }
261
+ export function liveLoadingBeforeFailure(file) {
262
+ const sf = file.sourceFile;
263
+ const bindings = destructuredBindings(sf);
264
+ const isLoading = (field) => field === LOADING_FIELD;
265
+ const isFailure = (field) => READ_FAILURE_FIELDS.has(field);
266
+ const hits = [];
267
+ forEachNode(sf, (node) => {
268
+ const condition = branchCondition(node);
269
+ const fn = condition && enclosingFunctionOf(node);
270
+ if (!condition || !fn)
271
+ return;
272
+ const tested = new Set(readFieldsIn(condition, bindings, isFailure).map((r) => r.receiver));
273
+ const end = condition.getEnd();
274
+ const later = readFieldsIn(fn, bindings, isFailure).filter((r) => r.index >= end);
275
+ const loading = readFieldsIn(condition, bindings, isLoading).find((r) => !tested.has(r.receiver) && later.some((f) => f.receiver === r.receiver));
276
+ if (loading)
277
+ hits.push({
278
+ index: loading.index,
279
+ detail: `a live loading flag tested before the read's failure: ${condition.getText(sf).replace(/\s+/g, ' ').slice(0, 120)}`,
280
+ });
126
281
  });
282
+ return hits;
127
283
  }
128
284
  export function liveFlagRetryStates(file, seat) {
129
285
  const code = file.code;
@@ -210,7 +366,11 @@ export function seatRetriesWithoutPending(file, seat) {
210
366
  export const readRetryStateGuard = {
211
367
  id: 'readRetryState',
212
368
  absentWhen: false,
213
- factProblems: (facts) => seatProblems(facts?.seat),
369
+ factProblems(facts) {
370
+ const problems = seatProblems(facts?.seat);
371
+ identifierProblem(facts?.controlPendingProp, 'controlPendingProp', problems);
372
+ return problems;
373
+ },
214
374
  build: (facts) => [
215
375
  {
216
376
  title: "a read's retry state comes from its one owner, never the live fetching flags",
@@ -220,7 +380,9 @@ export const readRetryStateGuard = {
220
380
  `(exposed from the read's hook) and pass its ${RETRY_STATE_FIELD}; a lookup hands out its held ${HELD_ANSWER_FIELD}, and a hook ` +
221
381
  `that answers with a status gives its failed answer the held ${HELD_ANSWER_FIELD} beside the error, never one built from a ` +
222
382
  `fetching flag; and every <${facts.seat.component}> given ${facts.seat.retryProp} also takes ${facts.seat.pendingProp}, so the ` +
223
- 'pressed retry shows it is running.',
383
+ `pressed retry shows it is running. The same live flags decide no failure surface: a control's ${facts.controlPendingProp} ` +
384
+ "inside a failure branch reads the held isRetrying, never a fetching flag, and a branch never tests a read's live isLoading " +
385
+ "ahead of that read's failure — the held retryState decides the failure first, then its isLoading.",
224
386
  run(context) {
225
387
  const findings = [];
226
388
  for (const file of context.files(APP_CODE)) {
@@ -228,6 +390,8 @@ export const readRetryStateGuard = {
228
390
  ...liveFlagRetryStates(file, facts.seat),
229
391
  ...seatRetriesWithoutPending(file, facts.seat),
230
392
  ...failedAnswersWithoutRetrying(file),
393
+ ...failureBranchLivePending(file, facts.controlPendingProp),
394
+ ...liveLoadingBeforeFailure(file),
231
395
  ];
232
396
  for (const hit of hits) {
233
397
  findings.push({
@@ -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}\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\nfunction readsFetchingFlag(\n expression: ts.Node,\n file: FileView,\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 (FETCHING_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 FETCHING_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 && readsFetchingFlag(value, file, seen);\n });\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) => seatProblems(facts?.seat),\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.',\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 ];\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 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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttt-productions/repo-guards",
3
- "version": "0.1.27",
3
+ "version": "0.1.28",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/ttt-productions/ttt-packages.git",