// Per-project count of files containing non-erasable syntax (what downlevel mode has to // down-level): enum, instantiated namespace/module, parameter properties, `import =`, // `export =`. AST-based (TypeScript's parser), not a grep, so decorators-only files and // commented-out keywords don't miscount. // Usage: node scripts/oss-oss-count-nonerasable.mjs import ts from "typescript"; import { projects, ossRoot, walkFiles } from "./oss-corpus.mjs"; import path from "node:path"; import fs from "node:fs"; const SK = ts.SyntaxKind; function hasNonErasable(sf) { const found = new Set(); (function visit(n) { switch (n.kind) { case SK.EnumDeclaration: found.add("enum"); break; case SK.ModuleDeclaration: // Instantiated namespace/module: has a body with real statements (not just a // declare-only ambient module, which is erased like any other declaration). if (n.body && !(n.modifiers?.some((m) => m.kind === SK.DeclareKeyword))) found.add("namespace"); break; case SK.ImportEqualsDeclaration: found.add("import="); break; case SK.ExportAssignment: if (n.isExportEquals) found.add("export="); break; case SK.Parameter: if (n.modifiers?.some((m) => [SK.PublicKeyword, SK.PrivateKeyword, SK.ProtectedKeyword, SK.ReadonlyKeyword].includes(m.kind))) { found.add("param-property"); } break; } ts.forEachChild(n, visit); })(sf); return found; } const rows = []; for (const name of projects()) { const dir = path.join(ossRoot, name); let files = 0, withNonErasable = 0; const kindCounts = {}; for (const f of walkFiles(dir)) { let src; try { src = fs.readFileSync(f, "utf8"); } catch { continue; } files++; const sf = ts.createSourceFile(path.basename(f), src, ts.ScriptTarget.ESNext, false, ts.ScriptKind.TS); const found = hasNonErasable(sf); if (found.size) { withNonErasable++; for (const k of found) kindCounts[k] = (kindCounts[k] ?? 0) + 1; } } rows.push({ name, files, withNonErasable, kindCounts }); console.log(`${name.padEnd(18)} files=${files} non-erasable=${withNonErasable} ${JSON.stringify(kindCounts)}`); } fs.writeFileSync(path.join(import.meta.dirname, "../corpus/oss-nonerasable.json"), JSON.stringify(rows, null, 2) + "\n"); console.log("\nwritten corpus/oss-nonerasable.json");