|
| 1 | +/** |
| 2 | + * Is this file text a HUMAN wrote, or a bundler's output? |
| 3 | + * |
| 4 | + * Both advisory scanners — the base-URL one and the anti-pattern one — exist to teach the |
| 5 | + * author of a file something about the file. A bundle is not authored: nobody can act on a |
| 6 | + * finding in it, the fix belongs in the source it was built from, and naming a generated |
| 7 | + * artifact spends the scanners' whole false-positive budget in one line. |
| 8 | + * |
| 9 | + * The rule is a property of the ARTIFACT, not of a directory name. An estate proved why: |
| 10 | + * its build output is `public/`, which no ignore list would have guessed (the lists cover |
| 11 | + * `dist`, `build`, `.next`, `.output`, `out`), so `meta verify` reported |
| 12 | + * `public/main.js:243 — <EntityFetcherProvider> is mounted with no baseUrl` while |
| 13 | + * `client/src/main.tsx:26` — the source, the file a person edits — passes `baseUrl="/api"` |
| 14 | + * correctly. Adding `public` to a list would have fixed that estate and nobody else. |
| 15 | + * |
| 16 | + * The two scanners keep their own walkers, deliberately (they diverge on eight axes and |
| 17 | + * unifying them needs ~6 options for two callers). What they share is this judgment, so it |
| 18 | + * lives here once rather than being decided twice. |
| 19 | + */ |
| 20 | + |
| 21 | +/** |
| 22 | + * Bundlers emit lines in the thousands-to-hundreds-of-thousands of characters; the estate |
| 23 | + * bundle that produced the false positive has a longest line of 266,226. Authored source |
| 24 | + * does not reach 5,000 — the threshold sits an order of magnitude above the longest line |
| 25 | + * any human writes and an order of magnitude below what minification produces, so it is a |
| 26 | + * wide gap rather than a tuned one. |
| 27 | + * |
| 28 | + * NOT `>= 512KB`, which `anti-patterns.ts` already applies for a different reason (cost): |
| 29 | + * that gate is about how much work a scan does, and a 300KB bundle sails through it while |
| 30 | + * being exactly as unauthored as a 700KB one. |
| 31 | + */ |
| 32 | +const BUNDLED_LINE_LENGTH = 5000; |
| 33 | + |
| 34 | +/** True when `text` looks like build output rather than source someone edits. */ |
| 35 | +export function looksBundled(text: string): boolean { |
| 36 | + // Scan for a long line without splitting the whole file: a 700KB bundle would otherwise |
| 37 | + // allocate an array of it, and this runs per file on every `meta verify` / `meta gen`. |
| 38 | + let lineStart = 0; |
| 39 | + for (let i = 0; i < text.length; i++) { |
| 40 | + if (text.charCodeAt(i) !== 10 /* \n */) continue; |
| 41 | + if (i - lineStart >= BUNDLED_LINE_LENGTH) return true; |
| 42 | + lineStart = i + 1; |
| 43 | + } |
| 44 | + return text.length - lineStart >= BUNDLED_LINE_LENGTH; |
| 45 | +} |
0 commit comments