diff --git a/.changeset/substrate-tiers-1-6.md b/.changeset/substrate-tiers-1-6.md new file mode 100644 index 00000000..46180c66 --- /dev/null +++ b/.changeset/substrate-tiers-1-6.md @@ -0,0 +1,34 @@ +--- +"@stainless-code/codemap": minor +--- + +Substrate tiers 1–6 remainder (excludes C.9 / `files.is_entry`). **Schema bump** `SCHEMA_VERSION` 27 → **34** — first run after upgrade auto-rebuilds `.codemap/index.db` via the existing version-mismatch path. + +**Tier 1 — call + import precision** + +- `calls.{args_count,is_method_call,is_constructor_call,is_optional_chain}`; constructor vs call dedup key fix +- `symbols.{return_type,is_async,is_generator}` +- Side-effect `import_specifiers` rows (`kind='side-effect'`) + `import_id` FK to `imports` + +**Tier 2 — bindings** + +- `bindings.resolution_kind='re-exported'` when resolution walks a re-export chain + +**Tier 3 — JSX** + +- New tables `jsx_elements` / `jsx_attributes`; extractor with per-file parent linking post-pass + +**Tier 5 — behavioral** + +- New tables `async_calls`, `try_catch`, `decorators`, `jsdoc_tags`; context stack for `in_loop` / `in_try` + +**Tier 6 — module graph (no entry points)** + +- `dynamic_imports` table + extractor +- Post-pass `files.is_barrel` and parse-time `files.has_side_effects` + +**Recipes + goldens:** `find-call-sites` (extended), `find-async-functions`, `find-dynamic-imports`, `find-barrel-files`, `find-side-effect-files`, `find-re-exported-bindings`, `find-side-effect-imports`, `find-jsx-usages`, `find-await-in-loop`, `find-swallowed-errors`, `find-decorator-usage`, `find-throws-jsdoc`. + +**Out of scope:** C.9 plugin layer (`files.is_entry`, reachability-from-entry); tiers 7–13. + +**Migration:** No in-place DDL — rebuild on schema mismatch preserves user-data tables (`coverage`, `query_baselines`, `recipe_recency`). Re-run `codemap --full` (or any index) after upgrade. diff --git a/bun.lock b/bun.lock index a1582e7b..9c95a4d4 100644 --- a/bun.lock +++ b/bun.lock @@ -10,23 +10,23 @@ "better-sqlite3": "^12.10.0", "chokidar": "^5.0.0", "lightningcss": "^1.32.0", - "oxc-parser": "^0.130.0", + "oxc-parser": "^0.132.0", "oxc-resolver": "^11.19.1", "package-manager-detector": "^1.6.0", "tinyglobby": "^0.2.16", - "zod": "^4.3.6", + "zod": "^4.4.3", }, "devDependencies": { "@changesets/changelog-github": "^0.7.0", "@changesets/cli": "^2.31.0", "@types/better-sqlite3": "^7.6.13", "@types/bun": "^1.3.14", - "@types/node": "^25.8.0", - "@typescript/native-preview": "^7.0.0-dev.20260515.1", + "@types/node": "^25.9.1", + "@typescript/native-preview": "^7.0.0-dev.20260519.1", "husky": "^9.1.7", - "lint-staged": "^17.0.4", - "oxfmt": "^0.49.0", - "oxlint": "^1.64.0", + "lint-staged": "^17.0.5", + "oxfmt": "^0.51.0", + "oxlint": "^1.66.0", "tsdown": "^0.22.0", "typescript": "^6.0.3", "unrun": "^0.3.0", @@ -34,7 +34,7 @@ }, }, "overrides": { - "zod": "^4.3.6", + "zod": "^4.4.3", }, "packages": { "@babel/generator": ["@babel/generator@8.0.0-rc.4", "", { "dependencies": { "@babel/parser": "^8.0.0-rc.4", "@babel/types": "^8.0.0-rc.4", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "@types/jsesc": "^2.5.0", "jsesc": "^3.0.2" } }, "sha512-YZ+FuIgkj7KrIb2a2X1XiY0QYgDxAbVbYP64SjwJzOK3euCsUerzenh2oqdsmKuPSlhzmFOOklnxzHAzXagvpw=="], @@ -123,47 +123,47 @@ "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], - "@oxc-parser/binding-android-arm-eabi": ["@oxc-parser/binding-android-arm-eabi@0.130.0", "", { "os": "android", "cpu": "arm" }, "sha512-h/xYU8/7ADWzVSf5I+YalLpj33LOy9CI/zgbJNIZ5eunRBG+Czqa3lZsvuPHHf3rOt6z1c5+UzoxjbAzAvhwVw=="], + "@oxc-parser/binding-android-arm-eabi": ["@oxc-parser/binding-android-arm-eabi@0.132.0", "", { "os": "android", "cpu": "arm" }, "sha512-KrLaPWa5c9Y7LkW+rKkaUE3y7DBDrQtaf7rlsSDfv6KAHUjgzAIRA761Lrrp6//Yd/Rlie/yEOt9YENCoJnOcw=="], - "@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.130.0", "", { "os": "android", "cpu": "arm64" }, "sha512-oFWFJrsGv9siFM4HjMqKNB7IuIZD/SMmZdCXl8xyx7lDplGvPKyewpOo272rSWgMXe2Wx7bWI0Yj+gkHv4qbeg=="], + "@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.132.0", "", { "os": "android", "cpu": "arm64" }, "sha512-SThDrSeamB/kG2+NxcJ5/wSLcV6dUqDknrPLqFYQ0ST/55mtBP4M7Q/f3QbubH6aAd11wpzZn/nwbVRSdobOpg=="], - "@oxc-parser/binding-darwin-arm64": ["@oxc-parser/binding-darwin-arm64@0.130.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-sGUzupdTplK9jQg7eJZ878HfEgQjJNBc6dAYVWJ9W5aU+J8rLfRJhTVsKThiu1pNwm6Y1qKCcbC6WhNWSXR3Ig=="], + "@oxc-parser/binding-darwin-arm64": ["@oxc-parser/binding-darwin-arm64@0.132.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Lc0f/TYoKBghE5/2Gsv7bLXk+TJZunx2Tf61X8hG4ARXdc8UYI26dCGccFSd1AyFbK3jfaNXtMnupggDbjPXdQ=="], - "@oxc-parser/binding-darwin-x64": ["@oxc-parser/binding-darwin-x64@0.130.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-PsB4cdCISbC00Uy8eiD8bc2AkGWjZqrSrJnkBFuG2ptrrf6mZ2F5gLFSjOAVMMgZPg8B1D7OydJwLWSfyI2Plg=="], + "@oxc-parser/binding-darwin-x64": ["@oxc-parser/binding-darwin-x64@0.132.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-RG2eJIpf7C21z9HSSXFw1bTArdpKe7Y4fwcJTwRq1yCSe1vSavaN9GA1sm9KqzemTLAGVktQ+7qBTGp0vQeUZg=="], - "@oxc-parser/binding-freebsd-x64": ["@oxc-parser/binding-freebsd-x64@0.130.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-DgABp3l38hS77JbXCV4qk1+n6DPym5u8zzwuweokezm2tX194nDSJDENbDRECxVsiNbprKATLbk+Z5wlHT0OHw=="], + "@oxc-parser/binding-freebsd-x64": ["@oxc-parser/binding-freebsd-x64@0.132.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-wQIPntPLtJ8NcBpvKPbEv3NqzV6k8eP8tP/jE9Rg8HTg/j7urZGFSsTCPCW5k77Qfw2DM4vRvc9p3I4yq/Shvw=="], - "@oxc-parser/binding-linux-arm-gnueabihf": ["@oxc-parser/binding-linux-arm-gnueabihf@0.130.0", "", { "os": "linux", "cpu": "arm" }, "sha512-4Kn3CTEmwFrzhTSC/JuUW16qovmaMdX7jeSKbL8w0pLtLww7To1a2XJi9Z5uD8QWUkfUHhqfV+VD6dVzBnWzoA=="], + "@oxc-parser/binding-linux-arm-gnueabihf": ["@oxc-parser/binding-linux-arm-gnueabihf@0.132.0", "", { "os": "linux", "cpu": "arm" }, "sha512-PixKEpeSe3yxQWqNyOCBALRYc72+Tj7ILDofUl3iXo25cVOzLA6jHUhmOINRtWIPh7dbUie3QNeabwaQpZTw6w=="], - "@oxc-parser/binding-linux-arm-musleabihf": ["@oxc-parser/binding-linux-arm-musleabihf@0.130.0", "", { "os": "linux", "cpu": "arm" }, "sha512-D35KZM3F4rRu1uAFKyBlg3Gaf/ybCjyaPR1hfgvk5ex8NtcTmRgc0JgSighEyNg96TPrFhemFba68SZuxaha8w=="], + "@oxc-parser/binding-linux-arm-musleabihf": ["@oxc-parser/binding-linux-arm-musleabihf@0.132.0", "", { "os": "linux", "cpu": "arm" }, "sha512-sCR+DzGHlyHKnbA2z9zWjTUhIo8Sy0enJl4RDsBwPmkxYynPatpwOAWe8W5127SlW0boqUWHGtr1NWn5UwIhXQ=="], - "@oxc-parser/binding-linux-arm64-gnu": ["@oxc-parser/binding-linux-arm64-gnu@0.130.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Q9o7oVlo955KHwS8l1u0bCzIx+JsZUA3XToLXC+MsMhye/9LeBQbt84nh120cl2XLy+TEzvugYDiHShg5yaX6Q=="], + "@oxc-parser/binding-linux-arm64-gnu": ["@oxc-parser/binding-linux-arm64-gnu@0.132.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-sQBix5P2cW+IpzTcCwYxnh9yALrKSIkKJThspBvMGcygSMnbzkSvhN7SfuX1hvBk8y1XEChsdkU3ET0V5DmzUw=="], - "@oxc-parser/binding-linux-arm64-musl": ["@oxc-parser/binding-linux-arm64-musl@0.130.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-EiJ/gC0ljbcwVpycC8YWw6ggMbtsPX8XMOt0mPx0aqWeMsNR+L9m05Flbvd5T+GlivG+GkSWQL7tM9SRFpM/dw=="], + "@oxc-parser/binding-linux-arm64-musl": ["@oxc-parser/binding-linux-arm64-musl@0.132.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-WozHg3Kc//8Sk756HXXgMbEAvqtG+Lzb9JOojwQzIGDtN78Az2dLttkb71akWYUF/8IgYfDSlfKh4Uot8is5Vw=="], - "@oxc-parser/binding-linux-ppc64-gnu": ["@oxc-parser/binding-linux-ppc64-gnu@0.130.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-b+h/lsLLurp756dMGizNs5uPaJfyEdWrTcV5t8M609jWm1DEHB1StpRXCkyvwtkJx3m+qL5BNQ0dEKan/4yGFA=="], + "@oxc-parser/binding-linux-ppc64-gnu": ["@oxc-parser/binding-linux-ppc64-gnu@0.132.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-CmX/ulNBOEwWTyVRmcpYKAcAizW6+OjtLJgo7fXoL9OqQvjF4VER8tPomv44vwzfSCy1BHbsB0ZlZYzYJNj4cA=="], - "@oxc-parser/binding-linux-riscv64-gnu": ["@oxc-parser/binding-linux-riscv64-gnu@0.130.0", "", { "os": "linux", "cpu": "none" }, "sha512-O19Cil83XAyjEFfo8WhkMwY58ALqZ7ckjGL+25mjMIuF84urWBeANH0FC8B8BsSSygWU3/1aY3ADdDbp+wlBnw=="], + "@oxc-parser/binding-linux-riscv64-gnu": ["@oxc-parser/binding-linux-riscv64-gnu@0.132.0", "", { "os": "linux", "cpu": "none" }, "sha512-j9oQS+hM90SdhviNGWbPgT4+Rlq+ac++q/zjgwPD1mVHgxHzATvoRGtDx0sXGmFOQ9J9YkwAhYGb5MAHL6TAsA=="], - "@oxc-parser/binding-linux-riscv64-musl": ["@oxc-parser/binding-linux-riscv64-musl@0.130.0", "", { "os": "linux", "cpu": "none" }, "sha512-BgXRVC0+83n3YzCscLQjj6nbyeBIVeZYPTI4fFMAE4WNm2+4RXhWp03IVizL7esIz36kgmT48aebk1iM+cs8sw=="], + "@oxc-parser/binding-linux-riscv64-musl": ["@oxc-parser/binding-linux-riscv64-musl@0.132.0", "", { "os": "linux", "cpu": "none" }, "sha512-bLz+Xi+Agnfmd7kWPEsSVwCn2k4EyIalZkNBcQ0OGIv9rqn8VgCPLNd03tM9mKX/5TdlvDXalz0q71BIrOPNqg=="], - "@oxc-parser/binding-linux-s390x-gnu": ["@oxc-parser/binding-linux-s390x-gnu@0.130.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-6tJz0xvnGhsokE7N1WlUSBXibpYmT9xSJFS1Ce41Km/+8gQvdlW8MLhRv8PD0L7ix8vRG0FDDepp3jdOFzdVdw=="], + "@oxc-parser/binding-linux-s390x-gnu": ["@oxc-parser/binding-linux-s390x-gnu@0.132.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-U6t2qbJU0ypTfyj9QV3W1Y6mITDTL8ai/OR6NUn85vyHthOvobKWgXzU4tu0EskSzlpuVFz1g0jFGulDIUKHxQ=="], - "@oxc-parser/binding-linux-x64-gnu": ["@oxc-parser/binding-linux-x64-gnu@0.130.0", "", { "os": "linux", "cpu": "x64" }, "sha512-9aCWj83dp3heTQGmGnZGdIWgxjZrr/7VQ0TGFHH5PKByxJKF2Hcr4qvaSUHhhGEa3MSsDjTL1YDP8RAgdL5/Cg=="], + "@oxc-parser/binding-linux-x64-gnu": ["@oxc-parser/binding-linux-x64-gnu@0.132.0", "", { "os": "linux", "cpu": "x64" }, "sha512-WcEaSNHFk8yz5YFlQQAlhq6jOFmZBB/RKE7uzhyCIf+pF1Lmv9gUH4221mle2Gd9iHyWT3ySNph8yZgb1xYdWg=="], - "@oxc-parser/binding-linux-x64-musl": ["@oxc-parser/binding-linux-x64-musl@0.130.0", "", { "os": "linux", "cpu": "x64" }, "sha512-afXt87aZBqrUVli8TB/I8H1G50RDWcwirjWtXGXYqJ2ZqWEiErH7V72j3LUSDZaivmtu2OLX0KQ/mbhP81mr7A=="], + "@oxc-parser/binding-linux-x64-musl": ["@oxc-parser/binding-linux-x64-musl@0.132.0", "", { "os": "linux", "cpu": "x64" }, "sha512-iQrV4iJzQgRwK3BWRmQl1C3C6g3wYpXN2WLdQdyR+efoUnncdShZAVp9OgcojtlD3MDRbuOMGG3SjxF4fL4nlQ=="], - "@oxc-parser/binding-openharmony-arm64": ["@oxc-parser/binding-openharmony-arm64@0.130.0", "", { "os": "none", "cpu": "arm64" }, "sha512-I0NCrZV/YZuCGWgqwNN/GO/iXlLF2z+Wgc7u+Aa9N4P51oYeIa0XT+zVBUne4csO9GqxskXgI4g8JzzWGRpfOw=="], + "@oxc-parser/binding-openharmony-arm64": ["@oxc-parser/binding-openharmony-arm64@0.132.0", "", { "os": "none", "cpu": "arm64" }, "sha512-FWzmUGrZ6GUby4U7WIwcCtab6tdmlTO3xTRRKyb5kjIJVEiaUAT8animUG/nK8ZCA8gkRkPOTId4rl6uTqUmJQ=="], - "@oxc-parser/binding-wasm32-wasi": ["@oxc-parser/binding-wasm32-wasi@0.130.0", "", { "dependencies": { "@emnapi/core": "1.10.0", "@emnapi/runtime": "1.10.0", "@napi-rs/wasm-runtime": "^1.1.4" }, "cpu": "none" }, "sha512-sJgQkGaBX0WJvPUDfwciex6IcTk5O5NLQ1bhEb6f3nBruh1GshKMRSMt2bxZlYrgBzjyBbJzsnO+InPG0bg+fA=="], + "@oxc-parser/binding-wasm32-wasi": ["@oxc-parser/binding-wasm32-wasi@0.132.0", "", { "dependencies": { "@emnapi/core": "1.10.0", "@emnapi/runtime": "1.10.0", "@napi-rs/wasm-runtime": "^1.1.4" }, "cpu": "none" }, "sha512-TlbMppxJI5CjWDes0QaP6G3aneVg1yikBu5QYI+DUShF9WDL66ccgKFNNGmi/Wybtszw6hxwAvv76T4DaPKnHw=="], - "@oxc-parser/binding-win32-arm64-msvc": ["@oxc-parser/binding-win32-arm64-msvc@0.130.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-bjcma99sQrNh6RY4mPO9yTkfxql6TDFoN3HWdK31RCKXwNhcDgJXW/l8PUtzKNiQ+9vpKJfJtQq+LklBuxSOBA=="], + "@oxc-parser/binding-win32-arm64-msvc": ["@oxc-parser/binding-win32-arm64-msvc@0.132.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-RH/NbFjGKqdUAUi7Oh3LQPxUk2hsWFEEQ38HSnbRQT8QjBZFKqL1fMbmsB3N4jy/KPh9iX94+9dmkEMBBbambw=="], - "@oxc-parser/binding-win32-ia32-msvc": ["@oxc-parser/binding-win32-ia32-msvc@0.130.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-hRYbv6HhpSTzT4xTiIkadLI7upLQxuOdLPR/9nL1fTjwhgutBTPXrwaAPb/jTFVx6/8C7Jb5HcUKhmNwloTbFA=="], + "@oxc-parser/binding-win32-ia32-msvc": ["@oxc-parser/binding-win32-ia32-msvc@0.132.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-JUr4jQY9jxoIB/YTLXr6XofSi5xikj6p5/Ns1h0VOBDT0j1jKU+kMsv2xxv51RwnETcXpA1Yw/9oUAfcqfaqEA=="], - "@oxc-parser/binding-win32-x64-msvc": ["@oxc-parser/binding-win32-x64-msvc@0.130.0", "", { "os": "win32", "cpu": "x64" }, "sha512-RBpA9TsRucJq6HNVNCFF1iKg+QeTkLdZf7hi4xaOGCPvMZWvDHjQgSOEZMUpuW4JNciHbxNhLEYmz5CVygjVGQ=="], + "@oxc-parser/binding-win32-x64-msvc": ["@oxc-parser/binding-win32-x64-msvc@0.132.0", "", { "os": "win32", "cpu": "x64" }, "sha512-2dapgHpA5X8DSXF4AU36hJWYf6zP0tKjMXFRAZFBD62pkevW/uhFDXoFH9Y/3Fd2EtDrw5ByNnR1wVE9X9y0SQ=="], - "@oxc-project/types": ["@oxc-project/types@0.130.0", "", {}, "sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q=="], + "@oxc-project/types": ["@oxc-project/types@0.132.0", "", {}, "sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ=="], "@oxc-resolver/binding-android-arm-eabi": ["@oxc-resolver/binding-android-arm-eabi@11.19.1", "", { "os": "android", "cpu": "arm" }, "sha512-aUs47y+xyXHUKlbhqHUjBABjvycq6YSD7bpxSW7vplUmdzAlJ93yXY6ZR0c1o1x5A/QKbENCvs3+NlY8IpIVzg=="], @@ -205,81 +205,81 @@ "@oxc-resolver/binding-win32-x64-msvc": ["@oxc-resolver/binding-win32-x64-msvc@11.19.1", "", { "os": "win32", "cpu": "x64" }, "sha512-6hIU3RQu45B+VNTY4Ru8ppFwjVS/S5qwYyGhBotmjxfEKk41I2DlGtRfGJndZ5+6lneE2pwloqunlOyZuX/XAw=="], - "@oxfmt/binding-android-arm-eabi": ["@oxfmt/binding-android-arm-eabi@0.49.0", "", { "os": "android", "cpu": "arm" }, "sha512-HbifJ84prIh9+55CTPAU35JdRQrwg47y16cGerCC+iejSKOuHXYo2WDql6l7cQlzrYVtc3f4UWY+dBj2lRmOeA=="], + "@oxfmt/binding-android-arm-eabi": ["@oxfmt/binding-android-arm-eabi@0.51.0", "", { "os": "android", "cpu": "arm" }, "sha512-Ni0sCqg5CIHaLIYFGj+ncbcumylvNC6FE4rfD0KfdmnWHbPJ+zev0qZCXKxy2hFVa0fYRK0yPzf5nzPbkZou7g=="], - "@oxfmt/binding-android-arm64": ["@oxfmt/binding-android-arm64@0.49.0", "", { "os": "android", "cpu": "arm64" }, "sha512-Ef7SKJqAaH2d7E6eXZZa2OffIShbhFMxnGK0zd93p4qiyTJr75B0qf7lrPD+qQOwcf04BrjYJ0JUxq8d5+yZwg=="], + "@oxfmt/binding-android-arm64": ["@oxfmt/binding-android-arm64@0.51.0", "", { "os": "android", "cpu": "arm64" }, "sha512-eu5lAZjuo0KAkp+M24EhDqfOwA8owQ8d7wyBlOUUGRbDLHpU3IRlDHp8Dif+YqGlxs6jra7yS6WQu/NkPhAxeg=="], - "@oxfmt/binding-darwin-arm64": ["@oxfmt/binding-darwin-arm64@0.49.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-8x5DN9CsFfb432sHa9NyqX5XisGUdA53LPEGSdv/VniS+v4uEOR8Orv7A9QSB98Xxgp0t6r31DzQA/wpIobGqQ=="], + "@oxfmt/binding-darwin-arm64": ["@oxfmt/binding-darwin-arm64@0.51.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-6LsUNIdURhhcIfIn8+xsOb61mSTa9msAHTeSGx9Jf4rsP/gN8PGCF+SKWPAQZbND2w/WBkqQ6303jqEEIXzMdQ=="], - "@oxfmt/binding-darwin-x64": ["@oxfmt/binding-darwin-x64@0.49.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-e0+DSVzk4ewhMVKNYDaRTmP81jNMBWR1X9al0cVKWS+hDM/dElNqD5zjTOCuLOZc4oOdp2Gx2ldrVL+yYo9TZQ=="], + "@oxfmt/binding-darwin-x64": ["@oxfmt/binding-darwin-x64@0.51.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-9aUMGmVxdHjYMsEAW1tNRoieTJXlVNDFkRvIR1J7LttJXWjVYCu2ekclLij2KJtxBxSQOYSHd12ME/adVGVbZg=="], - "@oxfmt/binding-freebsd-x64": ["@oxfmt/binding-freebsd-x64@0.49.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-W+mjtYtrQvFbXT/uNT+221OBhGRZ8UqNsLxjTWsjZ4GsQnRdvRC/N2NCK86BcamWr7lsTxwpwN3PULnr78sgcQ=="], + "@oxfmt/binding-freebsd-x64": ["@oxfmt/binding-freebsd-x64@0.51.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-mkY1nhZTqYb+NHaAWxOCKISN6FwdrwMNsu17vTUA3wzUV2VJ+Paq15ZokRcsMU/2PUdHO73prxyeJpjXQ3MPpQ=="], - "@oxfmt/binding-linux-arm-gnueabihf": ["@oxfmt/binding-linux-arm-gnueabihf@0.49.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Rtv6UevV7czDlLqil+NZUe4d8gs8jQo/zScSpumwyf7I+fSdLc+hc8AF3MQC7ymxSMMD9+vfiqQlsIf7wOAzXA=="], + "@oxfmt/binding-linux-arm-gnueabihf": ["@oxfmt/binding-linux-arm-gnueabihf@0.51.0", "", { "os": "linux", "cpu": "arm" }, "sha512-wtFwNwE4+YCNuPaWoGDZeGsKvD6D1YSUNBJNn/rJBh7CrDBThFE+TBI5kY7vRW9rIOQRsbW2IpyyL3Du4Zqwiw=="], - "@oxfmt/binding-linux-arm-musleabihf": ["@oxfmt/binding-linux-arm-musleabihf@0.49.0", "", { "os": "linux", "cpu": "arm" }, "sha512-sBi+8C/Q/MdKa5FL8ibAUCdhFBGFH7HFN/Qoyd5xQbZ/0ky3NMPpKfIBpaH0lhK2dXkGLczVQUoZ+xuNSerCdQ=="], + "@oxfmt/binding-linux-arm-musleabihf": ["@oxfmt/binding-linux-arm-musleabihf@0.51.0", "", { "os": "linux", "cpu": "arm" }, "sha512-rnOaNx86G7iRKM6lsCIQMux0SMGNC/TEbFR+r7lpruJ12bnrIWgxd5w1PLqOvgR9r8ZJbpK/zfRKctJnh8/Jfg=="], - "@oxfmt/binding-linux-arm64-gnu": ["@oxfmt/binding-linux-arm64-gnu@0.49.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-JIfWenFhlzx+O8YygyZhoHFzTsdgDhxhbDRnE2iJLnnM5pWKScFvPECO2vOlA7JqJ/9S1g3uzEKuRCkHFwTjvA=="], + "@oxfmt/binding-linux-arm64-gnu": ["@oxfmt/binding-linux-arm64-gnu@0.51.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-jOgDzSqWcICGRjsp4mc08FxKMN8vzP2Kgs4E0d2HUP99F+nJDQKklRV4Zuj+0gcBgjrzx2CbpqaIdUVPepCojA=="], - "@oxfmt/binding-linux-arm64-musl": ["@oxfmt/binding-linux-arm64-musl@0.49.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-iNzkMPG18jPkwBOZ4/HEjwqfzAjq4RrUQ0CgId/fC1ENvYD5jLVAaU/gWgpiqP1ys07kxSsSggDd1fp3E7mQHw=="], + "@oxfmt/binding-linux-arm64-musl": ["@oxfmt/binding-linux-arm64-musl@0.51.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-KBUCdrH5bwVrAvI9gU/1S55oH6fzXjr++J/oVocdu7bYTks1l7DNNT+rLd/1TDdAEjObGwmfWamn7LC1m8A0DQ=="], - "@oxfmt/binding-linux-ppc64-gnu": ["@oxfmt/binding-linux-ppc64-gnu@0.49.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-BPHA/NN3LvoIXiid+iz3BHt5V0Rzx0tXAqRUovwE1NsbDaLG9e8mtv7evDGRIkVQacqTDBv0XL25THHsxSJosQ=="], + "@oxfmt/binding-linux-ppc64-gnu": ["@oxfmt/binding-linux-ppc64-gnu@0.51.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NapfjYsABFqTJ1Dn9Efq6sN5esaHconVKwVLbDGNQLrwpOx/g17mkwErHzU72PutL67nf3wNAkbq122H+zLxag=="], - "@oxfmt/binding-linux-riscv64-gnu": ["@oxfmt/binding-linux-riscv64-gnu@0.49.0", "", { "os": "linux", "cpu": "none" }, "sha512-3Eroshe+s69htC9JIL0+zLGQczLtRKezkMhwqQC21VC5Z/fuLvzLfbAOLgJLUq601H8gDYjy7deYycfOBjCvWg=="], + "@oxfmt/binding-linux-riscv64-gnu": ["@oxfmt/binding-linux-riscv64-gnu@0.51.0", "", { "os": "linux", "cpu": "none" }, "sha512-5dlDt1dUZCVi6elIhiK1PWg9wpTzTcIuj0IZnSurvIoMrhOWqqTcc1dSTxcSkNaBZhfsNqRZdINI1zAgbKkJNQ=="], - "@oxfmt/binding-linux-riscv64-musl": ["@oxfmt/binding-linux-riscv64-musl@0.49.0", "", { "os": "linux", "cpu": "none" }, "sha512-fnaERGgsxGm0lKAmO72EYR4BA3qBnzBTJBTi6EtUMq1D4R7EexRBMU4voXnx4TXla3SEDl9x4uNp/18SbkPjGg=="], + "@oxfmt/binding-linux-riscv64-musl": ["@oxfmt/binding-linux-riscv64-musl@0.51.0", "", { "os": "linux", "cpu": "none" }, "sha512-pgdWUJn0S5nulyiVdlFV8DzCUnGXkU99W5PSkkmbaZW+LrZBPxpezun4G0DDHbQaVYuJeCuKsXsGKGo77CkUTQ=="], - "@oxfmt/binding-linux-s390x-gnu": ["@oxfmt/binding-linux-s390x-gnu@0.49.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-rBwasMl1Uul1MCCeTGEFKnOTL7VUxHf+634jWStrQAbzpBJgd5Yz5m4F7exVCsoI8PHn57dNjssXagXLCLB5yA=="], + "@oxfmt/binding-linux-s390x-gnu": ["@oxfmt/binding-linux-s390x-gnu@0.51.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-2XTFUe97CbDGAI8vjwDfZ1HdakO0XIADyJ24idEg64SC4/K4in/OisXVnrW4NMK7I6TgC7EqRhC0Ln/nKhAemA=="], - "@oxfmt/binding-linux-x64-gnu": ["@oxfmt/binding-linux-x64-gnu@0.49.0", "", { "os": "linux", "cpu": "x64" }, "sha512-BoC/F9xHe2y/deuBGA5Aw7bes07OD2gcL2wlpzTrfImR92vPP7S/k3LBTyspQZCNIVNdagkELcqKELwMLGIfAg=="], + "@oxfmt/binding-linux-x64-gnu": ["@oxfmt/binding-linux-x64-gnu@0.51.0", "", { "os": "linux", "cpu": "x64" }, "sha512-kQ1OuCqqt/yyf0ZN9VFxW1/JnlgJgii3Dr7pWf9vNBvrX1hv6g39/+mc5oGRHRGJFZtl3zsGDWR9c5N2B/gwBw=="], - "@oxfmt/binding-linux-x64-musl": ["@oxfmt/binding-linux-x64-musl@0.49.0", "", { "os": "linux", "cpu": "x64" }, "sha512-umY6jFADAo/oztFKl8D/S6vSrG6oBpEskcentiRuz42kZVU2kfDXMWCYavxyZR2bwPjqkHpcHZ6EZFiH3Qj9ZA=="], + "@oxfmt/binding-linux-x64-musl": ["@oxfmt/binding-linux-x64-musl@0.51.0", "", { "os": "linux", "cpu": "x64" }, "sha512-ARTYqxHF475o96Gbn41hvSWSSRygPlRDXZZgZ9I2scU1y0qiWpCQyZCoefaQa0mwv+wwtZ+luS4YOzsRzM/izg=="], - "@oxfmt/binding-openharmony-arm64": ["@oxfmt/binding-openharmony-arm64@0.49.0", "", { "os": "none", "cpu": "arm64" }, "sha512-J85zQMiw2pXiGPK+OusmDvSnJ/dgpgN7VgmB2zOBtgS8F+nsOUfSg9ZEBrwbQscjZ7tkPbm38CG4VF5f53MsiA=="], + "@oxfmt/binding-openharmony-arm64": ["@oxfmt/binding-openharmony-arm64@0.51.0", "", { "os": "none", "cpu": "arm64" }, "sha512-QiC1XrCl6a6BmqMzduO8hdIRMf1m44hCkt2Q68KWkTvUB/E7fd2iomyNh6KnnRca5w6eBrRAAtLFqTh+xjsjJA=="], - "@oxfmt/binding-win32-arm64-msvc": ["@oxfmt/binding-win32-arm64-msvc@0.49.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-38K67XR++CoFFORDd4sMFwUVAnD6msYBdGTei+qvKGrRPO6S2PbrYPNL/eQQ1RgnnxOegNba0YQwg6uRkNcw6A=="], + "@oxfmt/binding-win32-arm64-msvc": ["@oxfmt/binding-win32-arm64-msvc@0.51.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-NC/hJb9dtU23Zf8L7IVK95xnFjiQ7AfcLO2l5pb69TDEr958qxrtnB2CveeeNSCBFNIkgaTCfd/vHNSoG78l9g=="], - "@oxfmt/binding-win32-ia32-msvc": ["@oxfmt/binding-win32-ia32-msvc@0.49.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-rXVe0HICwQF0dBgbQtBCoYf8x/SidPIdhyQl+iPuJlV7suV+qDv7yUEB3wQ4qC3nOeNxz287SwFXKzyr0kWgEg=="], + "@oxfmt/binding-win32-ia32-msvc": ["@oxfmt/binding-win32-ia32-msvc@0.51.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-2C45za4Rj36n8YIbhRL1PQbxmXJYf81WEcAgvj5I4ptRROG+A+81hREEN5bmCHADE1UfYaN312U6tkILoZZy6w=="], - "@oxfmt/binding-win32-x64-msvc": ["@oxfmt/binding-win32-x64-msvc@0.49.0", "", { "os": "win32", "cpu": "x64" }, "sha512-gwWLwSEmBBfIK/Wh7GGd658161o4RKAvHWRaRQbJm571iQXGKfyr7UKsI1vsWvDlNLc30CxJDc8mMmCvJ/kczQ=="], + "@oxfmt/binding-win32-x64-msvc": ["@oxfmt/binding-win32-x64-msvc@0.51.0", "", { "os": "win32", "cpu": "x64" }, "sha512-73RqdAuVKQTkjZIDw08JaDHUM4lav5Qu+CaPwg4QbbA7k8o7LEW0p3UsfZ/F8dsO/pwVYh3RzFcanwLRTTahbQ=="], - "@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.64.0", "", { "os": "android", "cpu": "arm" }, "sha512-2r6Nq3XXGLHEXKkSj8JtmJ6N4gDw431DPFOg0ZoJHlNjnG6HVMm/ksQ10m0HJ8WBvwgMe1L50UHPaYZutCRPCw=="], + "@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.66.0", "", { "os": "android", "cpu": "arm" }, "sha512-f7kq8N51T4phpzqfBpA2qaVTI/KrkCmNwaj3t/97I/WLTDI+UhlP5GL9eER+zVxBhtlx5rKXWByJU1/zDAvyaw=="], - "@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.64.0", "", { "os": "android", "cpu": "arm64" }, "sha512-ePJMpePgg7fBv+L/hVx1xXRU5/5gd5m0obLA6hPEfLXF3GjpR8idIDbY1dhQYhyz1ms2wdTccSboo6KEd2Oxtg=="], + "@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.66.0", "", { "os": "android", "cpu": "arm64" }, "sha512-xu6QO71tdDS9mjmLZ3AqhtaVHBvdmsOKkYnReNNDgh+XiwnsipeQOIxbiYOOO0iAXycJ+GK0wdMSZP/2j/AmSg=="], - "@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.64.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-U4DMLQd10gJLuoSTLSGbfv3bGjTlUNsScm9Dgb8wwBqmCzidf1pE1pXV4doGNxqwH3KtVng1AGTINA0NvkGLvQ=="], + "@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.66.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HZ24VimSOC7mxuEA99e0H2FS0C1yO3+iW13jPRAk+e2njsUs3QeAXsafCDyaIrV/MirdOVez+etQNQsJE43zNQ=="], - "@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.64.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-GoRIL48QWm4/TAvjN8pB1nAG+1/uqc9EdnWT9zqHeb6wsmjZtywj8VRe5aGW47Fdb64YtLOsdLqVxOvQuz98Wg=="], + "@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.66.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-awhj8ZvJrrRSnXj7V++rpZvTmnl99L6mi0B7gg7Cp7BN6cKpzuI481bHNLvXGA9GB1/oEgA3ponuyoAc6Md12A=="], - "@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.64.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-5dFkv4tkg7PxJJGS9/OjrJwjhuHczrd3OQOkRE0wHcLM+ncUnULtzEPWjqGOxTXxZnLWcB91bGiIznx89TVXyQ=="], + "@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.66.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-KQF0oVV21/FjIqkRuL8Q1vh8ECsE5+ocdH5tcqTQ4ZnYuDVoYibQUNfqBjQaUsP6UIIda5Y75Wpm5p4RgQWiWw=="], - "@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.64.0", "", { "os": "linux", "cpu": "arm" }, "sha512-jsBqMLl/uOL5+Kq/+BtK9FrmiNGUbx8SiyZXv+WlUxA45KuwcLu9BfiSIL3I3DBDgWM3yZizDITnTK9BcqNBQg=="], + "@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.66.0", "", { "os": "linux", "cpu": "arm" }, "sha512-9u1rgwZSEXWb30vbFZzQ78HVXBo0WCKNwJ3a2InRUTNMRng+PUDIoSFmA+m4HdUfBaIqftShq8J8qHc+eE/Vig=="], - "@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.64.0", "", { "os": "linux", "cpu": "arm" }, "sha512-1lrj8At/Uuc9GhjrVFBQo0NEjfBrTkzpmtHIGAhNnIXqn1CAyGL+qrztUsXb2GIluJrpl9Q7qRLJOb/NqydacQ=="], + "@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.66.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Ynot2HR1bHxUaNWoC280MVTDfZuaWuP3XfSMRDhyuZrVjhzoaBCVFlw8h8qeZjWKVUBhPWFIxB7AQTlK8Z2WWg=="], - "@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.64.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-HpSQbubwh03mMhAdy2BYtad/fsY8vDFHDAb6bUwuCYg2VD3xCQgn6ArKcO0oZyLCheacKTv4PrF3Mfu5hgoE2g=="], + "@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.66.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-xCbgzciGgo+A4aQZEknsNrNiIwY7sU5SfRuMmRjPIvZAgdF34cIHiKvwOsS5XRLjlTVSFwitmq6YclTtHTfU+g=="], - "@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.64.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-00QQ0h0Y7u0G69BgiH3+ky2aaq/QvkDL6DYok8htIuJHxybiux5aQ8jwmg8qIk9wha6UagUP2BAwAzbemcJbpg=="], + "@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.66.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-hmo+ZB/lHkR1HdDmnziNpzSLmulnUSu10VEqX2Yex7OwvoBAbjJQLvy4gIBRV3AAwWnCvAxKp5Nv1GE6LU1QMg=="], - "@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.64.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-2GaimTV6EMW+s5HS0An3oGbQme3BgHswvfVdGk3EB57Xe9+/gyT+Qd7lNVzb3rtir52vbIPzXfaYArzs5b5zcw=="], + "@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.66.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-2Invd4Uyy81mVooQC5FBtfxSNrvcX1OxbMlVQ6M2erRrNI2awFYF26YNW2yFxdVFZ4ffNOWKghtMjhnUPsXsVA=="], - "@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.64.0", "", { "os": "linux", "cpu": "none" }, "sha512-H46AtFb9wypjoVwGdlxrm0DsD809NGmtiK9HiyPKTxkSte2YjhC4S+00rOIrwCaxcyPiGid3Y3OMXp5KMAkGZw=="], + "@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.66.0", "", { "os": "linux", "cpu": "none" }, "sha512-s0iXPDQVdgayE3RGa/N2DZF7tjgg0TwEtD1sGoDxqPDGrIXgo45H0yHknT0f9A0yteASsweYZtDyTuVlM4aSag=="], - "@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.64.0", "", { "os": "linux", "cpu": "none" }, "sha512-HEgsidjjvvyzdg82icYkuFCf7REDV7B9JFwbIMbVwrKLBY0MrXX+bku3POn/hduZ2yW91IyVDUMq0Bf02KwXQw=="], + "@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.66.0", "", { "os": "linux", "cpu": "none" }, "sha512-OekL4XFiu7RPK0JIZi8VeHgtIXPREf42t8Cy/rKEsC+P3gcqDgNAAGiyuUOpdbG4wwbfue1q4CHcCO7spSve6w=="], - "@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.64.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-Axvm8qryotmKN00P5w4JapaSjvP2LOSbdbBJiX+2SuHd3QzhW7TUc8skqgw+ahQZ5DmzEYeHCqauvW8f32Ns6Q=="], + "@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.66.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-Ga1D0kj1SFslm34ThA/BdkUlyAYEnTsXyRC4pF0C5agZSwtGdHYWMTQWemUfBGp4RCG4QWXgdO+HmmmKqOtlBg=="], - "@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.64.0", "", { "os": "linux", "cpu": "x64" }, "sha512-cR60vSd7+m+KRZ3GQGfDxWwahW5RMXg0qlGvAluZr0fTUYvw0H9N9AXAF/M/PMqgytyqvVNmBAkJG9l7U30Y1g=="], + "@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.66.0", "", { "os": "linux", "cpu": "x64" }, "sha512-p5jfP1wUZe/IC3qpQO84n9DRnf9g3lKRtLBlQq23ykyrDglHcVx7sWmVTlPuU6SBw8mNnPzyOn022G3XZHnlww=="], - "@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.64.0", "", { "os": "linux", "cpu": "x64" }, "sha512-2u/aPZ9pEg7HnvZPDsHxUGNnrpr4qaHi+mCgLgpt+LYRzPrS4Px4wPfkIdRdr2GvKnaYyt+XSlto0Vm5sbStTg=="], + "@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.66.0", "", { "os": "linux", "cpu": "x64" }, "sha512-vUB/sYlYZorDL1ZD+o9mRv7zbsykrrFRtmgS6R8musZqLtrPRQn1gc1eGpuX+sfdccz42STl/AqldY6XRb2upQ=="], - "@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.64.0", "", { "os": "none", "cpu": "arm64" }, "sha512-kfhkGfCdoXLSxEkrhDlJrvBYajGmq+ma4EMc53dsOWTq+rIBOlI0vTBmpZNnM5oH2LY/K/w1HAK+UQEgjgpVUg=="], + "@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.66.0", "", { "os": "none", "cpu": "arm64" }, "sha512-yde+6p/F59xRkGR9H1HfngWRif1QRJjynZK349l+UI0H6w9hL3G8/AVaTHFyTtLVQ56qtNbX2/5Dc77n1ovnOg=="], - "@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.64.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-r/cNKBFieONoVu2bb1KkVouq9W+edDUgHumXJGphCRRj+U0xaD4nanrw8ZOqo0IsutPkEM4vCcGBpak6x5aXMg=="], + "@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.66.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-O9GLucgoTdmOrbBX+EjzNe7o/Ze5TFOvXcib6bzUOtBOmj6cV+zw18NgB+cGKAkDw1Pdqs8vGkfHbbsLuDtXWg=="], - "@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.64.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-tUw0xUUwEFVZbpJoeCblkv8SJA4Xz3CdXCJbAnBsiNLyxDrk2tLcxEAS6M73Q7hHHDg3OtwI8vZVK3t5RJt4Gw=="], + "@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.66.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-m3Pjwc2MfTcom4E4gOv7DyuGyt7OfGNCbmqDHd+N7EzXmP+ppHuudm2NjcA3AjV5TSeGxaguVF4SbTKHe1USYA=="], - "@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.64.0", "", { "os": "win32", "cpu": "x64" }, "sha512-9CBR+LO0JVST87fNTzzNxS5I29jIUO5gxT9i9+M3SDHHALElj9sY1Prf12tad3vIRC6OD7Ehtvvh+sn13vSwHw=="], + "@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.66.0", "", { "os": "win32", "cpu": "x64" }, "sha512-/DbBvw8UFBhja6PqudUjV4UtfsJr0Oa7jUjWVKB0g86lj/VwnPrkngn0sFql3c9RDA0O16dh7ozsXb6GjNAzBQ=="], "@quansync/fs": ["@quansync/fs@1.0.0", "", { "dependencies": { "quansync": "^1.0.0" } }, "sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ=="], @@ -325,23 +325,23 @@ "@types/jsesc": ["@types/jsesc@2.5.1", "", {}, "sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw=="], - "@types/node": ["@types/node@25.8.0", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ=="], + "@types/node": ["@types/node@25.9.1", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg=="], - "@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20260515.1", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260515.1", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260515.1", "@typescript/native-preview-linux-arm": "7.0.0-dev.20260515.1", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260515.1", "@typescript/native-preview-linux-x64": "7.0.0-dev.20260515.1", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260515.1", "@typescript/native-preview-win32-x64": "7.0.0-dev.20260515.1" }, "bin": { "tsgo": "bin/tsgo.js" } }, "sha512-dWhzJGb9iJfCDsjz/LzPkbMj5XDbFWyZmDyTixcmQPgX5zFOPZ+sAdlCpTZFGEJhA7OqXG+lZyajbJfjYvQorA=="], + "@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20260519.1", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260519.1", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260519.1", "@typescript/native-preview-linux-arm": "7.0.0-dev.20260519.1", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260519.1", "@typescript/native-preview-linux-x64": "7.0.0-dev.20260519.1", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260519.1", "@typescript/native-preview-win32-x64": "7.0.0-dev.20260519.1" }, "bin": { "tsgo": "bin/tsgo.js" } }, "sha512-VVER7vFUDdfm5k3jbH5765tVEJa7+0rTUkFeXyGYrXPxpw9BIjA0QDxdtdlRyaU8MCZV9IKZUo6doxeAQRAjPg=="], - "@typescript/native-preview-darwin-arm64": ["@typescript/native-preview-darwin-arm64@7.0.0-dev.20260515.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-CSvyLkNV0k4Ro0B6nzNdDXFrRD8aa6sDvXSGla2FTmBio+JLKqNuJXq1ppyj42j9pAwdUhDZV/PNdjeHRCBjWQ=="], + "@typescript/native-preview-darwin-arm64": ["@typescript/native-preview-darwin-arm64@7.0.0-dev.20260519.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-c9zdG6sGJf25Jpz04JgE23zhYeprqFypDGuqiX94yMTvR8IWXjq3R2oMnim66YLBDon/V1nCEy6cFixeSd/4fg=="], - "@typescript/native-preview-darwin-x64": ["@typescript/native-preview-darwin-x64@7.0.0-dev.20260515.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-QTmm0dpF6CC3hrfudAyVcIvbr1tlBTZ7aGQHIs4PYmi+tnTi2R8jy6gDBCJWlDBSXqjPWlQZrdiOxRBCSlShSA=="], + "@typescript/native-preview-darwin-x64": ["@typescript/native-preview-darwin-x64@7.0.0-dev.20260519.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-N16V3wiM0tsNmSSA7nZrxqXXt5OCJxBwiCVn35rnA7fr4WzJw6rJmwf9heNNhZ6Gh4ne3+Pexajf5akzuHR75Q=="], - "@typescript/native-preview-linux-arm": ["@typescript/native-preview-linux-arm@7.0.0-dev.20260515.1", "", { "os": "linux", "cpu": "arm" }, "sha512-0b+Sxh8JUNMqvw06wfIoh45+G68/ikCW+aRqHGipU2uc9M9dWUKvI3zDyzP1rF6FOJ7xMKMbTbi5b2IvcRqh8g=="], + "@typescript/native-preview-linux-arm": ["@typescript/native-preview-linux-arm@7.0.0-dev.20260519.1", "", { "os": "linux", "cpu": "arm" }, "sha512-8v4BExeeuCTrhaSGfeIJqm3qQkTzlZix/Qd/FkPlWoz9f7d7COvXb3Z4qhbaVolL0MMnUvQ7m005Z4kYsZ645A=="], - "@typescript/native-preview-linux-arm64": ["@typescript/native-preview-linux-arm64@7.0.0-dev.20260515.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-bH/CYrtXURXr3YwqJmlKblQ858wuJ0Qw2VSMvlsWwYZpb8eOd07T2bl1Ba6QxGBuL6EotcDQFd2OYJIj0uvM7A=="], + "@typescript/native-preview-linux-arm64": ["@typescript/native-preview-linux-arm64@7.0.0-dev.20260519.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-ltf91vAwKdbu0SlRQbFgi1h5ZrLLrBn6a4qIeN2VILGbtYrCXnARHRznLBv81yUETQ7aVr/LSQcmsWo1ejCK0w=="], - "@typescript/native-preview-linux-x64": ["@typescript/native-preview-linux-x64@7.0.0-dev.20260515.1", "", { "os": "linux", "cpu": "x64" }, "sha512-eXgYE6pmkCiEEX7T43TYeF24uiY8+h9mbi9YSvnCoRp4BLgn9b7uJagh4ctSGCNxUy3QSDeoznkWfSVlrvJ5pA=="], + "@typescript/native-preview-linux-x64": ["@typescript/native-preview-linux-x64@7.0.0-dev.20260519.1", "", { "os": "linux", "cpu": "x64" }, "sha512-AVD0tczTtFCHNa4RQRVPvu8Hnw4P3hQ+OlUAjnz/lHowvc6o1pYB46elMqfDuaoWqIpv+EAkAPP4ipFCofJ5IA=="], - "@typescript/native-preview-win32-arm64": ["@typescript/native-preview-win32-arm64@7.0.0-dev.20260515.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-K1YJimcOr3/lFTJyOChT1GnRdfvoHtIvG/qcwHhHpeCBzpGfG7u2aH9MkBgsXqNJHAXHLnQRuON2uYgU8wWDzw=="], + "@typescript/native-preview-win32-arm64": ["@typescript/native-preview-win32-arm64@7.0.0-dev.20260519.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-TM+qatljyejqjHevCta3WIH53i0oGC7K8SoJ6t+mf4cGMTpZTyd7NhC1ts7e6/aydZnG53Bsta2iQi1SMIlQEw=="], - "@typescript/native-preview-win32-x64": ["@typescript/native-preview-win32-x64@7.0.0-dev.20260515.1", "", { "os": "win32", "cpu": "x64" }, "sha512-1cGEWLao/d2+Q3yMvtnDES85sM9HuI6J6PBmrcjwXzsQxnjXJkujStdp+LB6JZfY+VSDi+cpaCZmrKU6sYUfkg=="], + "@typescript/native-preview-win32-x64": ["@typescript/native-preview-win32-x64@7.0.0-dev.20260519.1", "", { "os": "win32", "cpu": "x64" }, "sha512-r9LEsoY7JC/82gXo8hlOmpQaUXcqmngCVOv+mUx1UeMt9f+1S6oNO0W48o75mlBqqC7jfcMHqw8YS4LfVxPRGw=="], "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], @@ -615,7 +615,7 @@ "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="], - "lint-staged": ["lint-staged@17.0.4", "", { "dependencies": { "listr2": "^10.2.1", "picomatch": "^4.0.4", "string-argv": "^0.3.2", "tinyexec": "^1.1.2" }, "optionalDependencies": { "yaml": "^2.8.4" }, "bin": { "lint-staged": "bin/lint-staged.js" } }, "sha512-+rU9lSUyVOZ/hDUmRLVGzyS2v73cDdQjX+XQz1AaOdIE4RysLq0HoPW2HrrgeNCLklkhi904VBU1bmgWLHVnkA=="], + "lint-staged": ["lint-staged@17.0.5", "", { "dependencies": { "listr2": "^10.2.1", "picomatch": "^4.0.4", "string-argv": "^0.3.2", "tinyexec": "^1.1.2" }, "optionalDependencies": { "yaml": "^2.8.4" }, "bin": { "lint-staged": "bin/lint-staged.js" } }, "sha512-d12yC+/e8RhBjZtaxZn71FyrgU/P5e+uAPifhCLwdosQZP/zamSdKRWDC30ocVIbzDKiFG1McHc/LUgB92GIPw=="], "listr2": ["listr2@10.2.1", "", { "dependencies": { "cli-truncate": "^5.2.0", "eventemitter3": "^5.0.4", "log-update": "^6.1.0", "rfdc": "^1.4.1", "wrap-ansi": "^10.0.0" } }, "sha512-7I5knELsJKTUjXG+A6BkKAiGkW1i25fNa/xlUl9hFtk15WbE9jndA89xu5FzQKrY5llajE1hfZZFMILXkDHk/Q=="], @@ -673,13 +673,13 @@ "outdent": ["outdent@0.5.0", "", {}, "sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q=="], - "oxc-parser": ["oxc-parser@0.130.0", "", { "dependencies": { "@oxc-project/types": "^0.130.0" }, "optionalDependencies": { "@oxc-parser/binding-android-arm-eabi": "0.130.0", "@oxc-parser/binding-android-arm64": "0.130.0", "@oxc-parser/binding-darwin-arm64": "0.130.0", "@oxc-parser/binding-darwin-x64": "0.130.0", "@oxc-parser/binding-freebsd-x64": "0.130.0", "@oxc-parser/binding-linux-arm-gnueabihf": "0.130.0", "@oxc-parser/binding-linux-arm-musleabihf": "0.130.0", "@oxc-parser/binding-linux-arm64-gnu": "0.130.0", "@oxc-parser/binding-linux-arm64-musl": "0.130.0", "@oxc-parser/binding-linux-ppc64-gnu": "0.130.0", "@oxc-parser/binding-linux-riscv64-gnu": "0.130.0", "@oxc-parser/binding-linux-riscv64-musl": "0.130.0", "@oxc-parser/binding-linux-s390x-gnu": "0.130.0", "@oxc-parser/binding-linux-x64-gnu": "0.130.0", "@oxc-parser/binding-linux-x64-musl": "0.130.0", "@oxc-parser/binding-openharmony-arm64": "0.130.0", "@oxc-parser/binding-wasm32-wasi": "0.130.0", "@oxc-parser/binding-win32-arm64-msvc": "0.130.0", "@oxc-parser/binding-win32-ia32-msvc": "0.130.0", "@oxc-parser/binding-win32-x64-msvc": "0.130.0" } }, "sha512-X0PJ+NmOok8qP3vK9uaW431ngkdM9UPEK7KG466urtIL2+EYTEgbZK2yqe2MWKJKBjRlFweP/pJPx0x9muMEVw=="], + "oxc-parser": ["oxc-parser@0.132.0", "", { "dependencies": { "@oxc-project/types": "^0.132.0" }, "optionalDependencies": { "@oxc-parser/binding-android-arm-eabi": "0.132.0", "@oxc-parser/binding-android-arm64": "0.132.0", "@oxc-parser/binding-darwin-arm64": "0.132.0", "@oxc-parser/binding-darwin-x64": "0.132.0", "@oxc-parser/binding-freebsd-x64": "0.132.0", "@oxc-parser/binding-linux-arm-gnueabihf": "0.132.0", "@oxc-parser/binding-linux-arm-musleabihf": "0.132.0", "@oxc-parser/binding-linux-arm64-gnu": "0.132.0", "@oxc-parser/binding-linux-arm64-musl": "0.132.0", "@oxc-parser/binding-linux-ppc64-gnu": "0.132.0", "@oxc-parser/binding-linux-riscv64-gnu": "0.132.0", "@oxc-parser/binding-linux-riscv64-musl": "0.132.0", "@oxc-parser/binding-linux-s390x-gnu": "0.132.0", "@oxc-parser/binding-linux-x64-gnu": "0.132.0", "@oxc-parser/binding-linux-x64-musl": "0.132.0", "@oxc-parser/binding-openharmony-arm64": "0.132.0", "@oxc-parser/binding-wasm32-wasi": "0.132.0", "@oxc-parser/binding-win32-arm64-msvc": "0.132.0", "@oxc-parser/binding-win32-ia32-msvc": "0.132.0", "@oxc-parser/binding-win32-x64-msvc": "0.132.0" } }, "sha512-+0LAPHaqtfQlvWdpaAa09SmOaZZgP8C552xosEkGJ4+ruEwP1Vgx+sqBgcBCNfR6KDCmagGOZTde8wmAvcI/Hg=="], "oxc-resolver": ["oxc-resolver@11.19.1", "", { "optionalDependencies": { "@oxc-resolver/binding-android-arm-eabi": "11.19.1", "@oxc-resolver/binding-android-arm64": "11.19.1", "@oxc-resolver/binding-darwin-arm64": "11.19.1", "@oxc-resolver/binding-darwin-x64": "11.19.1", "@oxc-resolver/binding-freebsd-x64": "11.19.1", "@oxc-resolver/binding-linux-arm-gnueabihf": "11.19.1", "@oxc-resolver/binding-linux-arm-musleabihf": "11.19.1", "@oxc-resolver/binding-linux-arm64-gnu": "11.19.1", "@oxc-resolver/binding-linux-arm64-musl": "11.19.1", "@oxc-resolver/binding-linux-ppc64-gnu": "11.19.1", "@oxc-resolver/binding-linux-riscv64-gnu": "11.19.1", "@oxc-resolver/binding-linux-riscv64-musl": "11.19.1", "@oxc-resolver/binding-linux-s390x-gnu": "11.19.1", "@oxc-resolver/binding-linux-x64-gnu": "11.19.1", "@oxc-resolver/binding-linux-x64-musl": "11.19.1", "@oxc-resolver/binding-openharmony-arm64": "11.19.1", "@oxc-resolver/binding-wasm32-wasi": "11.19.1", "@oxc-resolver/binding-win32-arm64-msvc": "11.19.1", "@oxc-resolver/binding-win32-ia32-msvc": "11.19.1", "@oxc-resolver/binding-win32-x64-msvc": "11.19.1" } }, "sha512-qE/CIg/spwrTBFt5aKmwe3ifeDdLfA2NESN30E42X/lII5ClF8V7Wt6WIJhcGZjp0/Q+nQ+9vgxGk//xZNX2hg=="], - "oxfmt": ["oxfmt@0.49.0", "", { "dependencies": { "tinypool": "2.1.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.49.0", "@oxfmt/binding-android-arm64": "0.49.0", "@oxfmt/binding-darwin-arm64": "0.49.0", "@oxfmt/binding-darwin-x64": "0.49.0", "@oxfmt/binding-freebsd-x64": "0.49.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.49.0", "@oxfmt/binding-linux-arm-musleabihf": "0.49.0", "@oxfmt/binding-linux-arm64-gnu": "0.49.0", "@oxfmt/binding-linux-arm64-musl": "0.49.0", "@oxfmt/binding-linux-ppc64-gnu": "0.49.0", "@oxfmt/binding-linux-riscv64-gnu": "0.49.0", "@oxfmt/binding-linux-riscv64-musl": "0.49.0", "@oxfmt/binding-linux-s390x-gnu": "0.49.0", "@oxfmt/binding-linux-x64-gnu": "0.49.0", "@oxfmt/binding-linux-x64-musl": "0.49.0", "@oxfmt/binding-openharmony-arm64": "0.49.0", "@oxfmt/binding-win32-arm64-msvc": "0.49.0", "@oxfmt/binding-win32-ia32-msvc": "0.49.0", "@oxfmt/binding-win32-x64-msvc": "0.49.0" }, "peerDependencies": { "svelte": "^5.0.0" }, "optionalPeers": ["svelte"], "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-IAHFMdlJSWe+oAr65dx22UvjCtV9DBMisAuLnKpDqMQrctzCkGnj3QRwNHm0d+uwSWPalsDF8ZYLz9rh6nH2IQ=="], + "oxfmt": ["oxfmt@0.51.0", "", { "dependencies": { "tinypool": "2.1.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.51.0", "@oxfmt/binding-android-arm64": "0.51.0", "@oxfmt/binding-darwin-arm64": "0.51.0", "@oxfmt/binding-darwin-x64": "0.51.0", "@oxfmt/binding-freebsd-x64": "0.51.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.51.0", "@oxfmt/binding-linux-arm-musleabihf": "0.51.0", "@oxfmt/binding-linux-arm64-gnu": "0.51.0", "@oxfmt/binding-linux-arm64-musl": "0.51.0", "@oxfmt/binding-linux-ppc64-gnu": "0.51.0", "@oxfmt/binding-linux-riscv64-gnu": "0.51.0", "@oxfmt/binding-linux-riscv64-musl": "0.51.0", "@oxfmt/binding-linux-s390x-gnu": "0.51.0", "@oxfmt/binding-linux-x64-gnu": "0.51.0", "@oxfmt/binding-linux-x64-musl": "0.51.0", "@oxfmt/binding-openharmony-arm64": "0.51.0", "@oxfmt/binding-win32-arm64-msvc": "0.51.0", "@oxfmt/binding-win32-ia32-msvc": "0.51.0", "@oxfmt/binding-win32-x64-msvc": "0.51.0" }, "peerDependencies": { "svelte": "^5.0.0" }, "optionalPeers": ["svelte"], "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-l/AoAnaEOV7Q5/Z9kHOMDehVJnCgYN7wRoooWCTUMBMi16BJhLZqd9cmCnwcVFfVlzkt53zK2KLPFNp8vSsoDg=="], - "oxlint": ["oxlint@1.64.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.64.0", "@oxlint/binding-android-arm64": "1.64.0", "@oxlint/binding-darwin-arm64": "1.64.0", "@oxlint/binding-darwin-x64": "1.64.0", "@oxlint/binding-freebsd-x64": "1.64.0", "@oxlint/binding-linux-arm-gnueabihf": "1.64.0", "@oxlint/binding-linux-arm-musleabihf": "1.64.0", "@oxlint/binding-linux-arm64-gnu": "1.64.0", "@oxlint/binding-linux-arm64-musl": "1.64.0", "@oxlint/binding-linux-ppc64-gnu": "1.64.0", "@oxlint/binding-linux-riscv64-gnu": "1.64.0", "@oxlint/binding-linux-riscv64-musl": "1.64.0", "@oxlint/binding-linux-s390x-gnu": "1.64.0", "@oxlint/binding-linux-x64-gnu": "1.64.0", "@oxlint/binding-linux-x64-musl": "1.64.0", "@oxlint/binding-openharmony-arm64": "1.64.0", "@oxlint/binding-win32-arm64-msvc": "1.64.0", "@oxlint/binding-win32-ia32-msvc": "1.64.0", "@oxlint/binding-win32-x64-msvc": "1.64.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.22.1" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-Star3SNpWPeWFPw7kRXIhXUSn6fdiAl25q15CQzH/9WaOtG6e9CWTc25vNZOCr4PE1yEP1GtKJKIKglhj3OmEQ=="], + "oxlint": ["oxlint@1.66.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.66.0", "@oxlint/binding-android-arm64": "1.66.0", "@oxlint/binding-darwin-arm64": "1.66.0", "@oxlint/binding-darwin-x64": "1.66.0", "@oxlint/binding-freebsd-x64": "1.66.0", "@oxlint/binding-linux-arm-gnueabihf": "1.66.0", "@oxlint/binding-linux-arm-musleabihf": "1.66.0", "@oxlint/binding-linux-arm64-gnu": "1.66.0", "@oxlint/binding-linux-arm64-musl": "1.66.0", "@oxlint/binding-linux-ppc64-gnu": "1.66.0", "@oxlint/binding-linux-riscv64-gnu": "1.66.0", "@oxlint/binding-linux-riscv64-musl": "1.66.0", "@oxlint/binding-linux-s390x-gnu": "1.66.0", "@oxlint/binding-linux-x64-gnu": "1.66.0", "@oxlint/binding-linux-x64-musl": "1.66.0", "@oxlint/binding-openharmony-arm64": "1.66.0", "@oxlint/binding-win32-arm64-msvc": "1.66.0", "@oxlint/binding-win32-ia32-msvc": "1.66.0", "@oxlint/binding-win32-x64-msvc": "1.66.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.22.1" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-N4LLxYLd94KEBqXDMDM5f+2PUpItTjDLreXe2Gn5KhjhCK4Qp2YUXaBi8Yu325ryOgKwt22m45fpD7nPOn69Yw=="], "p-filter": ["p-filter@2.1.0", "", { "dependencies": { "p-map": "^2.0.0" } }, "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw=="], @@ -887,6 +887,10 @@ "@quansync/fs/quansync": ["quansync@1.0.0", "", {}, "sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA=="], + "@types/better-sqlite3/@types/node": ["@types/node@25.8.0", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ=="], + + "bun-types/@types/node": ["@types/node@25.8.0", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ=="], + "log-update/slice-ansi": ["slice-ansi@7.1.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w=="], "log-update/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], @@ -897,6 +901,8 @@ "read-yaml-file/js-yaml": ["js-yaml@3.14.2", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="], + "rolldown/@oxc-project/types": ["@oxc-project/types@0.130.0", "", {}, "sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q=="], + "string-width/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], "type-is/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="], diff --git a/docs/architecture.md b/docs/architecture.md index e90ed86f..e2934ae7 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -119,7 +119,7 @@ A local SQLite database (`.codemap/index.db`) indexes the project tree and store **Commands and flags** (index, query, **`codemap agents init`**, **`--root`**, **`--config`**, environment): [../README.md § CLI](../README.md#cli) — **do not duplicate** flag lists here; this section only adds implementation notes. From this repository: **`bun run dev`** or **`bun src/index.ts`** (same flags). -**Query wiring:** **`src/cli/cmd-query.ts`** (argv, **`printQueryResult`**, `--recipe` / `-r` alias, **`--summary`**, **`--changed-since`**, **`--group-by`**, **`--save-baseline`** / **`--baseline`** / **`--baselines`** / **`--drop-baseline`**, **`--ci`** (aliases `--format sarif` + non-zero exit on findings + quiet)), **`src/application/query-recipes.ts`** (**`QUERY_RECIPES`** — bundled SQL only source; optional **`actions: RecipeAction[]`** per recipe), **`src/cli/main.ts`** (**`--recipes-json`** / **`--print-sql`** exit before config/DB). With **`--json`**, errors use **`{"error":"…"}`** on stdout for SQL failures, DB open, and bootstrap (same shape); **`runQueryCmd`** sets **`process.exitCode`** instead of **`process.exit`**. Friendlier "no `.codemap/index.db`" — `no such table: ` and `no such column: ` errors are rewritten in **`enrichQueryError`** to point at `codemap` / `codemap --full`. **`--summary`** filters output only — the SQL still executes against the index; output collapses to `{"count": N}` (with `--json`) or `count: N`. **`--changed-since `** post-filters result rows by `path` / `file_path` / `from_path` / `to_path` / `resolved_path` against `git diff --name-only ...HEAD ∪ git status --porcelain` (helper: **`src/git-changed.ts`** — `getFilesChangedSince`, `filterRowsByChangedFiles`, `PATH_COLUMNS`); rows with no recognised path column pass through. **`--group-by `** (`owner` | `directory` | `package`) routes through **`runGroupedQuery`** in `cmd-query.ts` and emits `{"group_by": "", "groups": [{key, count, rows}]}` (or `[{key, count}]` with `--summary`); helpers in **`src/group-by.ts`** (`groupRowsBy`, `firstDirectory`, `loadCodeowners`, `discoverWorkspaceRoots`, `makePackageBucketizer`, `codeownersGlobToRegex`). CODEOWNERS lookup is last-match-wins (GitHub semantics); workspace discovery reads `package.json` `workspaces` and `pnpm-workspace.yaml` `packages:`. **`--save-baseline[=]`** snapshots the result to the **`query_baselines`** table inside `.codemap/index.db` (no parallel JSON files; survives `--full` / SCHEMA bumps because the table is intentionally absent from `dropAll()`); name defaults to `--recipe` id, ad-hoc SQL needs an explicit name. **`--baseline[=]`** replays the SQL, fetches the saved row set, and emits `{baseline:{...}, current_row_count, added: [...], removed: [...]}` (or `{baseline:{...}, current_row_count, added: N, removed: N}` with `--summary`); identity is per-row multiset equality (canonical `JSON.stringify` keyed frequency map — duplicate rows are tracked, not collapsed). No fuzzy "changed" category in v1. **`--group-by` is mutually exclusive** with both `--save-baseline` and `--baseline` (different output shapes). **`--baselines`** (read-only list) and **`--drop-baseline `** complete the surface; helpers in **`src/db.ts`** (`upsertQueryBaseline`, `getQueryBaseline`, `listQueryBaselines`, `deleteQueryBaseline`). **Per-row recipe `actions`** are appended only when the user runs **`--recipe `** with **`--json`** AND the recipe defines an `actions` template — programmatic `cm.query(sql)` and ad-hoc CLI SQL never carry actions; under `--baseline`, actions attach to `added` rows only (the rows the agent should act on). The **`components-by-hooks`** recipe ranks by hook count with a **comma-based tally** on **`hooks_used`** (no SQLite JSON1). Shipped **`templates/agents/`** documents **`codemap query --json`** as the primary agent example ([README § CLI](../README.md#cli)). +**Query wiring:** Ad-hoc and recipe CLI SQL runs through **`printQueryResult`**, which sets **`PRAGMA query_only = 1`** before execute (parity with **`queryRows`** / **`executeQuery`**). **`src/cli/cmd-query.ts`** (argv, **`printQueryResult`**, `--recipe` / `-r` alias, **`--summary`**, **`--changed-since`**, **`--group-by`**, **`--save-baseline`** / **`--baseline`** / **`--baselines`** / **`--drop-baseline`**, **`--ci`** (aliases `--format sarif` + non-zero exit on findings + quiet)), **`src/application/query-recipes.ts`** (**`QUERY_RECIPES`** — bundled SQL only source; optional **`actions: RecipeAction[]`** per recipe), **`src/cli/main.ts`** (**`--recipes-json`** / **`--print-sql`** exit before config/DB). With **`--json`**, errors use **`{"error":"…"}`** on stdout for SQL failures, DB open, and bootstrap (same shape); **`runQueryCmd`** sets **`process.exitCode`** instead of **`process.exit`**. Friendlier "no `.codemap/index.db`" — `no such table: ` and `no such column: ` errors are rewritten in **`enrichQueryError`** to point at `codemap` / `codemap --full`. **`--summary`** filters output only — the SQL still executes against the index; output collapses to `{"count": N}` (with `--json`) or `count: N`. **`--changed-since `** post-filters result rows by `path` / `file_path` / `from_path` / `to_path` / `resolved_path` against `git diff --name-only ...HEAD ∪ git status --porcelain` (helper: **`src/git-changed.ts`** — `getFilesChangedSince`, `filterRowsByChangedFiles`, `PATH_COLUMNS`); rows with no recognised path column pass through. **`--group-by `** (`owner` | `directory` | `package`) routes through **`runGroupedQuery`** in `cmd-query.ts` and emits `{"group_by": "", "groups": [{key, count, rows}]}` (or `[{key, count}]` with `--summary`); helpers in **`src/group-by.ts`** (`groupRowsBy`, `firstDirectory`, `loadCodeowners`, `discoverWorkspaceRoots`, `makePackageBucketizer`, `codeownersGlobToRegex`). CODEOWNERS lookup is last-match-wins (GitHub semantics); workspace discovery reads `package.json` `workspaces` and `pnpm-workspace.yaml` `packages:`. **`--save-baseline[=]`** snapshots the result to the **`query_baselines`** table inside `.codemap/index.db` (no parallel JSON files; survives `--full` / SCHEMA bumps because the table is intentionally absent from `dropAll()`); name defaults to `--recipe` id, ad-hoc SQL needs an explicit name. **`--baseline[=]`** replays the SQL, fetches the saved row set, and emits `{baseline:{...}, current_row_count, added: [...], removed: [...]}` (or `{baseline:{...}, current_row_count, added: N, removed: N}` with `--summary`); identity is per-row multiset equality (canonical `JSON.stringify` keyed frequency map — duplicate rows are tracked, not collapsed). No fuzzy "changed" category in v1. **`--group-by` is mutually exclusive** with both `--save-baseline` and `--baseline` (different output shapes). **`--baselines`** (read-only list) and **`--drop-baseline `** complete the surface; helpers in **`src/db.ts`** (`upsertQueryBaseline`, `getQueryBaseline`, `listQueryBaselines`, `deleteQueryBaseline`). **Per-row recipe `actions`** are appended only when the user runs **`--recipe `** with **`--json`** AND the recipe defines an `actions` template — programmatic `cm.query(sql)` and ad-hoc CLI SQL never carry actions; under `--baseline`, actions attach to `added` rows only (the rows the agent should act on). The **`components-by-hooks`** recipe ranks by hook count with a **comma-based tally** on **`hooks_used`** (no SQLite JSON1). Shipped **`templates/agents/`** documents **`codemap query --json`** as the primary agent example ([README § CLI](../README.md#cli)). **Output formatters:** **`src/application/output-formatters.ts`** — pure transport-agnostic; **`formatSarif`** emits SARIF 2.1.0 (auto-detected location columns: `file_path` / `path` / `to_path` / `from_path` priority + optional `line_start` / `line_end` region; `rule.id = codemap.` for `--recipe`, `codemap.adhoc` for ad-hoc SQL; aggregate recipes without locations → `results: []` + stderr warning); **`formatAuditSarif`** emits the audit-shaped variant — one rule per delta key (`codemap.audit.-added`), one result per `added` row at severity `warning`; `removed` rows excluded (SARIF surfaces findings, not cleanups); location-only rows fall back to `"new : "` messages; **`formatAnnotations`** emits `::notice file=…,line=…::msg` GitHub Actions workflow commands (one line per locatable row; messages collapsed to a single line because the GH parser stops at the first newline); **`formatMermaid`** emits a `flowchart LR` from `{from, to, label?, kind?}` rows with a hard `MERMAID_MAX_EDGES = 50` ceiling — unbounded inputs reject with a scope-suggestion error naming the recipe + count + `LIMIT` / `--via` / `WHERE` knobs (auto-truncation deliberately out of scope; would be a verdict masquerading as output mode); **`formatDiff`** emits read-only unified diff text from `{file_path, line_start, before_pattern, after_pattern}` rows; **`formatDiffJson`** emits structured `{files, warnings, summary}` hunks for agents. Diff formatters read source files at format time and surface `stale` / `missing` flags when the indexed line no longer matches. Wired into both **`src/cli/cmd-query.ts`** (`--format `; `--format` overrides `--json`; formatted outputs reject `--summary` / `--group-by` / baseline at parse time) and the MCP **`query`** / **`query_recipe`** tools (`format: "sarif" | "annotations" | "mermaid" | "diff" | "diff-json"` with the same incompatibility guard). Per-recipe `sarifLevel` / `sarifMessage` / `sarifRuleId` overrides via frontmatter on `.md` deferred to v1.x. @@ -187,21 +187,23 @@ Optional **`/config.{ts,js,json}`** (default `.codemap/config.*`; def **Fresh database:** the default CLI **`codemap`** (incremental) calls **`createSchema()`** in **`runCodemapIndex`** before **`getChangedFiles()`**, so the **`meta`** table exists before **`getMeta(..., "last_indexed_commit")`** runs on an empty **`.codemap/index.db`**. -Current schema version: **27** — see [Schema Versioning](#schema-versioning) for details. +Current schema version: **34** — see [Schema Versioning](#schema-versioning) for details. All tables use `STRICT` mode. Tables marked with `WITHOUT ROWID` store data directly in the primary key B-tree. PRAGMAs and index design: [SQLite Performance Configuration](#sqlite-performance-configuration). ### `files` — Every indexed file (`STRICT`) -| Column | Type | Description | -| ------------- | ------- | ---------------------------------------------- | -| path | TEXT PK | Relative path from project root | -| content_hash | TEXT | SHA-256 hex — see **Fingerprints** at § Schema | -| size | INTEGER | File size in bytes | -| line_count | INTEGER | Total lines | -| language | TEXT | `ts`, `tsx`, `css`, `md`, etc. | -| last_modified | INTEGER | File mtime (epoch ms) | -| indexed_at | INTEGER | When this row was written | +| Column | Type | Description | +| ---------------- | ------- | -------------------------------------------------------------------- | +| path | TEXT PK | Relative path from project root | +| content_hash | TEXT | SHA-256 hex — see **Fingerprints** at § Schema | +| size | INTEGER | File size in bytes | +| line_count | INTEGER | Total lines | +| language | TEXT | `ts`, `tsx`, `css`, `md`, etc. | +| last_modified | INTEGER | File mtime (epoch ms) | +| indexed_at | INTEGER | When this row was written | +| is_barrel | INTEGER | 1 when every export is a re-export and no local value symbols exist | +| has_side_effects | INTEGER | 1 when module-level calls or assignments were detected at parse time | ### `symbols` — Functions, constants, classes, interfaces, types, enums (`STRICT`) @@ -228,21 +230,28 @@ All tables use `STRICT` mode. Tables marked with `WITHOUT ROWID` store data dire | body_line_count | INTEGER | `line_end - line_start + 1` for function-shaped symbols; NULL for non-functions | | param_count | INTEGER | Parameter count for function-shaped symbols; NULL otherwise | | nesting_depth | INTEGER | Max conditional/loop/ternary nesting inside the body; NULL for non-functions | +| return_type | TEXT | Stringified return type for function-shaped symbols; NULL when unannotated or N/A | +| is_async | INTEGER | 1 for async function-shaped symbols (`function`, `method`, arrow-assigned `function` kind) | +| is_generator | INTEGER | 1 for generator function-shaped symbols | ### `calls` — Function-scoped call edges, deduped per file (`STRICT`) -| Column | Type | Description | -| ------------ | ---------- | --------------------------------------------------------------------------------------------------------------------------------- | -| id | INTEGER PK | Auto-increment row id | -| file_path | TEXT FK | References `files(path)` ON DELETE CASCADE | -| caller_name | TEXT | Name of the calling function/method | -| caller_scope | TEXT | Dot-joined scope path (e.g. `UserService.run`). Anonymous scopes encode as `$anon_` to avoid sibling-callback collisions | -| callee_name | TEXT | Name of the called function, `obj.method` / `obj.foo.bar` for member chains (recursive flatten), `this.method` for self | -| line_start | INTEGER | 1-based line of the callee identifier token (per [R.6]) | -| column_start | INTEGER | 0-based byte column of the callee token | -| column_end | INTEGER | One-past-last column | - -Edges are deduped per (caller_scope, callee) per file: if `foo` calls `bar` three times in the same file, only one row is stored. Same-named methods in different classes get distinct `caller_scope` values. Module-level calls (outside any function) are excluded — only function-scoped calls are tracked. +| Column | Type | Description | +| ------------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------- | +| id | INTEGER PK | Auto-increment row id | +| file_path | TEXT FK | References `files(path)` ON DELETE CASCADE | +| caller_name | TEXT | Name of the calling function/method | +| caller_scope | TEXT | Dot-joined scope path (e.g. `UserService.run`). Anonymous scopes encode as `$anon_` to avoid sibling-callback collisions | +| callee_name | TEXT | Name of the called function, `obj.method` / `obj.foo.bar` for member chains (recursive flatten), `this.method` for self | +| line_start | INTEGER | 1-based line of the callee identifier token (per [R.6]) | +| column_start | INTEGER | 0-based byte column of the callee token | +| column_end | INTEGER | One-past-last column | +| args_count | INTEGER | Argument count; NULL when a spread argument is present | +| is_method_call | INTEGER | 1 when callee is a member expression (`obj.method()`) | +| is_constructor_call | INTEGER | 1 for `new Foo()` (`NewExpression`) | +| is_optional_chain | INTEGER | 1 when the call uses optional chaining (`?.`) | + +Edges are deduped per (caller_scope, callee, call vs constructor) per file: if `foo` calls `bar` three times in the same file, only one row is stored. `foo()` and `new Foo()` with the same callee name remain distinct rows. Same-named methods in different classes get distinct `caller_scope` values. Module-level calls (outside any function) are excluded — only function-scoped calls are tracked. ### `type_members` — Properties and methods of interfaces and object-literal types (`STRICT`) @@ -314,8 +323,9 @@ Edges are deduped per (caller_scope, callee) per file: if `foo` calls `bar` thre | column_end | INTEGER | One-past-last column | | imported_name | TEXT | Original exported name (or `default` / `*`) | | local_name | TEXT | Local binding name (different from `imported_name` for `import { foo as bar }`) | -| kind | TEXT | `named` / `default` / `namespace` | +| kind | TEXT | `named` / `default` / `namespace` / `side-effect` | | is_type_only | INTEGER | 1 if this specifier is `type`-only | +| import_id | INTEGER FK | Parent `imports.id`; populated for all specifier rows including side-effect | ### `scopes` — Lexical scope graph (`STRICT, WITHOUT ROWID`) @@ -355,7 +365,7 @@ Per [R.12]. One row per non-`member`-kind `references` row. Resolved in a single | ------------------ | ------- | ------------------------------------------------------------------------------- | | reference_id | INTEGER | PK + FK → `references(id)` CASCADE | | resolved_symbol_id | INTEGER | FK → `symbols(id)` SET NULL. NULL for `is_external=1` / `global` / `unresolved` | -| resolution_kind | TEXT | `same-file` / `imported` / `global` / `unresolved` | +| resolution_kind | TEXT | `same-file` / `imported` / `re-exported` / `global` / `unresolved` | | is_external | INTEGER | 1 when the import target isn't in the indexed set (e.g. `react`, `lodash`) | ### `function_params` — Typed parameters per function/method (`STRICT`) @@ -421,6 +431,47 @@ SCCs of size ≥ 2 from `dependencies`, plus size-1 SCCs with a self-edge. Compu | cycle_id | INTEGER | Per-PR auto-numbered cycle id (shared across cycle members) | | cycle_size | INTEGER | Number of files in the cycle | +### `dynamic_imports` — Dynamic `import()` sites (`STRICT`) + +| Column | Type | Description | +| -------------- | ---------- | --------------------------------------------------------------------- | +| id | INTEGER PK | Auto-increment row id | +| file_path | TEXT FK | Containing file | +| line_start | INTEGER | 1-based line of the module specifier token | +| column_start | INTEGER | 0-based column of the specifier start | +| source_kind | TEXT | `literal` / `template` / `expression` | +| source_text | TEXT | Specifier text (literal value, template source, or expression source) | +| resolved_path | TEXT | Project-relative path when `source_kind = 'literal'` and resolvable | +| in_async_fn | INTEGER | 1 when the import sits inside an async function body | +| scope_local_id | INTEGER | Enclosing scope (joins `scopes.local_id`; `0` = module) | + +### `jsx_elements` / `jsx_attributes` — JSX substrate (`STRICT`) + +Every JSX element and attribute in `.tsx`/`.jsx` files. `parent_element_id` is filled in a post-insert pass within the file. Fragments use `is_fragment = 1` and empty `component_name`. + +| Column (elements) | Type | Description | +| ----------------- | ---------- | -------------------------------------- | +| component_name | TEXT | Tag name (`ProductCard`, `article`, …) | +| is_self_closing | INTEGER | 1 for `` | +| is_fragment | INTEGER | 1 for `<>…` | +| is_lowercase | INTEGER | 1 for native HTML tags | +| parent_element_id | INTEGER FK | Parent element row | +| children_count | INTEGER | Direct JSX child element count | + +| Column (attributes) | Type | Description | +| ------------------- | ---- | ---------------------------------------------------------- | +| element_id | FK | Owning `jsx_elements.id` | +| value_kind | TEXT | `string` / `expression` / `boolean` / `spread` / `element` | + +### `async_calls` / `try_catch` / `decorators` / `jsdoc_tags` — Behavioral substrate (`STRICT`) + +| Table | Flagship signal | +| ------------- | ---------------------------------------------------------------------- | +| `async_calls` | `AwaitExpression` sites with `in_loop` / `in_try` context stack | +| `try_catch` | `TryStatement` shape + `catch_logs_only` / `catch_rethrows` heuristics | +| `decorators` | Decorator name + `target_kind`; `target_symbol_id` linked post-insert | +| `jsdoc_tags` | Structured tags (`@param`, `@throws`, …) per symbol from `doc_comment` | + ### `runtime_markers` — Operational signals (`STRICT`) Every `console.*` call, `debugger` statement, `throw` statement, and `process.env.X` access. Powers `find-leftover-console` + `env-var-audit`. diff --git a/docs/glossary.md b/docs/glossary.md index b8e26adf..91301ee1 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -43,13 +43,17 @@ Two-snapshot structural-drift command: `codemap audit` diffs the live `.codemap/ Ad-hoc audit snapshot from any git committish (`origin/main`, `HEAD~5`, ``, tag, …). `git archive --format=tar ` is piped through `tar -x` into `/.codemap/audit-cache//` — a plain extracted tree with no `.git` artifact and no registered git worktree, so `git clean -xdf` and `rm -rf` both sweep it without flag escalation. Codemap reindexes into the cache's `.codemap/index.db`, then per-delta canonical SQL runs on that DB vs the live one. Cache key is the **resolved sha** (`git rev-parse --verify`), so `--base origin/main` and `--base ` (when they point at the same commit) share one cache entry. **Atomic populate** — per-pid temp dir + POSIX `rename`; concurrent processes resolving the same sha race-safely without lock files. Eviction: hardcoded LRU 5 entries / 500 MiB. Per-delta `base.source` is `"ref"` (vs `"baseline"`) and the delta carries `base.ref` (user-supplied string) + `base.sha` (resolved). Mutually exclusive with `--baseline `; composes orthogonally with per-delta `---baseline ` overrides. Hard error on non-git projects (no graceful fallback — there's no meaningful "ref" without git). Both transports (MCP `audit` tool's `base?` arg, HTTP `POST /tool/audit`) call the same `runAuditFromRef` engine in `application/audit-engine.ts`. +### `async_calls` (table) + +One row per `AwaitExpression`. Captures `awaited_expression` source text, optional `awaited_callee_name`, and loop/try context flags (`in_loop`, `in_try`) from a visitor context stack. Joins `scopes.local_id` via `scope_local_id`. Powers `find-await-in-loop`. + --- ## B ### barrel file -In Codemap usage: a file with a high number of `exports` rows — typically a public-API hub like `src/index.ts`. Surfaced by the `barrel-files` recipe. Distinct from **hub** below — barrel measures _exports out_, hub measures _imports in_. +In Codemap usage: a file whose exports are entirely re-exports with no local value symbols — surfaced as `files.is_barrel = 1` (post-pass) and by the `barrel-files` / `find-barrel-files` recipes. Distinct from **hub** below — barrel measures _exports out_, hub measures _imports in_. ### batch insert @@ -57,7 +61,7 @@ The shared `batchInsert()` helper in `src/db.ts`. Splits inserts into multi-r ### `bindings` (table) / bindings resolver -Per-reference resolution to the originating symbol per [R.12]. One row per non-`member`-kind `references` row, with `resolution_kind` in `{same-file, imported, global, unresolved}` and a nullable `resolved_symbol_id` joining `symbols(id)`. Resolved in a single in-memory pass (`src/application/bindings-engine.ts`) after files/symbols/imports settle. Full-rebuild only — targeted reindex skips per [R.10]. Powers `find-symbol-references` (bindings-precise rename substrate). +Per-reference resolution to the originating symbol per [R.12]. One row per non-`member`-kind `references` row, with `resolution_kind` in `{same-file, imported, re-exported, global, unresolved}` and a nullable `resolved_symbol_id` joining `symbols(id)`. Resolved in a single in-memory pass (`src/application/bindings-engine.ts`) after files/symbols/imports settle. Full-rebuild only — targeted reindex skips per [R.10]. Powers `find-symbol-references` and `find-re-exported-bindings`. ### `boundaries` (config) / `boundary_rules` (table) / `boundary-violations` (recipe) @@ -77,7 +81,7 @@ Synchronous Node.js SQLite binding. The Node-side counterpart to `bun:sqlite`. A ### `calls` (table) -Function-scoped call edges, deduped per `(caller_scope, callee_name)` per file. **`caller_scope`** is dot-joined enclosing scope (e.g. `UserService.run`). Module-level calls are excluded. See `CallRow` for the TS shape. +Function-scoped call edges, deduped per `(caller_scope, callee_name, call_kind)` per file (`call` vs `new`). **`caller_scope`** is dot-joined enclosing scope (e.g. `UserService.run`). Module-level calls are excluded. Columns include `args_count` (NULL when a spread argument is present), `is_method_call`, `is_constructor_call`, and `is_optional_chain`. See `CallRow`. ### `CallRow` @@ -183,6 +187,10 @@ CSS custom properties (`--token: value`). `scope` is `:root`, `@theme` (Tailwind ## D +### `decorators` (table) + +One row per `@decorator` site on classes, methods, properties, or accessors. `target_symbol_id` links to `symbols(id)` post-insert when resolvable. Powers `find-decorator-usage`. + ### DDL Data Definition Language — the `CREATE TABLE` / `CREATE INDEX` strings in `src/db.ts`. Distinct from **schema** (the conceptual structure) and from **`SCHEMA_VERSION`** (the integer that triggers auto-rebuild on mismatch). @@ -195,6 +203,10 @@ Resolved file-to-file edges derived from `imports.resolved_path`. Composite prim TS shape for one row of the `dependencies` table. +### `dynamic_imports` (table) + +One row per `import()` expression. `source_kind` is `literal` / `template` / `expression`; `resolved_path` filled when literal and resolvable. `in_async_fn` flags dynamic imports inside async functions. Powers `find-dynamic-imports`. + --- ## E @@ -225,7 +237,7 @@ Number of edges _out of_ a file — `COUNT(*) FROM dependencies WHERE from_path ### `files` (table) -Header row for every indexed file. `path` is the primary key; all other tables FK to it with `ON DELETE CASCADE`. See `FileRow`. +Header row for every indexed file. `path` is the primary key; all other tables FK to it with `ON DELETE CASCADE`. Flags: `is_barrel` (100% re-exports, no local value symbols) and `has_side_effects` (module-level call/assignment seen at parse time). See `FileRow`. ### `FileRow` @@ -285,7 +297,7 @@ Symbol or file blast-radius walker. CLI: `codemap impact [--direction u ### `import_specifiers` (table) -Per-specifier breakdown of the `imports.specifiers` JSON blob. One row per imported binding — `imported_name` (original) and `local_name` (renamed via `as`), `kind` in `{named, default, namespace}`, `is_type_only`, column-precise position. Powers specifier-precise rewrites and the `find-import-sites` recipe. +Per-specifier breakdown of the `imports.specifiers` JSON blob. One row per imported binding — or one `kind='side-effect'` row for bare `import "mod"`. Columns include `imported_name`, `local_name`, `kind` in `{named, default, namespace, side-effect}`, `is_type_only`, column-precise position, and `import_id` FK to `imports`. Powers `find-import-sites` and `find-side-effect-imports`. ### `imports` (table) @@ -305,6 +317,22 @@ Public TS shape returned from `Codemap#index()` and `runCodemapIndex()`. Wall-cl --- +## J + +### `jsdoc_tags` (table) + +Structured JSDoc tags parsed from `symbols.doc_comment` — one row per tag per symbol (`@param`, `@throws`, `@returns`, …). FK `symbol_id` → `symbols(id)`. Powers `find-throws-jsdoc`. + +### `jsx_attributes` (table) + +One row per JSX attribute on a `jsx_elements` row. `value_kind` in `{string, expression, boolean, spread, element}`. Join parent via `element_id`. + +### `jsx_elements` (table) + +One row per JSX element or fragment in `.tsx`/`.jsx` files. `parent_element_id` linked in a per-file post-insert pass. `is_fragment = 1` for `<>…`. Powers `find-jsx-usages`. + +--- + ## L ### language adapter @@ -520,7 +548,7 @@ SQLite per-table option enforcing column types at insert time. Every Codemap tab ### `symbols` (table) -Functions / consts / classes / interfaces / types / enums, plus class members (`method`, `property`, `getter`, `setter`). Class members carry `parent_name`. JSDoc tags in `doc_comment` power the `deprecated-symbols` and `visibility-tags` recipes; `members` is JSON for enums. See `SymbolRow`. +Functions / consts / classes / interfaces / types / enums, plus class members (`method`, `property`, `getter`, `setter`). Class members carry `parent_name`. Function-shaped rows may carry `return_type`, `is_async`, and `is_generator`. JSDoc tags in `doc_comment` power the `deprecated-symbols` and `visibility-tags` recipes; structured tags also land in `jsdoc_tags`. `members` is JSON for enums. See `SymbolRow`. ### `SymbolRow` @@ -530,6 +558,10 @@ TS shape for one row of the `symbols` table. ## T +### `try_catch` (table) + +One row per `TryStatement`. Heuristic flags include `catch_logs_only` (catch body only calls `console.*`) and `catch_rethrows`. Powers `find-swallowed-errors`. + ### `test_suites` (table) Test metadata — describe / it / test / suite / context blocks with skip/only/todo flags and detected `framework` in `{vitest, jest, bun-test, node-test, mocha, unknown}`. Framework detection is per-file from imports (mixed-framework codebases handled automatically). `parent_suite_id` resolves nested describes. Powers `find-skipped-tests` + `tests-by-file` recipes. diff --git a/docs/plans/substrate-extraction.md b/docs/plans/substrate-extraction.md index 7f4e5d9d..724de77f 100644 --- a/docs/plans/substrate-extraction.md +++ b/docs/plans/substrate-extraction.md @@ -2,7 +2,7 @@ > **Status:** open · plan iterating in parallel with the broader [`research/codemap-richer-index-synthesis-2026-05.md`](../research/codemap-richer-index-synthesis-2026-05.md) write-engine direction. > -> **Per-tier ship status (fact-checked 2026-05-18):** Tiers **1** and **2** shipped in narrowed form. Tiers **4 / 6 / 9 / 10 / 11 / 12** partially shipped — their foundation tables landed in [`src/db.ts`](../../src/db.ts) but not the full proposed shapes. Tiers **3 (JSX) / 5 (Behavioral) / 7 (CSS rich) / 8 (Project meta) / 13 (ORM/SQL)** are not shipped. Current live schema confirms rows for `calls`, `exports`, `import_specifiers`, `references`, `scopes`, `bindings`, `function_params`, `re_export_chains`, `test_suites`, `runtime_markers`, `file_metrics`, and `module_cycles`; absent tables include `jsx_elements`, `jsx_attributes`, `async_calls`, `try_catch`, `decorators`, `jsdoc_tags`, `css_rules`, `css_at_rules`, `css_declarations`, `tsconfig_options`, `package_json_meta`, `orm_models`, `sql_strings`, and `db_migrations`. +> **Per-tier ship status (fact-checked 2026-05-19):** Tiers **1–6** remainder shipped (`SCHEMA_VERSION` **34**). Tier **1**: call-shape columns, side-effect `import_specifiers` + `import_id`. Tier **2**: `bindings.resolution_kind='re-exported'`. Tier **3**: `jsx_elements` / `jsx_attributes`. Tier **5**: `async_calls`, `try_catch`, `decorators`, `jsdoc_tags`. Tier **4** partial: `symbols.{return_type,is_async,is_generator}`; `generic_params` / `type_predicates` deferred. Tier **6** partial: `dynamic_imports`, `files.{is_barrel,has_side_effects}`; `files.is_entry` deferred to [`c9-plugin-layer.md`](./c9-plugin-layer.md). Tiers **7–13** open. > > **Motivator:** Codemap's distinctive value is the SQL-against-structural-index substrate. Per [Moat B](../roadmap.md#moats-load-bearing) — _"Extracted structure ≥ verdicts. Schema breadth is the substrate every recipe layers on."_ — the load-bearing growth axis is **what oxc / Lightning CSS / config loaders give us that the index doesn't yet expose.** Today the schema captures symbols + imports + exports + calls + components + markers + type*members + css*{variables,classes,keyframes} + suppressions. The AST contains roughly 4× more queryable structure that we discard at parse time. This plan enumerates the entire extraction surface — ~13 tiers spanning identifier references, scope graph, binding resolution, JSX, type-system depth, behavioral facts, module-graph topology, CSS rule structure, test-suite metadata, runtime/dev markers, metrics expansion, and ORM/SQL tracking — and sequences them as independent tracer-bullet PRs that compound into a maximal substrate. Once landed, every recipe / write capability discussed in the synthesis doc (and many more) lights up via SQL JOINs alone, with zero engine work. > @@ -43,7 +43,7 @@ These commit before any PR opens. Questions opened against them must justify aga | R.8 | **No JS execution at extract time.** oxc parses; we walk; we record. Same floor as today's index. No `eval`, no dynamic resolution, no LLM in the box. | [Floors "No JS execution at index time"](../roadmap.md#floors-v1-product-shape) | | R.9 | **No hard size ceiling; soft warn at >5× DB growth.** Empirical measurement on four real fixtures with a minimal `references`-only probe (one of the heaviest single tiers in isolation) showed consistent ~3.6-4.5× DB growth at one tier. Projecting all 13 tiers conservatively: ~5-10× growth. SQLite handles 200-500 MB DBs trivially. Users hitting pain on large monorepos opt out of expensive tiers via R.3 — that's the safety valve, not a global ceiling. | Measured 2026-05-14, four fixtures spanning ~900-2,100 files (see § Operational considerations § Index size growth) | | R.10 | **Latency budget tied to user-visible operations, not DB size.** Soft warn when full reindex > 30s OR targeted reindex > 500ms. Measured worst-case (one tier, largest fixture ~2,100 files / 28k symbols): full ~1.9s, targeted ~15ms. Both ~10-60× under the user-stated bottleneck threshold (1 min full / sub-second targeted). Full 13-tier projection still well under budget. | Measured 2026-05-14 (see § Operational considerations § Reindex performance) | -| R.11 | **Hand-rolled scope walker in the existing oxc visitor.** No library dep. `oxc-parser` explicitly doesn't construct scopes; no NAPI binding for `oxc-semantic` yet. Existing `scopeStack` in `parser.ts` (used for cyclomatic complexity + call-site scope) extends to a full scope graph. Edge cases (TS namespace merge, declaration hoisting, TDZ) handled conservatively. **Status 2026-05-18:** the shipped `bindings.resolution_kind` enum is `same-file` / `imported` / `global` / `unresolved`; the originally proposed `ambiguous` escape valve did not ship. | oxc-parser's `showSemanticErrors` doc explicitly says "the parser does not construct symbols and scopes"; existing `scopeStack` infrastructure in `parser.ts` | +| R.11 | **Hand-rolled scope walker in the existing oxc visitor.** No library dep. `oxc-parser` explicitly doesn't construct scopes; no NAPI binding for `oxc-semantic` yet. Existing `scopeStack` in `parser.ts` (used for cyclomatic complexity + call-site scope) extends to a full scope graph. Edge cases (TS namespace merge, declaration hoisting, TDZ) handled conservatively. **Status 2026-05-19:** the shipped `bindings.resolution_kind` enum is `same-file` / `imported` / `re-exported` / `global` / `unresolved`; the originally proposed `ambiguous` escape valve did not ship. | oxc-parser's `showSemanticErrors` doc explicitly says "the parser does not construct symbols and scopes"; existing `scopeStack` infrastructure in `parser.ts` | | R.12 | **Pre-resolve `bindings` at index time (two-pass).** Pass 1 (per file, in worker): extract refs, scopes, local declarations. Pass 2 (main thread, after all files parsed): walk `references` rows; resolve via same-file scope-walk → `imports` → `exports` → re-export chain; populate `bindings`. Same architecture as today's `resolver.ts` two-pass for `dependencies`. Cost: ~25-50% on top of refs-only reindex (projected worst case ~3-4s full on the largest fixture; well under R.10 budget). Recipes get a single-JOIN `bindings → symbols` instead of recursive-CTE-per-recipe. R.4 cascade extends: single-file reindex deletes that file's `bindings` rows AND any binding referencing symbols in that file. | Existing `resolver.ts` two-pass pattern; `dependencies` table as precedent | | R.13 | **`references.is_write` distinguishes reads from writes.** Boolean column populated by parent-node-shape check during the visitor pass (`AssignmentExpression.left`, `UpdateExpression`, `delete`, `AssignmentPattern`, `VariableDeclarator.id` with initializer, `ForOfStatement.left`, `ForInStatement.left`). Compound assignment (`x += 1`) emits TWO `references` rows — one with `is_write = 0` (the read) and one with `is_write = 1` (the write) — at the same `(file_path, line_start, column_start)`. Substrate honesty: recipes that want a single-row-per-position can `SELECT DISTINCT`. Unlocks immutability audits, side-effect detection, cross-file mutation tracking. | Cost trivial (one column + ~10 lines of visitor logic); recipe-unlock substantial (no other way to express "find writes to X" without external AST walk) | | R.14 | **FTS5 stays file-content-only.** New substrate tables (`references`, `jsx_elements`, `function_params`, `decorators`, `test_suites`, …) are NOT indexed via FTS5 by default. Every `name` / identifier column gets a regular B-tree index, which covers exact match + anchored prefix (`LIKE 'use%'` / `GLOB 'use*'`) at O(log N). FTS5 only helps unanchored substring search; the row counts at every tier remain small enough (~10-500k) that an unanchored `LIKE '%foo%'` scan still completes in tens of milliseconds. Cost saved: ~25-90 MB of FTS5 storage per project across all 13 tiers. Per-tier opt-in path: a tier PR can add FTS5 on its own table when a concrete recipe requires unanchored search — schema-additive, no breaking change. | Existing `source_fts` keeps its current shape (file-content full-text); empirical row-count + B-tree-index-perf argument; substrate stays lean | @@ -193,14 +193,14 @@ Each tier is one tracer-bullet PR: parser visitor change + schema migration + 1- **Goal:** Make `calls` / `exports` / `symbols` / `markers` column-precise; split `imports.specifiers` JSON blob into a typed child table. -**Ship status (fact-checked 2026-05-18):** 4 slices landed, but the live schema is narrower than this tier's original proposal. Present today: `calls.{line_start,column_start,column_end}`, `exports.{line_start,line_end,column_start,column_end,is_re_export}`, `symbols.{name_column_start,name_column_end}`, `markers.{column_start,column_end}`, and `import_specifiers`. Deferred from the proposal: `calls.{args_count,is_method_call,is_constructor_call,is_optional_chain}`, `import_specifiers.import_id`, and side-effect import rows. +**Ship status (fact-checked 2026-05-19):** Tier 1 remainder shipped — `calls.{args_count,is_method_call,is_constructor_call,is_optional_chain}`, side-effect `import_specifiers` rows, and `import_id` FK. Position columns from 2026-05-14 remain. -| Slice | Substrate | Flagship recipe | Schema bump | -| ----- | -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | ----------- | -| 1.A | `calls.{line_start, column_start, column_end}` + `idx_calls_position`; proposed call flags deferred | `find-call-sites` (`--params callee=…`) | 10 → 11 | -| 1.B | `exports.{line_start, line_end, column_start, column_end, is_re_export}` + 2 indexes | `find-export-sites` (`--params name=…`) | 11 → 12 | -| 1.C | `symbols.{name_column_start, name_column_end}` + `markers.{column_start, column_end}` | `find-symbol-definitions` (`--params name=…`) | 12 → 13 | -| 1.D | `import_specifiers` child table (file_path, source, line, column_start/end, imported_name, local_name, kind, is_type_only) + 4 indexes | `find-import-sites` (`--params imported_name=…`) | 13 → 14 | +| Slice | Substrate | Flagship recipe | Schema bump | +| ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------ | ----------- | +| 1.A | `calls.{line_start, column_start, column_end}` + `idx_calls_position`; call-shape flags `{args_count,is_method_call,is_constructor_call,is_optional_chain}` shipped 2026-05-19 | `find-call-sites` (`--params callee=…`) | 10 → 11 | +| 1.B | `exports.{line_start, line_end, column_start, column_end, is_re_export}` + 2 indexes | `find-export-sites` (`--params name=…`) | 11 → 12 | +| 1.C | `symbols.{name_column_start, name_column_end}` + `markers.{column_start, column_end}` | `find-symbol-definitions` (`--params name=…`) | 12 → 13 | +| 1.D | `import_specifiers` child table (file_path, source, line, column_start/end, imported_name, local_name, kind, is_type_only) + 4 indexes | `find-import-sites` (`--params imported_name=…`) | 13 → 14 | **Empirical post-Tier-1 cost** (clean rebuild, median of 3 runs): @@ -278,7 +278,7 @@ New recipe candidates: `dedupe-imports`, `consolidate-type-only-imports`, `stale ### Tier 2 — `references` + `scopes` + `bindings` (the load-bearing tier) — **SHIPPED 2026-05-15** -**Status (fact-checked 2026-05-18):** Tier 2 shipped in narrowed form. `references`, `scopes`, and `bindings` exist and are populated in the live self-index. Current schema uses parser-local scope IDs (`scopes.local_id`, `references.scope_local_id`) and a compact `references.kind IN ('value','type','jsx','member')`; the richer proposed kind taxonomy (`decorator`, `shorthand-*`, `computed-member`, etc.), `bindings.namespace`, and `resolution_kind='re-exported'` remain deferred. Params and re-export chains shipped as separate foundation tables (`function_params`, `re_export_chains`) rather than the exact Tier 2 DDL below. +**Status (fact-checked 2026-05-19):** Tier 2 shipped including `bindings.resolution_kind='re-exported'` (2026-05-19). `references`, `scopes`, and `bindings` populated. Richer proposed kind taxonomy (`decorator`, `shorthand-*`, …) and `bindings.namespace` remain deferred. **Goal:** Every identifier _use_ — call, type position, JSX, decorator, shorthand, member access, spread — becomes a queryable row. Plus a lexical scope graph and per-reference binding resolution to the originating symbol. @@ -419,7 +419,7 @@ Both numbers are well within the plan's thresholds (full < 1 min, targeted < 100 What landed (SCHEMA_VERSION 16 → 17): -- **`bindings` table** — `(reference_id, resolved_symbol_id, resolution_kind, is_external)`. PK on `reference_id`. `resolution_kind` enum: `same-file` / `imported` / `global` / `unresolved`. `re-exported` deferred to Tier 6. +- **`bindings` table** — `(reference_id, resolved_symbol_id, resolution_kind, is_external)`. PK on `reference_id`. `resolution_kind` enum: `same-file` / `imported` / `global` / `unresolved` at initial ship; `re-exported` shipped 2026-05-19 (Tier 6 rollout). - **`symbols.scope_local_id`** column — captured BEFORE the symbol's own scope is pushed (so it points at the declaring scope, not the body). Class members anchor to their class's pushed scope. - **`resolveBindings`** engine (`src/application/bindings-engine.ts`) — two-phase: one SELECT per table into in-memory Maps, then per-reference resolution via scope-walk → imports → globals → unresolved. ~300ms for ~127k refs. - **Cross-file resolution** uses `imports.resolved_path` (not `dependencies`, which lacks the module specifier). When `imp.imported_name` matches an export and the target file has a module-scope symbol of the same name → `is_external=0` with a real symbol id. Non-indexed module → `is_external=1`. @@ -526,7 +526,7 @@ Deferred to a future slice (out of Tier 2 scope): ### Tier 3 — JSX elements + attributes -**Ship status (2026-05-15):** Not shipped. `jsx_elements` / `jsx_attributes` absent from [`src/db.ts`](../../src/db.ts). Open. +**Ship status (2026-05-19):** Shipped. `jsx_elements` / `jsx_attributes` in [`src/db.ts`](../../src/db.ts); extractor [`src/extractors/jsx.ts`](../../src/extractors/jsx.ts); recipe `find-jsx-usages`. **Goal:** Every JSX element + every JSX attribute becomes a queryable row with column-precise positions. @@ -602,7 +602,7 @@ New recipe candidates: `rename-component` (alongside `rename-app-wide`); `migrat ### Tier 4 — Type / signature depth (params, generics, predicates) — **PARTIAL (2026-05-15)** -**Ship status (2026-05-15):** `function_params` table shipped via Tier 2.2 (different keying — `(file_path, owner_name, owner_kind, position)` instead of `symbol_id`-FK; columns `name` / `type_text` / `default_text` / `is_rest` / `is_optional` + position triplet). Params also emit as `symbols` rows with `kind='param'` so cross-file binding resolution works. **Deferred:** `generic_params` table (type-params currently emit as `symbols.kind='type-param'` instead — adequate for binding resolution; structured constraint/default columns deferred); `type_predicates` table; `symbols.{return_type, is_async, is_generator, throws_clauses}` columns. Recipes that need per-param JOINs work today against the shipped `function_params`; recipes needing predicates / async / return-type / generics-with-constraints stay open. +**Ship status (2026-05-19):** `function_params` table shipped via Tier 2.2 (different keying — `(file_path, owner_name, owner_kind, position)` instead of `symbol_id`-FK; columns `name` / `type_text` / `default_text` / `is_rest` / `is_optional` + position triplet). Params also emit as `symbols` rows with `kind='param'` so cross-file binding resolution works. **`symbols.{return_type,is_async,is_generator}`** shipped 2026-05-19. **Deferred:** `generic_params` table (type-params currently emit as `symbols.kind='type-param'` instead — adequate for binding resolution; structured constraint/default columns deferred); `type_predicates` table; `symbols.throws_clauses`. Recipes that need per-param JOINs work today against the shipped `function_params`; recipes needing predicates / generics-with-constraints stay open. **Goal:** Function parameters + generic parameters + type predicates + return types become structured queryable facts, not just stringified into `symbols.signature`. @@ -684,7 +684,7 @@ New recipe candidates: `swap-positional-to-named-args` (extends `rename-preview` ### Tier 5 — Behavioral facts (async, try/catch, decorators, structured JSDoc) -**Ship status (2026-05-15):** Not shipped. `async_calls` / `try_catch` / `decorators` / `jsdoc_tags` absent from [`src/db.ts`](../../src/db.ts). Open. +**Ship status (2026-05-19):** Shipped. Tables + [`src/extractors/behavioral.ts`](../../src/extractors/behavioral.ts); recipes `find-await-in-loop`, `find-swallowed-errors`, `find-decorator-usage`, `find-throws-jsdoc`. **Goal:** Capture runtime-shape behavioral facts the AST encodes but today's index discards. @@ -787,9 +787,9 @@ New recipe candidates: `find-awaits-in-loops`; `find-empty-catches`; `find-depre --- -### Tier 6 — Module-graph enrichment — **PARTIAL (2026-05-15)** +### Tier 6 — Module-graph enrichment — **PARTIAL (2026-05-19)** -**Ship status (2026-05-15):** `re_export_chains` shipped via Tier 2.2 (slimmer shape — `(from_file, from_name, to_file, to_name, hops, truncated)` `WITHOUT ROWID` PK; no separate `chain_path` text). Bounded at 10 hops with cycle detection. `bindings-engine` walks chains for cross-file resolution. **Deferred:** `dynamic_imports` table; `files.{is_barrel, is_entry, has_side_effects}` columns. `files.is_entry` stays gated on the [`c9-plugin-layer.md`](./c9-plugin-layer.md) plan. +**Ship status (2026-05-19):** `re_export_chains`, `dynamic_imports`, `files.{is_barrel,has_side_effects}` shipped. **Deferred:** `files.is_entry` ([`c9-plugin-layer.md`](./c9-plugin-layer.md)). **Goal:** Flatten re-export chains; record dynamic imports; mark barrel files. diff --git a/docs/research/codemap-richer-index-synthesis-2026-05.md b/docs/research/codemap-richer-index-synthesis-2026-05.md index 8f052b9e..26e925cc 100644 --- a/docs/research/codemap-richer-index-synthesis-2026-05.md +++ b/docs/research/codemap-richer-index-synthesis-2026-05.md @@ -10,19 +10,20 @@ --- -## What shipped (fact-checked 2026-05-18) — appendix per § 9 lifecycle +## What shipped (fact-checked 2026-05-19) — appendix per § 9 lifecycle The substrate-growth half of this synthesis lifted to a dedicated plan PR — [`plans/substrate-extraction.md`](../plans/substrate-extraction.md) — which generalised § 4.1 / § 4.2 / § 5.3 items 1, 3 into a 13-tier sequenced plan. Per § 9's discipline ("when the synthesis path ships any step, add a 'What shipped' appendix; slim duplicated prose"), the canonical live status is **the substrate plan's per-tier headings**, not this note. **Shipped via the substrate plan:** -- **Synthesis Step 5** (`calls.{line_start, column_start, column_end}`) — shipped as substrate plan **Tier 1 Slice 1.A**. Proposed call metadata (`args_count`, `is_method_call`, `is_constructor_call`, `is_optional_chain`) is not in the live schema. +- **Synthesis Step 5** (`calls.{line_start, column_start, column_end}`) — shipped as substrate plan **Tier 1 Slice 1.A**. Call metadata (`args_count`, `is_method_call`, `is_constructor_call`, `is_optional_chain`) shipped 2026-05-19. - **Synthesis Step 7** (`exports.{line_start, line_end, column_start, column_end, is_re_export}`) — shipped as substrate plan **Tier 1 Slice 1.B**. - **§ 4.1 column anchoring on `symbols` / `imports` / `markers`** ("Deferred (incremental)") — shipped as substrate plan **Tier 1 Slices 1.C / 1.D**. -- **§ 4.2 `import_specifiers` child table** — shipped as substrate plan **Tier 1 Slice 1.D**, with the live schema keyed by `file_path`/`source` rather than the originally proposed `import_id` FK. -- **§ 4.2 generalised `references` + `scopes` + `bindings` + `symbol_namespace`** ("Deferred — defer until ≥3 narrower position tables prove demand") — the trigger fired with Tier 1 landing four position-precise surfaces; lifted to substrate plan **Tier 2** and shipped in narrowed form. Live schema has `references.kind IN ('value','type','jsx','member')` and `bindings.resolution_kind IN ('same-file','imported','global','unresolved')`; richer namespaces / re-export resolution kinds remain deferred. +- **§ 4.2 `import_specifiers` child table** — shipped as substrate plan **Tier 1 Slice 1.D**, including `import_id` FK and `kind='side-effect'` rows (2026-05-19). +- **§ 4.2 generalised `references` + `scopes` + `bindings` + `symbol_namespace`** ("Deferred — defer until ≥3 narrower position tables prove demand") — the trigger fired with Tier 1 landing four position-precise surfaces; lifted to substrate plan **Tier 2** and shipped in narrowed form. Live schema has `references.kind IN ('value','type','jsx','member')` and `bindings.resolution_kind IN ('same-file','imported','re-exported','global','unresolved')`; richer `bindings.namespace` remains deferred. - **§ 5.3 leverage-ranked items 1 + 3** — shipped via Tiers 1 + 2. -- **Partial ship** of substrate plan Tiers 4 / 6 / 9 / 10 / 11 / 12 — foundation tables landed (`function_params` / `re_export_chains` / `test_suites` / `runtime_markers` / `file_metrics` / `module_cycles`); deferred bits stay tracked under each tier's heading. +- **Substrate plan Tiers 1–6 (2026-05-19)** — remainder shipped: JSX (`jsx_elements` / `jsx_attributes`), behavioral (`async_calls`, `try_catch`, `decorators`, `jsdoc_tags`), `symbols.{return_type,is_async,is_generator}`, `dynamic_imports`, `files.{is_barrel,has_side_effects}`. **`files.is_entry`** deferred to [`plans/c9-plugin-layer.md`](../plans/c9-plugin-layer.md). +- **Partial ship** of substrate plan Tiers 9 / 10 / 11 / 12 — foundation tables landed (`test_suites` / `runtime_markers` / `file_metrics` / `module_cycles`); deferred bits stay tracked under each tier's heading. Tier 4 partial: `function_params` shipped; `generic_params` / `type_predicates` deferred. **Still open (the apply-engine half of this synthesis):** diff --git a/docs/roadmap.md b/docs/roadmap.md index 9841bb59..037de3db 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -29,7 +29,7 @@ Codemap stays a structural-index primitive that other tools can consume. Two lay Every PR reviewer defends these. The reviewer tests embedded below are the canonical filters for any new verb / column / engine. - **A. SQL is the API.** Every capability is a recipe (saved query) or a primitive recipes can compose — never a pre-baked verdict. SQL is a durable, well-known query language; agents compose any predicate without us deciding which questions are important. The moment a CLI verb returns `pass`/`fail` _without_ a recipe form behind it, the moat erodes — the tool becomes "yet another linter with opinions baked in" instead of "the database your agent queries." **Verdicts are an OUTPUT mode** (e.g. `--format sarif`, `audit --base ` deltas), never a primitive. **Reviewer test for any new verb:** "is this also expressible as `query --recipe `?" -- **B. Extracted structure ≥ verdicts.** Schema breadth is the substrate every recipe layers on. CSS (`css_variables` / `css_classes` / `css_keyframes`), `markers`, `type_members`, `calls.caller_scope`, `components.hooks_used`, the substrate-extraction tier (`scopes` / `references` / `bindings` / `function_params` / `runtime_markers` / `test_suites` / `re_export_chains` / `module_cycles` / `file_metrics` / `import_specifiers`) — these are codemap-specific extractions; their richness directly determines what JOINs are expressible and which agent questions get clean answers. Slimming the schema for theoretical perf / simplicity is a regression unless the column is empirically unread. **Reviewer test for any "drop column X" PR:** "what recipe (bundled or hypothetical) does this kill?" +- **B. Extracted structure ≥ verdicts.** Schema breadth is the substrate every recipe layers on. CSS (`css_variables` / `css_classes` / `css_keyframes`), `markers`, `type_members`, `calls.caller_scope`, `components.hooks_used`, the substrate-extraction tier (`scopes` / `references` / `bindings` / `function_params` / `runtime_markers` / `test_suites` / `re_export_chains` / `module_cycles` / `file_metrics` / `import_specifiers` / `jsx_elements` / `jsx_attributes` / `async_calls` / `try_catch` / `decorators` / `jsdoc_tags` / `dynamic_imports`) — these are codemap-specific extractions; their richness directly determines what JOINs are expressible and which agent questions get clean answers. Slimming the schema for theoretical perf / simplicity is a regression unless the column is empirically unread. **Reviewer test for any "drop column X" PR:** "what recipe (bundled or hypothetical) does this kill?" ### Floors (v1 product-shape) diff --git a/fixtures/benchmark/perf-baseline.json b/fixtures/benchmark/perf-baseline.json index 64f2d5d1..c10c228d 100644 --- a/fixtures/benchmark/perf-baseline.json +++ b/fixtures/benchmark/perf-baseline.json @@ -1,13 +1,13 @@ { - "captured_at": "2026-05-17T19:43:00.997Z", - "commit": "cc8daed", + "captured_at": "2026-05-20T08:23:42.000Z", + "commit": "75a1a65", "phases": { - "collect_ms": 14, - "parse_ms": 435, - "insert_ms": 170, - "index_create_ms": 97, - "bindings_ms": 130, - "total_ms": 866 + "collect_ms": 18, + "parse_ms": 484, + "insert_ms": 213, + "index_create_ms": 104, + "bindings_ms": 136, + "total_ms": 971 }, "regression_pct": 25, "noise_floor_ms": 10 diff --git a/fixtures/db/schema-v27.sql b/fixtures/db/schema-v27.sql new file mode 100644 index 00000000..2c5adc03 --- /dev/null +++ b/fixtures/db/schema-v27.sql @@ -0,0 +1,456 @@ +-- Frozen DDL from main @ SCHEMA_VERSION 27 (for v27→34 rebuild tests in db.test.ts). + +CREATE TABLE IF NOT EXISTS files ( + path TEXT PRIMARY KEY, + content_hash TEXT NOT NULL, + size INTEGER NOT NULL, + line_count INTEGER NOT NULL, + language TEXT NOT NULL, + last_modified INTEGER NOT NULL, + indexed_at INTEGER NOT NULL + ) STRICT; + + CREATE TABLE IF NOT EXISTS symbols ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, + name TEXT NOT NULL, + kind TEXT NOT NULL, + line_start INTEGER NOT NULL, + line_end INTEGER NOT NULL, + signature TEXT NOT NULL, + is_exported INTEGER NOT NULL DEFAULT 0, + is_default_export INTEGER NOT NULL DEFAULT 0, + members TEXT, + doc_comment TEXT, + value TEXT, + parent_name TEXT, + visibility TEXT, + complexity REAL, + name_column_start INTEGER NOT NULL DEFAULT 0, + name_column_end INTEGER NOT NULL DEFAULT 0, + scope_local_id INTEGER NOT NULL DEFAULT 0, + body_line_count INTEGER, + param_count INTEGER, + nesting_depth INTEGER + ) STRICT; + + -- One row per indexed file. Pure counters from the AST walk. + -- Joins to files(path). + CREATE TABLE IF NOT EXISTS file_metrics ( + file_path TEXT PRIMARY KEY REFERENCES files(path) ON DELETE CASCADE, + total_lines INTEGER NOT NULL, + code_lines INTEGER NOT NULL, + blank_lines INTEGER NOT NULL, + comment_lines INTEGER NOT NULL, + let_count INTEGER NOT NULL DEFAULT 0, + const_count INTEGER NOT NULL DEFAULT 0, + var_count INTEGER NOT NULL DEFAULT 0, + function_count INTEGER NOT NULL DEFAULT 0, + arrow_count INTEGER NOT NULL DEFAULT 0, + class_count INTEGER NOT NULL DEFAULT 0, + interface_count INTEGER NOT NULL DEFAULT 0, + export_count INTEGER NOT NULL DEFAULT 0 + ) STRICT; + + CREATE TABLE IF NOT EXISTS imports ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, + source TEXT NOT NULL, + resolved_path TEXT, + specifiers TEXT NOT NULL, + is_type_only INTEGER NOT NULL DEFAULT 0, + line_number INTEGER NOT NULL + ) STRICT; + + CREATE TABLE IF NOT EXISTS exports ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, + name TEXT NOT NULL, + kind TEXT NOT NULL, + is_default INTEGER NOT NULL DEFAULT 0, + re_export_source TEXT, + line_start INTEGER NOT NULL, + line_end INTEGER NOT NULL, + column_start INTEGER NOT NULL, + column_end INTEGER NOT NULL, + is_re_export INTEGER NOT NULL DEFAULT 0 + ) STRICT; + + CREATE TABLE IF NOT EXISTS components ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, + name TEXT NOT NULL, + props_type TEXT, + hooks_used TEXT NOT NULL, + is_default_export INTEGER NOT NULL DEFAULT 0 + ) STRICT; + + CREATE TABLE IF NOT EXISTS dependencies ( + from_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, + to_path TEXT NOT NULL, + PRIMARY KEY (from_path, to_path) + ) STRICT, WITHOUT ROWID; + + CREATE TABLE IF NOT EXISTS markers ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, + line_number INTEGER NOT NULL, + kind TEXT NOT NULL, + content TEXT NOT NULL, + column_start INTEGER NOT NULL DEFAULT 0, + column_end INTEGER NOT NULL DEFAULT 0 + ) STRICT; + + CREATE TABLE IF NOT EXISTS css_variables ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, + name TEXT NOT NULL, + value TEXT, + scope TEXT NOT NULL, + line_number INTEGER NOT NULL + ) STRICT; + + CREATE TABLE IF NOT EXISTS css_classes ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, + name TEXT NOT NULL, + is_module INTEGER NOT NULL DEFAULT 0, + line_number INTEGER NOT NULL + ) STRICT; + + CREATE TABLE IF NOT EXISTS css_keyframes ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, + name TEXT NOT NULL, + line_number INTEGER NOT NULL + ) STRICT; + + CREATE TABLE IF NOT EXISTS calls ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, + caller_name TEXT NOT NULL, + caller_scope TEXT NOT NULL, + callee_name TEXT NOT NULL, + line_start INTEGER NOT NULL, + column_start INTEGER NOT NULL, + column_end INTEGER NOT NULL + ) STRICT; + + CREATE TABLE IF NOT EXISTS type_members ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, + symbol_name TEXT NOT NULL, + name TEXT NOT NULL, + type TEXT, + is_optional INTEGER NOT NULL DEFAULT 0, + is_readonly INTEGER NOT NULL DEFAULT 0 + ) STRICT; + + -- Lexical scope graph per R.11. Block/for/catch deferred — body refs + -- resolve to the enclosing function/method scope (conservative escape + -- valve). local_id is parser-assigned so refs avoid SQLite rowid + -- round-trips. + CREATE TABLE IF NOT EXISTS scopes ( + file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, + local_id INTEGER NOT NULL, + kind TEXT NOT NULL CHECK (kind IN ('module','function','arrow','class','method','interface','type-alias','for','catch')), + parent_local_id INTEGER, + line_start INTEGER NOT NULL, + line_end INTEGER NOT NULL, + owner_symbol_name TEXT, + PRIMARY KEY (file_path, local_id) + ) STRICT, WITHOUT ROWID; + + -- Identifier USEs per R.11 (kinds: value/type/jsx). is_write per R.13. + -- Compound assign emits two rows, declaration-with-init emits write + -- only. scope_local_id joins scopes(local_id), 0 = module. + CREATE TABLE IF NOT EXISTS "references" ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, + name TEXT NOT NULL, + line_start INTEGER NOT NULL, + column_start INTEGER NOT NULL, + column_end INTEGER NOT NULL, + kind TEXT NOT NULL CHECK (kind IN ('value','type','jsx','member')), + scope_local_id INTEGER NOT NULL DEFAULT 0, + is_write INTEGER NOT NULL DEFAULT 0 + ) STRICT; + + -- Per R.12. resolved_symbol_id NULL when is_external/global/unresolved. + -- Re-export chain walk defers to Tier 6. + CREATE TABLE IF NOT EXISTS bindings ( + reference_id INTEGER PRIMARY KEY REFERENCES "references"(id) ON DELETE CASCADE, + resolved_symbol_id INTEGER REFERENCES symbols(id) ON DELETE SET NULL, + resolution_kind TEXT NOT NULL CHECK (resolution_kind IN ( + 'same-file','imported','global','unresolved' + )), + is_external INTEGER NOT NULL DEFAULT 0 + ) STRICT, WITHOUT ROWID; + + -- Test suite metadata: describe / it / test / suite blocks with + -- their hierarchy + skip/only/todo flags. framework is detected + -- from imports (vitest / jest / bun-test / node-test / mocha) and + -- defaults to 'unknown' when no test framework import is found + -- in the file. parent_suite_id is NULL for top-level blocks. + CREATE TABLE IF NOT EXISTS test_suites ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, + name TEXT NOT NULL, + kind TEXT NOT NULL CHECK (kind IN ('describe','it','test','suite','context')), + line_start INTEGER NOT NULL, + line_end INTEGER NOT NULL, + parent_suite_id INTEGER REFERENCES test_suites(id) ON DELETE CASCADE, + is_skipped INTEGER NOT NULL DEFAULT 0, + is_only INTEGER NOT NULL DEFAULT 0, + is_todo INTEGER NOT NULL DEFAULT 0, + framework TEXT NOT NULL CHECK (framework IN ('vitest','jest','bun-test','node-test','mocha','unknown')) + ) STRICT; + + -- Runtime markers — operational signals worth auditing: console + -- calls, debugger statements, raw throws, process.env reads. detail + -- is the qualifier (console.log → 'log', throw → expression text, + -- process.env.X → 'X'). + CREATE TABLE IF NOT EXISTS runtime_markers ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, + kind TEXT NOT NULL CHECK (kind IN ('console','debugger','throw','process-env')), + line_start INTEGER NOT NULL, + column_start INTEGER NOT NULL, + column_end INTEGER NOT NULL, + detail TEXT, + scope_local_id INTEGER NOT NULL DEFAULT 0 + ) STRICT; + + -- First-class parameter rows: one row per leaf parameter binding, + -- ordered by position. Keyed by (file_path, owner_name, owner_kind) + -- to disambiguate same-name functions vs methods in the same file. + -- type_text is the stringified annotation. default_text is the raw + -- default expression source (NULL when there is no default). + CREATE TABLE IF NOT EXISTS function_params ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, + owner_name TEXT NOT NULL, + owner_kind TEXT NOT NULL, + position INTEGER NOT NULL, + name TEXT NOT NULL, + type_text TEXT, + default_text TEXT, + is_rest INTEGER NOT NULL DEFAULT 0, + is_optional INTEGER NOT NULL DEFAULT 0, + line_start INTEGER NOT NULL, + column_start INTEGER NOT NULL, + column_end INTEGER NOT NULL + ) STRICT; + + -- Materialised re-export chains. One row per (from_file, from_name) + -- pointing at the terminal definition site after walking through + -- barrel files (bounded at 10 hops). Same engine as bindings-engine + -- exposes the walk to ad-hoc SQL. + CREATE TABLE IF NOT EXISTS re_export_chains ( + from_file TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, + from_name TEXT NOT NULL, + to_file TEXT NOT NULL, + to_name TEXT NOT NULL, + hops INTEGER NOT NULL, + truncated INTEGER NOT NULL DEFAULT 0, + PRIMARY KEY (from_file, from_name) + ) STRICT, WITHOUT ROWID; + + -- Strongly-connected component (SCC) of the import dependency graph. + -- Only cyclic files appear here. Files sharing cycle_id import each + -- other directly or transitively. Computed via Tarjan's SCC on + -- dependencies after the full index pass. + CREATE TABLE IF NOT EXISTS module_cycles ( + file_path TEXT PRIMARY KEY REFERENCES files(path) ON DELETE CASCADE, + cycle_id INTEGER NOT NULL, + cycle_size INTEGER NOT NULL + ) STRICT; + + -- Per-specifier breakdown of imports.specifiers JSON blob. Recipes that + -- want specifier-precise rewrites (rename specifier, dedupe, type-only + -- migrate) JOIN this table. The original imports.specifiers JSON stays + -- in place as a v1 convenience surface. + CREATE TABLE IF NOT EXISTS import_specifiers ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, + source TEXT NOT NULL, + line INTEGER NOT NULL, + column_start INTEGER NOT NULL, + column_end INTEGER NOT NULL, + imported_name TEXT NOT NULL, + local_name TEXT NOT NULL, + kind TEXT NOT NULL CHECK (kind IN ('named','default','namespace')), + is_type_only INTEGER NOT NULL DEFAULT 0 + ) STRICT; + + -- Opt-in suppressions — recipes LEFT JOIN to honor, ad-hoc SQL unaffected. + -- line_number > 0 = next-line scope (suppressed line). 0 = file scope. + -- Sourced from // codemap-ignore-{next-line,file} directives (see markers.ts). + CREATE TABLE IF NOT EXISTS suppressions ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, + line_number INTEGER NOT NULL, + recipe_id TEXT NOT NULL + ) STRICT; + + CREATE TABLE IF NOT EXISTS meta ( + key TEXT PRIMARY KEY, + value TEXT + ) STRICT, WITHOUT ROWID; + + -- User-data table: query result snapshots for --save-baseline / --baseline. + -- Lives next to the index tables so the entire codemap state is one SQLite file + -- (no parallel JSON files / new gitignore entries). Intentionally absent from + -- dropAll() so --full and SCHEMA_VERSION rebuilds preserve baselines (only + -- index tables get dropped). Future schema bumps that change THIS tables shape + -- need an in-place migration rather than relying on the schema-mismatch rebuild. + CREATE TABLE IF NOT EXISTS query_baselines ( + name TEXT PRIMARY KEY, + recipe_id TEXT, + sql TEXT NOT NULL, + rows_json TEXT NOT NULL, + row_count INTEGER NOT NULL, + git_ref TEXT, + created_at INTEGER NOT NULL + ) STRICT; + + -- User-data table: static coverage snapshots ingested via codemap ingest-coverage + -- (Istanbul coverage-final.json + LCOV lcov.info, written by every modern test + -- runner). Joins to symbols on the natural key (file_path, name, line_start) — + -- intentionally NOT a FK to symbols.id, because dropAll() drops symbols on every + -- --full reindex and the recreated rows get fresh AUTOINCREMENT ids. Natural-key + -- rows survive that churn. Like query_baselines, intentionally excluded from + -- dropAll() so a --full rebuild doesn't nuke the user's last ingest. Orphan + -- cleanup (file deleted from project) lives at the end of every ingest in + -- application/coverage-engine.ts, not here. See docs/plans/coverage-ingestion.md + -- (D6) for the unwind on why CASCADE was rejected. + CREATE TABLE IF NOT EXISTS coverage ( + file_path TEXT NOT NULL, + name TEXT NOT NULL, + line_start INTEGER NOT NULL, + coverage_pct REAL, + hit_statements INTEGER NOT NULL, + total_statements INTEGER NOT NULL, + PRIMARY KEY (file_path, name, line_start) + ) STRICT, WITHOUT ROWID; + + -- User-data table: per-recipe last_run_at + run_count for agent-host + -- ranking. Joined inline into --recipes-json / codemap://recipes via + -- loadRecipeRecency. Like query_baselines / coverage, intentionally absent + -- from dropAll() so --full and SCHEMA_VERSION rebuilds preserve activity + -- history. 90-day window is eager-on-write (recordRecipeRun DELETEs stale + -- rows before its upsert) — reads stay pure. recipe_id is loose (no FK, + -- can match bundled or project recipe ids). See docs/architecture.md. + CREATE TABLE IF NOT EXISTS recipe_recency ( + recipe_id TEXT PRIMARY KEY, + last_run_at INTEGER NOT NULL, + run_count INTEGER NOT NULL DEFAULT 1 + ) STRICT, WITHOUT ROWID; + + -- Config-derived: reconcileBoundaryRules clears and re-fills from + -- .codemap/config boundaries on every index pass. Dropped on --full + -- like the other index tables (unlike query_baselines / coverage which + -- are user data and persist). Joined against dependencies by the + -- bundled boundary-violations recipe. + CREATE TABLE IF NOT EXISTS boundary_rules ( + name TEXT PRIMARY KEY, + from_glob TEXT NOT NULL, + to_glob TEXT NOT NULL, + action TEXT NOT NULL CHECK (action IN ('deny', 'allow')) + ) STRICT, WITHOUT ROWID; + +-- Covering indexes: include columns returned by common queries to avoid table lookups + CREATE INDEX IF NOT EXISTS idx_symbols_name ON symbols(name, kind, file_path, line_start, line_end, signature, is_exported); + CREATE INDEX IF NOT EXISTS idx_symbols_kind ON symbols(kind, is_exported, name, file_path); + CREATE INDEX IF NOT EXISTS idx_symbols_file ON symbols(file_path); + + -- Partial indexes: subset indexes for common filtered AI agent queries + CREATE INDEX IF NOT EXISTS idx_symbols_exported ON symbols(name, kind, file_path, signature) + WHERE is_exported = 1; + CREATE INDEX IF NOT EXISTS idx_symbols_functions ON symbols(name, file_path, line_start, line_end, signature) + WHERE kind = 'function'; + CREATE INDEX IF NOT EXISTS idx_symbols_visibility ON symbols(visibility, file_path, name, line_start) + WHERE visibility IS NOT NULL; + + CREATE INDEX IF NOT EXISTS idx_imports_source ON imports(source, file_path); + CREATE INDEX IF NOT EXISTS idx_imports_resolved ON imports(resolved_path, file_path); + CREATE INDEX IF NOT EXISTS idx_imports_file ON imports(file_path); + + CREATE INDEX IF NOT EXISTS idx_exports_name ON exports(name, file_path, kind, is_default); + CREATE INDEX IF NOT EXISTS idx_exports_file ON exports(file_path); + CREATE INDEX IF NOT EXISTS idx_exports_position ON exports(file_path, line_start); + CREATE INDEX IF NOT EXISTS idx_exports_re_export ON exports(is_re_export, file_path); + + CREATE INDEX IF NOT EXISTS idx_components_name ON components(name, file_path, props_type, hooks_used); + CREATE INDEX IF NOT EXISTS idx_components_file ON components(file_path, name); + + -- WITHOUT ROWID tables already have a clustered PK — this covers reverse lookups + CREATE INDEX IF NOT EXISTS idx_dependencies_to ON dependencies(to_path, from_path); + + CREATE INDEX IF NOT EXISTS idx_markers_kind ON markers(kind, file_path, line_number, content); + CREATE INDEX IF NOT EXISTS idx_markers_file ON markers(file_path); + + -- Suppressions: most recipe LEFT JOINs key on (recipe_id, file_path[, line_number]). + CREATE INDEX IF NOT EXISTS idx_suppressions_lookup ON suppressions(recipe_id, file_path, line_number); + CREATE INDEX IF NOT EXISTS idx_suppressions_file ON suppressions(file_path); + + CREATE INDEX IF NOT EXISTS idx_css_variables_name ON css_variables(name, value, scope, file_path); + CREATE INDEX IF NOT EXISTS idx_css_variables_file ON css_variables(file_path); + CREATE INDEX IF NOT EXISTS idx_css_classes_name ON css_classes(name, file_path, is_module); + CREATE INDEX IF NOT EXISTS idx_css_classes_file ON css_classes(file_path); + CREATE INDEX IF NOT EXISTS idx_css_keyframes_name ON css_keyframes(name, file_path); + + CREATE INDEX IF NOT EXISTS idx_type_members_symbol ON type_members(symbol_name, file_path, name, type, is_optional, is_readonly); + CREATE INDEX IF NOT EXISTS idx_type_members_file ON type_members(file_path); + + CREATE INDEX IF NOT EXISTS idx_scopes_parent ON scopes(file_path, parent_local_id); + CREATE INDEX IF NOT EXISTS idx_scopes_kind ON scopes(kind, file_path); + CREATE INDEX IF NOT EXISTS idx_scopes_owner ON scopes(owner_symbol_name, file_path); + + CREATE INDEX IF NOT EXISTS idx_references_name ON "references"(name, file_path); + CREATE INDEX IF NOT EXISTS idx_references_file ON "references"(file_path, line_start); + CREATE INDEX IF NOT EXISTS idx_references_kind ON "references"(kind, file_path); + CREATE INDEX IF NOT EXISTS idx_references_writes ON "references"(name, is_write) WHERE is_write = 1; + + CREATE INDEX IF NOT EXISTS idx_bindings_resolved ON bindings(resolved_symbol_id); + CREATE INDEX IF NOT EXISTS idx_bindings_kind ON bindings(resolution_kind); + + CREATE INDEX IF NOT EXISTS idx_module_cycles_cid ON module_cycles(cycle_id); + CREATE INDEX IF NOT EXISTS idx_module_cycles_size ON module_cycles(cycle_size); + + CREATE INDEX IF NOT EXISTS idx_re_export_chains_to ON re_export_chains(to_file, to_name); + CREATE INDEX IF NOT EXISTS idx_re_export_chains_truncated ON re_export_chains(truncated) WHERE truncated = 1; + + CREATE INDEX IF NOT EXISTS idx_function_params_owner ON function_params(file_path, owner_name); + CREATE INDEX IF NOT EXISTS idx_function_params_name ON function_params(name); + CREATE INDEX IF NOT EXISTS idx_function_params_type ON function_params(type_text) WHERE type_text IS NOT NULL; + + CREATE INDEX IF NOT EXISTS idx_runtime_markers_kind ON runtime_markers(kind); + CREATE INDEX IF NOT EXISTS idx_runtime_markers_file ON runtime_markers(file_path); + CREATE INDEX IF NOT EXISTS idx_runtime_markers_detail ON runtime_markers(detail) WHERE detail IS NOT NULL; + + CREATE INDEX IF NOT EXISTS idx_test_suites_file ON test_suites(file_path); + CREATE INDEX IF NOT EXISTS idx_test_suites_kind ON test_suites(kind); + CREATE INDEX IF NOT EXISTS idx_test_suites_parent ON test_suites(parent_suite_id); + CREATE INDEX IF NOT EXISTS idx_test_suites_skipped ON test_suites(is_skipped) WHERE is_skipped = 1; + + CREATE INDEX IF NOT EXISTS idx_import_specifiers_imported ON import_specifiers(imported_name, file_path); + CREATE INDEX IF NOT EXISTS idx_import_specifiers_local ON import_specifiers(local_name, file_path); + CREATE INDEX IF NOT EXISTS idx_import_specifiers_file ON import_specifiers(file_path, line); + CREATE INDEX IF NOT EXISTS idx_import_specifiers_source ON import_specifiers(source, file_path); + + CREATE INDEX IF NOT EXISTS idx_calls_caller ON calls(caller_name, file_path); + CREATE INDEX IF NOT EXISTS idx_calls_scope ON calls(caller_scope, file_path, callee_name); + CREATE INDEX IF NOT EXISTS idx_calls_callee ON calls(callee_name, file_path); + CREATE INDEX IF NOT EXISTS idx_calls_file ON calls(file_path); + CREATE INDEX IF NOT EXISTS idx_calls_position ON calls(file_path, line_start); + + -- Mirrors the typical join shape symbols.(file_path, name, line_start). + -- The (file_path, name) prefix also covers GROUP BY file_path scans + -- used by the bundled files-by-coverage recipe (D2 + D13). + CREATE INDEX IF NOT EXISTS idx_coverage_file_name ON coverage(file_path, name); + + -- Powers the lazy 90-day prune (DELETE WHERE last_run_at < cutoff) inside + -- loadRecipeRecency. Tiny table (one row per known recipe id) — index keeps + -- the prune predictable as project-recipe counts grow. + CREATE INDEX IF NOT EXISTS idx_recipe_recency_last_run ON recipe_recency(last_run_at); diff --git a/fixtures/golden/minimal/barrel-files.json b/fixtures/golden/minimal/barrel-files.json index 64d6f363..0121695a 100644 --- a/fixtures/golden/minimal/barrel-files.json +++ b/fixtures/golden/minimal/barrel-files.json @@ -7,6 +7,10 @@ "file_path": "src/components/shop/index.ts", "exports": 4 }, + { + "file_path": "src/lib/complexity-fixture.ts", + "exports": 4 + }, { "file_path": "src/utils/date.ts", "exports": 4 @@ -15,6 +19,14 @@ "file_path": "src/components/shop/ShopButton.tsx", "exports": 2 }, + { + "file_path": "src/consumer.ts", + "exports": 2 + }, + { + "file_path": "src/env.ts", + "exports": 2 + }, { "file_path": "src/lib/cache.ts", "exports": 2 @@ -23,10 +35,22 @@ "file_path": "src/lib/store.ts", "exports": 2 }, + { + "file_path": "src/orphan.ts", + "exports": 2 + }, { "file_path": "src/utils/format.ts", "exports": 2 }, + { + "file_path": "src/api/decorated.ts", + "exports": 1 + }, + { + "file_path": "src/components/shop/ApiBridge.tsx", + "exports": 1 + }, { "file_path": "src/components/shop/ProductCard.tsx", "exports": 1 @@ -36,7 +60,7 @@ "exports": 1 }, { - "file_path": "src/consumer.ts", + "file_path": "src/types/status.ts", "exports": 1 }, { diff --git a/fixtures/golden/minimal/boundary-violations.json b/fixtures/golden/minimal/boundary-violations.json new file mode 100644 index 00000000..7b06f3d6 --- /dev/null +++ b/fixtures/golden/minimal/boundary-violations.json @@ -0,0 +1,9 @@ +[ + { + "file_path": "src/components/shop/ApiBridge.tsx", + "to_path": "src/api/client.ts", + "rule_name": "ui-no-api", + "rule_from_glob": "src/components/**", + "rule_to_glob": "src/api/**" + } +] diff --git a/fixtures/golden/minimal/calls-consumer.json b/fixtures/golden/minimal/calls-consumer.json index 86dd87ed..fcef6a9f 100644 --- a/fixtures/golden/minimal/calls-consumer.json +++ b/fixtures/golden/minimal/calls-consumer.json @@ -1,4 +1,7 @@ [ + { + "callee_name": "ApiCache" + }, { "callee_name": "createClient" }, @@ -8,7 +11,16 @@ { "callee_name": "get" }, + { + "callee_name": "labyrinth" + }, { "callee_name": "now" + }, + { + "callee_name": "optionalPing" + }, + { + "callee_name": "spreadLog" } ] diff --git a/fixtures/golden/minimal/components-by-hooks.json b/fixtures/golden/minimal/components-by-hooks.json new file mode 100644 index 00000000..76a0a445 --- /dev/null +++ b/fixtures/golden/minimal/components-by-hooks.json @@ -0,0 +1,12 @@ +[ + { + "name": "ProductCard", + "file_path": "src/components/shop/ProductCard.tsx", + "hook_count": 1 + }, + { + "name": "ShopButton", + "file_path": "src/components/shop/ShopButton.tsx", + "hook_count": 1 + } +] diff --git a/fixtures/golden/minimal/components-touching-deprecated.json b/fixtures/golden/minimal/components-touching-deprecated.json new file mode 100644 index 00000000..568b2425 --- /dev/null +++ b/fixtures/golden/minimal/components-touching-deprecated.json @@ -0,0 +1,9 @@ +[ + { + "component": "ShopButton", + "component_file": "src/components/shop/ShopButton.tsx", + "deprecated_symbol": "now", + "deprecated_file": "src/utils/date.ts", + "via": "call" + } +] diff --git a/fixtures/golden/minimal/coverage-rows-after-ingest.json b/fixtures/golden/minimal/coverage-rows-after-ingest.json index abd5c0e2..1f5c5f3e 100644 --- a/fixtures/golden/minimal/coverage-rows-after-ingest.json +++ b/fixtures/golden/minimal/coverage-rows-after-ingest.json @@ -1,11 +1,4 @@ [ - { - "file_path": "src/api/client.ts", - "name": "legacyClient", - "hit_statements": 0, - "total_statements": 1, - "coverage_pct": 0 - }, { "file_path": "src/components/shop/ProductCard.tsx", "name": "ProductCard", @@ -15,16 +8,23 @@ }, { "file_path": "src/components/shop/ShopButton.tsx", - "name": "FormatPrice", + "name": "cents", "hit_statements": 0, "total_statements": 1, "coverage_pct": 0 }, { "file_path": "src/components/shop/ShopButton.tsx", - "name": "ShopButton", - "hit_statements": 2, - "total_statements": 2, + "name": "perms", + "hit_statements": 1, + "total_statements": 1, + "coverage_pct": 100 + }, + { + "file_path": "src/components/shop/ShopButton.tsx", + "name": "_stamp", + "hit_statements": 1, + "total_statements": 1, "coverage_pct": 100 }, { diff --git a/fixtures/golden/minimal/deeply-nested-functions.json b/fixtures/golden/minimal/deeply-nested-functions.json index fe51488c..8ee30046 100644 --- a/fixtures/golden/minimal/deeply-nested-functions.json +++ b/fixtures/golden/minimal/deeply-nested-functions.json @@ -1 +1,20 @@ -[] +[ + { + "name": "labyrinth", + "kind": "function", + "file_path": "src/lib/complexity-fixture.ts", + "line_start": 22, + "body_line_count": 62, + "complexity": 19, + "nesting_depth": 5 + }, + { + "name": "deeplyNested", + "kind": "function", + "file_path": "src/lib/complexity-fixture.ts", + "line_start": 6, + "body_line_count": 15, + "complexity": 5, + "nesting_depth": 4 + } +] diff --git a/fixtures/golden/minimal/dependencies-from-consumer.json b/fixtures/golden/minimal/dependencies-from-consumer.json index dba1d723..c4dd3845 100644 --- a/fixtures/golden/minimal/dependencies-from-consumer.json +++ b/fixtures/golden/minimal/dependencies-from-consumer.json @@ -3,6 +3,10 @@ "from_path": "src/consumer.ts", "to_path": "src/api/client.ts" }, + { + "from_path": "src/consumer.ts", + "to_path": "src/api/decorated.ts" + }, { "from_path": "src/consumer.ts", "to_path": "src/components/shop/index.ts" @@ -11,6 +15,14 @@ "from_path": "src/consumer.ts", "to_path": "src/lib/cache.ts" }, + { + "from_path": "src/consumer.ts", + "to_path": "src/lib/complexity-fixture.ts" + }, + { + "from_path": "src/consumer.ts", + "to_path": "src/polyfill.ts" + }, { "from_path": "src/consumer.ts", "to_path": "src/utils/date.ts" diff --git a/fixtures/golden/minimal/deprecated-symbols.json b/fixtures/golden/minimal/deprecated-symbols.json index 3cb0802c..9472f835 100644 --- a/fixtures/golden/minimal/deprecated-symbols.json +++ b/fixtures/golden/minimal/deprecated-symbols.json @@ -3,7 +3,7 @@ "name": "legacyClient", "kind": "function", "file_path": "src/api/client.ts", - "line_start": 41, + "line_start": 46, "signature": "legacyClient()", "doc_comment": "@deprecated Use `createClient({ baseUrl })` directly. Kept as a fixture for\n`deprecated-symbols` + `--format sarif` / `--format annotations` recipes." }, diff --git a/fixtures/golden/minimal/enum-order-status.json b/fixtures/golden/minimal/enum-order-status.json new file mode 100644 index 00000000..61d52a3d --- /dev/null +++ b/fixtures/golden/minimal/enum-order-status.json @@ -0,0 +1,7 @@ +[ + { + "name": "OrderStatus", + "kind": "enum", + "file_path": "src/types/status.ts" + } +] diff --git a/fixtures/golden/minimal/env-var-audit.json b/fixtures/golden/minimal/env-var-audit.json index fe51488c..c11b7740 100644 --- a/fixtures/golden/minimal/env-var-audit.json +++ b/fixtures/golden/minimal/env-var-audit.json @@ -1 +1,12 @@ -[] +[ + { + "env_var": "CODEMAP_FIXTURE_API_KEY", + "uses": 1, + "files": 1 + }, + { + "env_var": "NODE_ENV", + "uses": 1, + "files": 1 + } +] diff --git a/fixtures/golden/minimal/fan-in.json b/fixtures/golden/minimal/fan-in.json new file mode 100644 index 00000000..755eac5b --- /dev/null +++ b/fixtures/golden/minimal/fan-in.json @@ -0,0 +1,46 @@ +[ + { + "to_path": "src/utils/date.ts", + "fan_in": 3 + }, + { + "to_path": "src/api/client.ts", + "fan_in": 2 + }, + { + "to_path": "src/lib/cache.ts", + "fan_in": 2 + }, + { + "to_path": "src/lib/complexity-fixture.ts", + "fan_in": 2 + }, + { + "to_path": "src/usePermissions.ts", + "fan_in": 2 + }, + { + "to_path": "src/api/decorated.ts", + "fan_in": 1 + }, + { + "to_path": "src/components/shop/ShopButton.tsx", + "fan_in": 1 + }, + { + "to_path": "src/components/shop/index.ts", + "fan_in": 1 + }, + { + "to_path": "src/lib/store.ts", + "fan_in": 1 + }, + { + "to_path": "src/polyfill.ts", + "fan_in": 1 + }, + { + "to_path": "src/utils/format.ts", + "fan_in": 1 + } +] diff --git a/fixtures/golden/minimal/fan-out-sample-json.json b/fixtures/golden/minimal/fan-out-sample-json.json new file mode 100644 index 00000000..26e03a86 --- /dev/null +++ b/fixtures/golden/minimal/fan-out-sample-json.json @@ -0,0 +1,42 @@ +[ + { + "from_path": "src/consumer.ts", + "deps": 8, + "sample_targets": "[\"src/api/client.ts\",\"src/api/decorated.ts\",\"src/components/shop/index.ts\",\"src/lib/cache.ts\",\"src/lib/complexity-fixture.ts\"]" + }, + { + "from_path": "src/components/shop/ProductCard.tsx", + "deps": 2, + "sample_targets": "[\"src/usePermissions.ts\",\"src/utils/date.ts\"]" + }, + { + "from_path": "src/components/shop/ShopButton.tsx", + "deps": 2, + "sample_targets": "[\"src/usePermissions.ts\",\"src/utils/date.ts\"]" + }, + { + "from_path": "src/__tests__/smoke.test.ts", + "deps": 1, + "sample_targets": "[\"src/lib/complexity-fixture.ts\"]" + }, + { + "from_path": "src/components/shop/ApiBridge.tsx", + "deps": 1, + "sample_targets": "[\"src/api/client.ts\"]" + }, + { + "from_path": "src/components/shop/ShopButton.default.ts", + "deps": 1, + "sample_targets": "[\"src/components/shop/ShopButton.tsx\"]" + }, + { + "from_path": "src/lib/cache.ts", + "deps": 1, + "sample_targets": "[\"src/lib/store.ts\"]" + }, + { + "from_path": "src/lib/store.ts", + "deps": 1, + "sample_targets": "[\"src/lib/cache.ts\"]" + } +] diff --git a/fixtures/golden/minimal/fan-out-sample.json b/fixtures/golden/minimal/fan-out-sample.json new file mode 100644 index 00000000..3f6953dc --- /dev/null +++ b/fixtures/golden/minimal/fan-out-sample.json @@ -0,0 +1,42 @@ +[ + { + "from_path": "src/consumer.ts", + "deps": 8, + "sample_targets": "src/api/client.ts | src/api/decorated.ts | src/components/shop/index.ts | src/lib/cache.ts | src/lib/complexity-fixture.ts" + }, + { + "from_path": "src/components/shop/ProductCard.tsx", + "deps": 2, + "sample_targets": "src/usePermissions.ts | src/utils/date.ts" + }, + { + "from_path": "src/components/shop/ShopButton.tsx", + "deps": 2, + "sample_targets": "src/usePermissions.ts | src/utils/date.ts" + }, + { + "from_path": "src/__tests__/smoke.test.ts", + "deps": 1, + "sample_targets": "src/lib/complexity-fixture.ts" + }, + { + "from_path": "src/components/shop/ApiBridge.tsx", + "deps": 1, + "sample_targets": "src/api/client.ts" + }, + { + "from_path": "src/components/shop/ShopButton.default.ts", + "deps": 1, + "sample_targets": "src/components/shop/ShopButton.tsx" + }, + { + "from_path": "src/lib/cache.ts", + "deps": 1, + "sample_targets": "src/lib/store.ts" + }, + { + "from_path": "src/lib/store.ts", + "deps": 1, + "sample_targets": "src/lib/cache.ts" + } +] diff --git a/fixtures/golden/minimal/fan-out.json b/fixtures/golden/minimal/fan-out.json new file mode 100644 index 00000000..3cd7e2b9 --- /dev/null +++ b/fixtures/golden/minimal/fan-out.json @@ -0,0 +1,34 @@ +[ + { + "from_path": "src/consumer.ts", + "deps": 8 + }, + { + "from_path": "src/components/shop/ProductCard.tsx", + "deps": 2 + }, + { + "from_path": "src/components/shop/ShopButton.tsx", + "deps": 2 + }, + { + "from_path": "src/__tests__/smoke.test.ts", + "deps": 1 + }, + { + "from_path": "src/components/shop/ApiBridge.tsx", + "deps": 1 + }, + { + "from_path": "src/components/shop/ShopButton.default.ts", + "deps": 1 + }, + { + "from_path": "src/lib/cache.ts", + "deps": 1 + }, + { + "from_path": "src/lib/store.ts", + "deps": 1 + } +] diff --git a/fixtures/golden/minimal/files-by-coverage.json b/fixtures/golden/minimal/files-by-coverage.json index 7a24c45c..25892853 100644 --- a/fixtures/golden/minimal/files-by-coverage.json +++ b/fixtures/golden/minimal/files-by-coverage.json @@ -1,10 +1,4 @@ [ - { - "file_path": "src/api/client.ts", - "hit_statements": 0, - "total_statements": 1, - "coverage_pct": 0 - }, { "file_path": "src/utils/date.ts", "hit_statements": 1, diff --git a/fixtures/golden/minimal/files-count.json b/fixtures/golden/minimal/files-count.json index f5f07db5..9353bfed 100644 --- a/fixtures/golden/minimal/files-count.json +++ b/fixtures/golden/minimal/files-count.json @@ -1,5 +1,5 @@ [ { - "n": 18 + "n": 27 } ] diff --git a/fixtures/golden/minimal/files-hashes.json b/fixtures/golden/minimal/files-hashes.json index 5e7d373d..7ae748c3 100644 --- a/fixtures/golden/minimal/files-hashes.json +++ b/fixtures/golden/minimal/files-hashes.json @@ -1,4 +1,10 @@ [ + { + "path": ".codemap/config.json", + "content_hash": "336aef86f425c7227027d30a696382314825c37d6c7a6b65b13d354d5980f111", + "language": "json", + "line_count": 11 + }, { "path": ".codemap/recipes/shop-symbols.md", "content_hash": "0ef26e4291fd1dbfb60887d79251bfd9eb1af71675811ba40a1932368e6b112c", @@ -7,9 +13,9 @@ }, { "path": "README.md", - "content_hash": "05f60d056b6a09c6d2024be74cd45e17f40b1126c408b67a42bc098f5159d13e", + "content_hash": "390688dd7d6a7fd10daf9ec36acf4562e1a29859bfce78ca88ba4d5abd2eb0ab", "language": "md", - "line_count": 50 + "line_count": 52 }, { "path": "package.json", @@ -17,17 +23,35 @@ "language": "json", "line_count": 11 }, + { + "path": "src/__tests__/smoke.test.ts", + "content_hash": "2fa9fff351d4f0181db6a2edac133ab3d90ee227934a599b122ad8dcbf7ba13c", + "language": "ts", + "line_count": 26 + }, { "path": "src/api/client.ts", - "content_hash": "625df0a0f197f2233506c028f5a4b2022567587de2ecc5e81863c2cb2654e507", + "content_hash": "7d313fff06443ff9e7ca3d13f44a8c601ce65baa3d8aa1a8263f3e85090afe0b", "language": "ts", - "line_count": 44 + "line_count": 49 + }, + { + "path": "src/api/decorated.ts", + "content_hash": "96bd631cc642f270589cba89e4fbfea8555b375aba66be53fed657f4b2de8d9c", + "language": "ts", + "line_count": 5 + }, + { + "path": "src/components/shop/ApiBridge.tsx", + "content_hash": "825a69353a860b7a4f0bb562b71ca12fad3f6a2b38cd7f28b91a17562ac5d8d5", + "language": "tsx", + "line_count": 8 }, { "path": "src/components/shop/ProductCard.tsx", - "content_hash": "4cdd3d8376da664789c075bfdb3eab49adc3460fcd0810eedc1ad456e7c5be9a", + "content_hash": "27b25a905655574a3002adc140b36e91b95f8f1a5db0758ba172115595134122", "language": "tsx", - "line_count": 20 + "line_count": 23 }, { "path": "src/components/shop/ShopButton.default.ts", @@ -37,9 +61,9 @@ }, { "path": "src/components/shop/ShopButton.tsx", - "content_hash": "cbc7939a134240c0076f76f6499fa893309f131dda53eaef4d946470f42c54af", + "content_hash": "abc37ff9c611c7259b63bde0727216c8e1848f279f142d1ce276564bcb34aed8", "language": "tsx", - "line_count": 15 + "line_count": 17 }, { "path": "src/components/shop/index.ts", @@ -49,15 +73,27 @@ }, { "path": "src/consumer.ts", - "content_hash": "ab868f04a0f22a8b132bc7a4ae42b403dad9c20185497f8513c06dd26c848091", + "content_hash": "ce739e8bbfd30a8ef46a82f6eb9760227ca8b8369162df3b819747b81b7a57cc", "language": "ts", - "line_count": 19 + "line_count": 40 + }, + { + "path": "src/env.ts", + "content_hash": "5d5828d36203762f7aae84b4bc3672285ee9e335fbbba95e29c01393095440b6", + "language": "ts", + "line_count": 4 }, { "path": "src/lib/cache.ts", - "content_hash": "a185908afc6dca9552783847c0726686378dcf60e9d5714bfdb0aa24c479a4c1", + "content_hash": "964f6d3ddb8a7782b1273a38ed0bbde8cd886eb672c1f20466f0aa88ff49205f", + "language": "ts", + "line_count": 27 + }, + { + "path": "src/lib/complexity-fixture.ts", + "content_hash": "6002e60fb440df4dbaeb5840e6090bcdc1a0c6416bd3c2aebfaa6661c51cc16f", "language": "ts", - "line_count": 21 + "line_count": 105 }, { "path": "src/lib/store.ts", @@ -71,6 +107,18 @@ "language": "md", "line_count": 11 }, + { + "path": "src/orphan.ts", + "content_hash": "2c1516b82d9ad1c65f3827701f6adf6c9a246bc71b9b8eab486717e40e6e0e58", + "language": "ts", + "line_count": 10 + }, + { + "path": "src/polyfill.ts", + "content_hash": "f9c2f0d0224aef67b737ce225be1c3797d50fa0ab05fcd8c2fd129dc5bad6914", + "language": "ts", + "line_count": 3 + }, { "path": "src/styles/button.module.css", "content_hash": "1c385277a506b2cb1c70c2d2128bbd280bf080796c83ab37f6f3434655c17348", @@ -83,6 +131,12 @@ "language": "css", "line_count": 9 }, + { + "path": "src/types/status.ts", + "content_hash": "85a4d68b1bcffdd9b00c25293b5b81be1ce690a7525b444c6315dcf2b8876b7b", + "language": "ts", + "line_count": 5 + }, { "path": "src/usePermissions.ts", "content_hash": "8758cc9ba2756e08198f11fca9ff58a0612fc9219173d06784e0b7e2f2ca1e1f", @@ -97,14 +151,14 @@ }, { "path": "src/utils/format.ts", - "content_hash": "8f4e1b729d1a69f1457a57c0a6ce61740ff27f2119976d2183ca053bf50b2ad6", + "content_hash": "670e458b068c63994b027d3200cc74e1a2c1bf5472ae2dc5e5508653178c506d", "language": "ts", - "line_count": 16 + "line_count": 17 }, { "path": "tsconfig.json", - "content_hash": "6b8ead4b09e6885483c805937a35fa0df3cbc47de346abb2d0ed8b73dc7f9e92", + "content_hash": "4bbd0839e5e2edc79d5432dff495b709edc6f281cf0b09f35d1155ff38f9def0", "language": "json", - "line_count": 17 + "line_count": 18 } ] diff --git a/fixtures/golden/minimal/files-largest.json b/fixtures/golden/minimal/files-largest.json new file mode 100644 index 00000000..669f98de --- /dev/null +++ b/fixtures/golden/minimal/files-largest.json @@ -0,0 +1,122 @@ +[ + { + "path": "src/lib/complexity-fixture.ts", + "line_count": 105, + "size": 1864, + "language": "ts" + }, + { + "path": "README.md", + "line_count": 52, + "size": 8499, + "language": "md" + }, + { + "path": "src/api/client.ts", + "line_count": 49, + "size": 1373, + "language": "ts" + }, + { + "path": "src/consumer.ts", + "line_count": 40, + "size": 1068, + "language": "ts" + }, + { + "path": "src/utils/date.ts", + "line_count": 29, + "size": 684, + "language": "ts" + }, + { + "path": "src/lib/cache.ts", + "line_count": 27, + "size": 733, + "language": "ts" + }, + { + "path": "src/__tests__/smoke.test.ts", + "line_count": 26, + "size": 489, + "language": "ts" + }, + { + "path": "src/components/shop/ProductCard.tsx", + "line_count": 23, + "size": 654, + "language": "tsx" + }, + { + "path": "tsconfig.json", + "line_count": 18, + "size": 363, + "language": "json" + }, + { + "path": "src/components/shop/ShopButton.tsx", + "line_count": 17, + "size": 377, + "language": "tsx" + }, + { + "path": "src/utils/format.ts", + "line_count": 17, + "size": 500, + "language": "ts" + }, + { + "path": "src/styles/button.module.css", + "line_count": 16, + "size": 167, + "language": "css" + }, + { + "path": "src/lib/store.ts", + "line_count": 15, + "size": 329, + "language": "ts" + }, + { + "path": ".codemap/config.json", + "line_count": 11, + "size": 151, + "language": "json" + }, + { + "path": "package.json", + "line_count": 11, + "size": 238, + "language": "json" + }, + { + "path": "src/notes.md", + "line_count": 11, + "size": 418, + "language": "md" + }, + { + "path": "src/orphan.ts", + "line_count": 10, + "size": 239, + "language": "ts" + }, + { + "path": ".codemap/recipes/shop-symbols.md", + "line_count": 9, + "size": 310, + "language": "md" + }, + { + "path": "src/theme.css", + "line_count": 9, + "size": 94, + "language": "css" + }, + { + "path": "src/components/shop/ApiBridge.tsx", + "line_count": 8, + "size": 184, + "language": "tsx" + } +] diff --git a/fixtures/golden/minimal/find-async-functions.json b/fixtures/golden/minimal/find-async-functions.json new file mode 100644 index 00000000..28cbe8d6 --- /dev/null +++ b/fixtures/golden/minimal/find-async-functions.json @@ -0,0 +1,9 @@ +[ + { + "file_path": "src/consumer.ts", + "name": "prefetch", + "kind": "function", + "return_type": "Promise", + "is_generator": 0 + } +] diff --git a/fixtures/golden/minimal/find-await-in-loop.json b/fixtures/golden/minimal/find-await-in-loop.json new file mode 100644 index 00000000..365ecfef --- /dev/null +++ b/fixtures/golden/minimal/find-await-in-loop.json @@ -0,0 +1,11 @@ +[ + { + "file_path": "src/consumer.ts", + "caller_scope": "prefetch.$anon_2", + "awaited_expression": "await import(\"./lib/cache\")", + "awaited_callee_name": null, + "line_start": 17, + "in_loop": 1, + "in_try": 0 + } +] diff --git a/fixtures/golden/minimal/find-barrel-files.json b/fixtures/golden/minimal/find-barrel-files.json new file mode 100644 index 00000000..4a9aed00 --- /dev/null +++ b/fixtures/golden/minimal/find-barrel-files.json @@ -0,0 +1,8 @@ +[ + { + "path": "src/components/shop/index.ts", + "language": "ts", + "is_barrel": 1, + "has_side_effects": 0 + } +] diff --git a/fixtures/golden/minimal/find-by-param-type.json b/fixtures/golden/minimal/find-by-param-type.json index b40f707d..c021bf0f 100644 --- a/fixtures/golden/minimal/find-by-param-type.json +++ b/fixtures/golden/minimal/find-by-param-type.json @@ -8,7 +8,7 @@ "default_text": null, "is_rest": 0, "is_optional": 1, - "line_start": 15, + "line_start": 20, "column_start": 29 } ] diff --git a/fixtures/golden/minimal/find-call-sites.json b/fixtures/golden/minimal/find-call-sites.json index ec42a8a9..fc9cbf2a 100644 --- a/fixtures/golden/minimal/find-call-sites.json +++ b/fixtures/golden/minimal/find-call-sites.json @@ -3,16 +3,36 @@ "file_path": "src/api/client.ts", "caller_name": "legacyClient", "caller_scope": "legacyClient", - "line_start": 42, + "line_start": 47, "column_start": 9, - "column_end": 21 + "column_end": 21, + "args_count": 0, + "is_method_call": 0, + "is_constructor_call": 0, + "is_optional_chain": 0 + }, + { + "file_path": "src/components/shop/ApiBridge.tsx", + "caller_name": "ApiBridge", + "caller_scope": "ApiBridge", + "line_start": 5, + "column_start": 2, + "column_end": 14, + "args_count": 0, + "is_method_call": 0, + "is_constructor_call": 0, + "is_optional_chain": 0 }, { "file_path": "src/consumer.ts", "caller_name": "run", "caller_scope": "run", - "line_start": 12, + "line_start": 24, "column_start": 2, - "column_end": 14 + "column_end": 14, + "args_count": 1, + "is_method_call": 0, + "is_constructor_call": 0, + "is_optional_chain": 0 } ] diff --git a/fixtures/golden/minimal/find-decorator-usage.json b/fixtures/golden/minimal/find-decorator-usage.json new file mode 100644 index 00000000..a5e93e58 --- /dev/null +++ b/fixtures/golden/minimal/find-decorator-usage.json @@ -0,0 +1,10 @@ +[ + { + "file_path": "src/api/decorated.ts", + "target_kind": "class", + "name": "sealed", + "line": 3, + "column_start": 0, + "target_symbol_id": 17 + } +] diff --git a/fixtures/golden/minimal/find-dynamic-imports.json b/fixtures/golden/minimal/find-dynamic-imports.json new file mode 100644 index 00000000..f3f9ed1b --- /dev/null +++ b/fixtures/golden/minimal/find-dynamic-imports.json @@ -0,0 +1,11 @@ +[ + { + "file_path": "src/consumer.ts", + "line_start": 17, + "column_start": 17, + "source_kind": "literal", + "source_text": "./lib/cache", + "resolved_path": "src/lib/cache.ts", + "in_async_fn": 1 + } +] diff --git a/fixtures/golden/minimal/find-export-sites.json b/fixtures/golden/minimal/find-export-sites.json index 020856c6..82d3099b 100644 --- a/fixtures/golden/minimal/find-export-sites.json +++ b/fixtures/golden/minimal/find-export-sites.json @@ -6,8 +6,8 @@ "is_default": 0, "is_re_export": 0, "re_export_source": null, - "line_start": 11, - "line_end": 19, + "line_start": 10, + "line_end": 22, "column_start": 16, "column_end": 27 }, diff --git a/fixtures/golden/minimal/find-import-sites.json b/fixtures/golden/minimal/find-import-sites.json index af9b3a51..0c667a71 100644 --- a/fixtures/golden/minimal/find-import-sites.json +++ b/fixtures/golden/minimal/find-import-sites.json @@ -2,7 +2,7 @@ { "file_path": "src/consumer.ts", "source": "~/components/shop", - "line": 2, + "line": 3, "column_start": 9, "column_end": 20, "imported_name": "ProductCard", diff --git a/fixtures/golden/minimal/find-jsx-usages.json b/fixtures/golden/minimal/find-jsx-usages.json new file mode 100644 index 00000000..c81d8216 --- /dev/null +++ b/fixtures/golden/minimal/find-jsx-usages.json @@ -0,0 +1,12 @@ +[ + { + "file_path": "src/components/shop/ProductCard.tsx", + "component_name": "article", + "line_start": 15, + "line_end": 19, + "is_self_closing": 0, + "is_fragment": 0, + "is_lowercase": 1, + "children_count": 2 + } +] diff --git a/fixtures/golden/minimal/find-leftover-console.json b/fixtures/golden/minimal/find-leftover-console.json index fe51488c..f3d3c5c3 100644 --- a/fixtures/golden/minimal/find-leftover-console.json +++ b/fixtures/golden/minimal/find-leftover-console.json @@ -1 +1,14 @@ -[] +[ + { + "file_path": "src/consumer.ts", + "line_start": 38, + "column_start": 2, + "method": "debug" + }, + { + "file_path": "src/lib/cache.ts", + "line_start": 23, + "column_start": 6, + "method": "error" + } +] diff --git a/fixtures/golden/minimal/find-re-exported-bindings.json b/fixtures/golden/minimal/find-re-exported-bindings.json new file mode 100644 index 00000000..17249d13 --- /dev/null +++ b/fixtures/golden/minimal/find-re-exported-bindings.json @@ -0,0 +1,30 @@ +[ + { + "file_path": "src/consumer.ts", + "name": "ProductCard", + "line_start": 3, + "column_start": 9, + "resolution_kind": "re-exported" + }, + { + "file_path": "src/consumer.ts", + "name": "ShopButton", + "line_start": 3, + "column_start": 22, + "resolution_kind": "re-exported" + }, + { + "file_path": "src/consumer.ts", + "name": "ShopButton", + "line_start": 26, + "column_start": 23, + "resolution_kind": "re-exported" + }, + { + "file_path": "src/consumer.ts", + "name": "ProductCard", + "line_start": 26, + "column_start": 35, + "resolution_kind": "re-exported" + } +] diff --git a/fixtures/golden/minimal/find-references.json b/fixtures/golden/minimal/find-references.json index 99d2e884..e5a1d59f 100644 --- a/fixtures/golden/minimal/find-references.json +++ b/fixtures/golden/minimal/find-references.json @@ -11,7 +11,7 @@ }, { "file_path": "src/consumer.ts", - "line_start": 2, + "line_start": 3, "column_start": 9, "column_end": 20, "kind": "value", @@ -21,7 +21,7 @@ }, { "file_path": "src/consumer.ts", - "line_start": 16, + "line_start": 26, "column_start": 35, "column_end": 46, "kind": "value", diff --git a/fixtures/golden/minimal/find-side-effect-files.json b/fixtures/golden/minimal/find-side-effect-files.json new file mode 100644 index 00000000..3042612d --- /dev/null +++ b/fixtures/golden/minimal/find-side-effect-files.json @@ -0,0 +1,20 @@ +[ + { + "path": "src/__tests__/smoke.test.ts", + "language": "ts", + "is_barrel": 0, + "has_side_effects": 1 + }, + { + "path": "src/consumer.ts", + "language": "ts", + "is_barrel": 0, + "has_side_effects": 1 + }, + { + "path": "src/polyfill.ts", + "language": "ts", + "is_barrel": 0, + "has_side_effects": 1 + } +] diff --git a/fixtures/golden/minimal/find-side-effect-imports.json b/fixtures/golden/minimal/find-side-effect-imports.json new file mode 100644 index 00000000..47f4aa2b --- /dev/null +++ b/fixtures/golden/minimal/find-side-effect-imports.json @@ -0,0 +1,10 @@ +[ + { + "file_path": "src/consumer.ts", + "source": "./polyfill", + "line": 5, + "column_start": 7, + "column_end": 19, + "import_id": 12 + } +] diff --git a/fixtures/golden/minimal/find-skipped-tests.json b/fixtures/golden/minimal/find-skipped-tests.json index fe51488c..1a952360 100644 --- a/fixtures/golden/minimal/find-skipped-tests.json +++ b/fixtures/golden/minimal/find-skipped-tests.json @@ -1 +1,26 @@ -[] +[ + { + "file_path": "src/__tests__/smoke.test.ts", + "line_start": 10, + "kind": "it", + "name": "focused example", + "status": "only", + "framework": "vitest" + }, + { + "file_path": "src/__tests__/smoke.test.ts", + "line_start": 6, + "kind": "it", + "name": "skipped example", + "status": "skipped", + "framework": "vitest" + }, + { + "file_path": "src/__tests__/smoke.test.ts", + "line_start": 14, + "kind": "it", + "name": "todo example", + "status": "todo", + "framework": "vitest" + } +] diff --git a/fixtures/golden/minimal/find-swallowed-errors.json b/fixtures/golden/minimal/find-swallowed-errors.json new file mode 100644 index 00000000..5dcb169e --- /dev/null +++ b/fixtures/golden/minimal/find-swallowed-errors.json @@ -0,0 +1,10 @@ +[ + { + "file_path": "src/lib/cache.ts", + "try_line_start": 20, + "try_line_end": 22, + "catch_param": "err", + "catch_logs_only": 1, + "catch_rethrows": 0 + } +] diff --git a/fixtures/golden/minimal/find-symbol-definitions.json b/fixtures/golden/minimal/find-symbol-definitions.json index 300623be..a9a9b567 100644 --- a/fixtures/golden/minimal/find-symbol-definitions.json +++ b/fixtures/golden/minimal/find-symbol-definitions.json @@ -3,8 +3,8 @@ "file_path": "src/components/shop/ProductCard.tsx", "name": "ProductCard", "kind": "function", - "line_start": 11, - "line_end": 19, + "line_start": 10, + "line_end": 22, "name_column_start": 16, "name_column_end": 27, "parent_name": null, diff --git a/fixtures/golden/minimal/find-symbol-references.json b/fixtures/golden/minimal/find-symbol-references.json index c3b82bb5..174678b5 100644 --- a/fixtures/golden/minimal/find-symbol-references.json +++ b/fixtures/golden/minimal/find-symbol-references.json @@ -1,7 +1,7 @@ [ { "file_path": "src/api/client.ts", - "line_start": 42, + "line_start": 47, "column_start": 9, "column_end": 21, "kind": "value", @@ -10,6 +10,28 @@ "scope_kind": "function", "scope_owner": "legacyClient" }, + { + "file_path": "src/components/shop/ApiBridge.tsx", + "line_start": 1, + "column_start": 9, + "column_end": 21, + "kind": "value", + "is_write": 0, + "resolution_kind": "imported", + "scope_kind": "module", + "scope_owner": null + }, + { + "file_path": "src/components/shop/ApiBridge.tsx", + "line_start": 5, + "column_start": 2, + "column_end": 14, + "kind": "value", + "is_write": 0, + "resolution_kind": "imported", + "scope_kind": "function", + "scope_owner": "ApiBridge" + }, { "file_path": "src/consumer.ts", "line_start": 1, @@ -23,7 +45,7 @@ }, { "file_path": "src/consumer.ts", - "line_start": 12, + "line_start": 24, "column_start": 2, "column_end": 14, "kind": "value", diff --git a/fixtures/golden/minimal/find-throws-jsdoc.json b/fixtures/golden/minimal/find-throws-jsdoc.json new file mode 100644 index 00000000..2fb488bd --- /dev/null +++ b/fixtures/golden/minimal/find-throws-jsdoc.json @@ -0,0 +1,10 @@ +[ + { + "file_path": "src/api/client.ts", + "name": "createClient", + "line_start": 20, + "tag": "@throws", + "type_text": "Error", + "description": "when config is invalid" + } +] diff --git a/fixtures/golden/minimal/find-write-sites.json b/fixtures/golden/minimal/find-write-sites.json index 7e4faa18..b006a54a 100644 --- a/fixtures/golden/minimal/find-write-sites.json +++ b/fixtures/golden/minimal/find-write-sites.json @@ -2,7 +2,7 @@ { "file_path": "src/components/shop/ProductCard.tsx", "name": "perms", - "line_start": 12, + "line_start": 11, "column_start": 8, "column_end": 13, "kind": "value", @@ -12,7 +12,7 @@ { "file_path": "src/components/shop/ShopButton.tsx", "name": "perms", - "line_start": 8, + "line_start": 9, "column_start": 8, "column_end": 13, "kind": "value", diff --git a/fixtures/golden/minimal/high-complexity-untested.json b/fixtures/golden/minimal/high-complexity-untested.json new file mode 100644 index 00000000..9166acdf --- /dev/null +++ b/fixtures/golden/minimal/high-complexity-untested.json @@ -0,0 +1,11 @@ +[ + { + "name": "labyrinth", + "kind": "function", + "file_path": "src/lib/complexity-fixture.ts", + "line_start": 22, + "line_end": 83, + "complexity": 19, + "coverage_pct": 0 + } +] diff --git a/fixtures/golden/minimal/index-summary.json b/fixtures/golden/minimal/index-summary.json index 75fb3e08..3b11c245 100644 --- a/fixtures/golden/minimal/index-summary.json +++ b/fixtures/golden/minimal/index-summary.json @@ -1,9 +1,9 @@ [ { - "files": 18, - "symbols": 44, - "imports": 11, + "files": 27, + "symbols": 75, + "imports": 19, "components": 2, - "dependencies": 10 + "dependencies": 17 } ] diff --git a/fixtures/golden/minimal/jsdoc-tags-createClient.json b/fixtures/golden/minimal/jsdoc-tags-createClient.json new file mode 100644 index 00000000..05a4b64c --- /dev/null +++ b/fixtures/golden/minimal/jsdoc-tags-createClient.json @@ -0,0 +1,17 @@ +[ + { + "tag": "@param", + "name": "config", + "type_text": null + }, + { + "tag": "@returns", + "name": null, + "type_text": null + }, + { + "tag": "@throws", + "name": null, + "type_text": "Error" + } +] diff --git a/fixtures/golden/minimal/jsx-attributes-product-card.json b/fixtures/golden/minimal/jsx-attributes-product-card.json new file mode 100644 index 00000000..1866bcde --- /dev/null +++ b/fixtures/golden/minimal/jsx-attributes-product-card.json @@ -0,0 +1,26 @@ +[ + { + "name": "alt", + "value_kind": "string" + }, + { + "name": "data-id", + "value_kind": "expression" + }, + { + "name": "hidden", + "value_kind": "expression" + }, + { + "name": "src", + "value_kind": "string" + }, + { + "name": "type", + "value_kind": "string" + }, + { + "name": "…spread", + "value_kind": "spread" + } +] diff --git a/fixtures/golden/minimal/large-functions.json b/fixtures/golden/minimal/large-functions.json index fe51488c..c5c0d337 100644 --- a/fixtures/golden/minimal/large-functions.json +++ b/fixtures/golden/minimal/large-functions.json @@ -1 +1,13 @@ -[] +[ + { + "name": "labyrinth", + "kind": "function", + "file_path": "src/lib/complexity-fixture.ts", + "line_start": 22, + "line_end": 83, + "body_line_count": 62, + "param_count": 1, + "complexity": 19, + "nesting_depth": 5 + } +] diff --git a/fixtures/golden/minimal/markers-all-kinds.json b/fixtures/golden/minimal/markers-all-kinds.json index 7daab66b..d5c659de 100644 --- a/fixtures/golden/minimal/markers-all-kinds.json +++ b/fixtures/golden/minimal/markers-all-kinds.json @@ -1,7 +1,7 @@ [ { "kind": "FIXME", - "n": 1 + "n": 2 }, { "kind": "HACK", @@ -13,6 +13,6 @@ }, { "kind": "TODO", - "n": 2 + "n": 1 } ] diff --git a/fixtures/golden/minimal/markers-by-kind.json b/fixtures/golden/minimal/markers-by-kind.json new file mode 100644 index 00000000..806f99c3 --- /dev/null +++ b/fixtures/golden/minimal/markers-by-kind.json @@ -0,0 +1,18 @@ +[ + { + "kind": "FIXME", + "count": 2 + }, + { + "kind": "HACK", + "count": 2 + }, + { + "kind": "NOTE", + "count": 2 + }, + { + "kind": "TODO", + "count": 1 + } +] diff --git a/fixtures/golden/minimal/refactor-risk-ranking.json b/fixtures/golden/minimal/refactor-risk-ranking.json new file mode 100644 index 00000000..07becd7b --- /dev/null +++ b/fixtures/golden/minimal/refactor-risk-ranking.json @@ -0,0 +1,122 @@ +[ + { + "file_path": "src/api/client.ts", + "exported_count": 7, + "fan_in": 2, + "avg_coverage_pct": 0, + "measured_symbols": 0, + "risk_score": 300 + }, + { + "file_path": "src/lib/cache.ts", + "exported_count": 2, + "fan_in": 2, + "avg_coverage_pct": 0, + "measured_symbols": 0, + "risk_score": 300 + }, + { + "file_path": "src/lib/complexity-fixture.ts", + "exported_count": 4, + "fan_in": 2, + "avg_coverage_pct": 0, + "measured_symbols": 0, + "risk_score": 300 + }, + { + "file_path": "src/utils/date.ts", + "exported_count": 4, + "fan_in": 3, + "avg_coverage_pct": 33.3, + "measured_symbols": 3, + "risk_score": 266.7 + }, + { + "file_path": "src/api/decorated.ts", + "exported_count": 1, + "fan_in": 1, + "avg_coverage_pct": 0, + "measured_symbols": 0, + "risk_score": 200 + }, + { + "file_path": "src/lib/store.ts", + "exported_count": 2, + "fan_in": 1, + "avg_coverage_pct": 0, + "measured_symbols": 0, + "risk_score": 200 + }, + { + "file_path": "src/components/shop/ApiBridge.tsx", + "exported_count": 1, + "fan_in": 0, + "avg_coverage_pct": 0, + "measured_symbols": 0, + "risk_score": 100 + }, + { + "file_path": "src/consumer.ts", + "exported_count": 2, + "fan_in": 0, + "avg_coverage_pct": 0, + "measured_symbols": 0, + "risk_score": 100 + }, + { + "file_path": "src/env.ts", + "exported_count": 2, + "fan_in": 0, + "avg_coverage_pct": 0, + "measured_symbols": 0, + "risk_score": 100 + }, + { + "file_path": "src/orphan.ts", + "exported_count": 2, + "fan_in": 0, + "avg_coverage_pct": 0, + "measured_symbols": 0, + "risk_score": 100 + }, + { + "file_path": "src/types/status.ts", + "exported_count": 1, + "fan_in": 0, + "avg_coverage_pct": 0, + "measured_symbols": 0, + "risk_score": 100 + }, + { + "file_path": "src/utils/format.ts", + "exported_count": 2, + "fan_in": 1, + "avg_coverage_pct": 50, + "measured_symbols": 2, + "risk_score": 100 + }, + { + "file_path": "src/components/shop/ShopButton.tsx", + "exported_count": 2, + "fan_in": 1, + "avg_coverage_pct": 66.7, + "measured_symbols": 3, + "risk_score": 66.7 + }, + { + "file_path": "src/components/shop/ProductCard.tsx", + "exported_count": 1, + "fan_in": 0, + "avg_coverage_pct": 100, + "measured_symbols": 1, + "risk_score": 0 + }, + { + "file_path": "src/usePermissions.ts", + "exported_count": 1, + "fan_in": 2, + "avg_coverage_pct": 100, + "measured_symbols": 1, + "risk_score": 0 + } +] diff --git a/fixtures/golden/minimal/suppressions-orphan.json b/fixtures/golden/minimal/suppressions-orphan.json new file mode 100644 index 00000000..97046f3c --- /dev/null +++ b/fixtures/golden/minimal/suppressions-orphan.json @@ -0,0 +1,7 @@ +[ + { + "file_path": "src/orphan.ts", + "line_number": 2, + "recipe_id": "unimported-exports" + } +] diff --git a/fixtures/golden/minimal/tests-by-file.json b/fixtures/golden/minimal/tests-by-file.json index fe51488c..a62eb864 100644 --- a/fixtures/golden/minimal/tests-by-file.json +++ b/fixtures/golden/minimal/tests-by-file.json @@ -1 +1,11 @@ -[] +[ + { + "file_path": "src/__tests__/smoke.test.ts", + "framework": "vitest", + "describes": 2, + "tests": 5, + "skipped": 1, + "only_marks": 1, + "todos": 1 + } +] diff --git a/fixtures/golden/minimal/text-in-deprecated-functions.json b/fixtures/golden/minimal/text-in-deprecated-functions.json new file mode 100644 index 00000000..8450766f --- /dev/null +++ b/fixtures/golden/minimal/text-in-deprecated-functions.json @@ -0,0 +1,10 @@ +[ + { + "symbol": "epochMs", + "kind": "function", + "file_path": "src/utils/format.ts", + "line_start": 5, + "line_end": 8, + "coverage_pct": 0 + } +] diff --git a/fixtures/golden/minimal/try-catch-rethrow-heuristics.json b/fixtures/golden/minimal/try-catch-rethrow-heuristics.json new file mode 100644 index 00000000..b0db428e --- /dev/null +++ b/fixtures/golden/minimal/try-catch-rethrow-heuristics.json @@ -0,0 +1,10 @@ +[ + { + "name": "catchDirectRethrow", + "catch_rethrows": 1 + }, + { + "name": "catchInnerArrowRethrow", + "catch_rethrows": 0 + } +] diff --git a/fixtures/golden/minimal/unimported-exports.json b/fixtures/golden/minimal/unimported-exports.json new file mode 100644 index 00000000..099e9067 --- /dev/null +++ b/fixtures/golden/minimal/unimported-exports.json @@ -0,0 +1,156 @@ +[ + { + "name": "Transport", + "kind": "type", + "file_path": "src/api/client.ts", + "is_default": 0, + "re_export_source": null + }, + { + "name": "handshake", + "kind": "value", + "file_path": "src/api/client.ts", + "is_default": 0, + "re_export_source": null + }, + { + "name": "legacyClient", + "kind": "value", + "file_path": "src/api/client.ts", + "is_default": 0, + "re_export_source": null + }, + { + "name": "openSocket", + "kind": "value", + "file_path": "src/api/client.ts", + "is_default": 0, + "re_export_source": null + }, + { + "name": "setupTransport", + "kind": "value", + "file_path": "src/api/client.ts", + "is_default": 0, + "re_export_source": null + }, + { + "name": "ApiBridge", + "kind": "value", + "file_path": "src/components/shop/ApiBridge.tsx", + "is_default": 0, + "re_export_source": null + }, + { + "name": "ProductCard", + "kind": "value", + "file_path": "src/components/shop/ProductCard.tsx", + "is_default": 0, + "re_export_source": null + }, + { + "name": "FormatPrice", + "kind": "value", + "file_path": "src/components/shop/ShopButton.tsx", + "is_default": 0, + "re_export_source": null + }, + { + "name": "prefetch", + "kind": "value", + "file_path": "src/consumer.ts", + "is_default": 0, + "re_export_source": null + }, + { + "name": "run", + "kind": "value", + "file_path": "src/consumer.ts", + "is_default": 0, + "re_export_source": null + }, + { + "name": "fixtureApiKey", + "kind": "value", + "file_path": "src/env.ts", + "is_default": 0, + "re_export_source": null + }, + { + "name": "nodeEnv", + "kind": "value", + "file_path": "src/env.ts", + "is_default": 0, + "re_export_source": null + }, + { + "name": "catchDirectRethrow", + "kind": "value", + "file_path": "src/lib/complexity-fixture.ts", + "is_default": 0, + "re_export_source": null + }, + { + "name": "catchInnerArrowRethrow", + "kind": "value", + "file_path": "src/lib/complexity-fixture.ts", + "is_default": 0, + "re_export_source": null + }, + { + "name": "deeplyNested", + "kind": "value", + "file_path": "src/lib/complexity-fixture.ts", + "is_default": 0, + "re_export_source": null + }, + { + "name": "ignoredExport", + "kind": "value", + "file_path": "src/orphan.ts", + "is_default": 0, + "re_export_source": null + }, + { + "name": "orphanHelper", + "kind": "value", + "file_path": "src/orphan.ts", + "is_default": 0, + "re_export_source": null + }, + { + "name": "OrderStatus", + "kind": "value", + "file_path": "src/types/status.ts", + "is_default": 0, + "re_export_source": null + }, + { + "name": "_epochSeconds", + "kind": "value", + "file_path": "src/utils/date.ts", + "is_default": 0, + "re_export_source": null + }, + { + "name": "_hiResEpoch", + "kind": "value", + "file_path": "src/utils/date.ts", + "is_default": 0, + "re_export_source": null + }, + { + "name": "nanoseconds", + "kind": "value", + "file_path": "src/utils/date.ts", + "is_default": 0, + "re_export_source": null + }, + { + "name": "nowIso", + "kind": "value", + "file_path": "src/utils/format.ts", + "is_default": 0, + "re_export_source": null + } +] diff --git a/fixtures/golden/minimal/untested-and-dead.json b/fixtures/golden/minimal/untested-and-dead.json index e6f870ac..1b96fb52 100644 --- a/fixtures/golden/minimal/untested-and-dead.json +++ b/fixtures/golden/minimal/untested-and-dead.json @@ -2,19 +2,61 @@ { "name": "legacyClient", "file_path": "src/api/client.ts", - "line_start": 41, + "line_start": 46, + "coverage_pct": 0 + }, + { + "name": "ApiBridge", + "file_path": "src/components/shop/ApiBridge.tsx", + "line_start": 4, "coverage_pct": 0 }, { "name": "FormatPrice", "file_path": "src/components/shop/ShopButton.tsx", - "line_start": 3, + "line_start": 4, + "coverage_pct": 0 + }, + { + "name": "ShopButton", + "file_path": "src/components/shop/ShopButton.tsx", + "line_start": 8, + "coverage_pct": 0 + }, + { + "name": "prefetch", + "file_path": "src/consumer.ts", + "line_start": 15, "coverage_pct": 0 }, { "name": "run", "file_path": "src/consumer.ts", - "line_start": 10, + "line_start": 22, + "coverage_pct": 0 + }, + { + "name": "catchInnerArrowRethrow", + "file_path": "src/lib/complexity-fixture.ts", + "line_start": 86, + "coverage_pct": 0 + }, + { + "name": "catchDirectRethrow", + "file_path": "src/lib/complexity-fixture.ts", + "line_start": 98, + "coverage_pct": 0 + }, + { + "name": "ignoredExport", + "file_path": "src/orphan.ts", + "line_start": 2, + "coverage_pct": 0 + }, + { + "name": "orphanHelper", + "file_path": "src/orphan.ts", + "line_start": 7, "coverage_pct": 0 }, { diff --git a/fixtures/golden/minimal/visibility-tags.json b/fixtures/golden/minimal/visibility-tags.json index a8786270..25245993 100644 --- a/fixtures/golden/minimal/visibility-tags.json +++ b/fixtures/golden/minimal/visibility-tags.json @@ -31,7 +31,7 @@ "kind": "function", "visibility": "beta", "file_path": "src/utils/format.ts", - "line_start": 13, + "line_start": 14, "signature": "nowIso(): string", "doc_comment": "@beta Fixture for the `visibility-tags` recipe — lock-in for the four-tag\ncoverage (alongside `@internal`, `@alpha`, `@private`)." } diff --git a/fixtures/golden/minimal/worst-covered-exports.json b/fixtures/golden/minimal/worst-covered-exports.json index 541eab6d..49f71a2b 100644 --- a/fixtures/golden/minimal/worst-covered-exports.json +++ b/fixtures/golden/minimal/worst-covered-exports.json @@ -2,43 +2,61 @@ { "name": "createClient", "file_path": "src/api/client.ts", - "line_start": 15, + "line_start": 20, "coverage_pct": 0 }, { "name": "setupTransport", "file_path": "src/api/client.ts", - "line_start": 22, + "line_start": 27, "coverage_pct": 0 }, { "name": "openSocket", "file_path": "src/api/client.ts", - "line_start": 28, + "line_start": 33, "coverage_pct": 0 }, { "name": "handshake", "file_path": "src/api/client.ts", - "line_start": 32, + "line_start": 37, "coverage_pct": 0 }, { "name": "legacyClient", "file_path": "src/api/client.ts", - "line_start": 41, + "line_start": 46, + "coverage_pct": 0 + }, + { + "name": "ApiBridge", + "file_path": "src/components/shop/ApiBridge.tsx", + "line_start": 4, "coverage_pct": 0 }, { "name": "FormatPrice", "file_path": "src/components/shop/ShopButton.tsx", - "line_start": 3, + "line_start": 4, + "coverage_pct": 0 + }, + { + "name": "ShopButton", + "file_path": "src/components/shop/ShopButton.tsx", + "line_start": 8, + "coverage_pct": 0 + }, + { + "name": "prefetch", + "file_path": "src/consumer.ts", + "line_start": 15, "coverage_pct": 0 }, { "name": "run", "file_path": "src/consumer.ts", - "line_start": 10, + "line_start": 22, "coverage_pct": 0 }, { @@ -54,69 +72,51 @@ "coverage_pct": 0 }, { - "name": "read", - "file_path": "src/lib/store.ts", - "line_start": 7, + "name": "deeplyNested", + "file_path": "src/lib/complexity-fixture.ts", + "line_start": 6, "coverage_pct": 0 }, { - "name": "write", - "file_path": "src/lib/store.ts", - "line_start": 11, + "name": "labyrinth", + "file_path": "src/lib/complexity-fixture.ts", + "line_start": 22, "coverage_pct": 0 }, { - "name": "_epochSeconds", - "file_path": "src/utils/date.ts", - "line_start": 12, + "name": "catchInnerArrowRethrow", + "file_path": "src/lib/complexity-fixture.ts", + "line_start": 86, "coverage_pct": 0 }, { - "name": "nanoseconds", - "file_path": "src/utils/date.ts", - "line_start": 19, + "name": "catchDirectRethrow", + "file_path": "src/lib/complexity-fixture.ts", + "line_start": 98, "coverage_pct": 0 }, { - "name": "_hiResEpoch", - "file_path": "src/utils/date.ts", - "line_start": 26, + "name": "read", + "file_path": "src/lib/store.ts", + "line_start": 7, "coverage_pct": 0 }, { - "name": "epochMs", - "file_path": "src/utils/format.ts", - "line_start": 5, + "name": "write", + "file_path": "src/lib/store.ts", + "line_start": 11, "coverage_pct": 0 }, { - "name": "ProductCard", - "file_path": "src/components/shop/ProductCard.tsx", - "line_start": 11, - "coverage_pct": 100 + "name": "ignoredExport", + "file_path": "src/orphan.ts", + "line_start": 2, + "coverage_pct": 0 }, { - "name": "ShopButton", - "file_path": "src/components/shop/ShopButton.tsx", + "name": "orphanHelper", + "file_path": "src/orphan.ts", "line_start": 7, - "coverage_pct": 100 - }, - { - "name": "usePermissions", - "file_path": "src/usePermissions.ts", - "line_start": 1, - "coverage_pct": 100 - }, - { - "name": "now", - "file_path": "src/utils/date.ts", - "line_start": 5, - "coverage_pct": 100 - }, - { - "name": "nowIso", - "file_path": "src/utils/format.ts", - "line_start": 13, - "coverage_pct": 100 + "coverage_pct": 0 } ] diff --git a/fixtures/golden/scenarios.json b/fixtures/golden/scenarios.json index e7a5d58d..acc0ed49 100644 --- a/fixtures/golden/scenarios.json +++ b/fixtures/golden/scenarios.json @@ -100,6 +100,62 @@ "recipe": "find-call-sites", "params": { "callee": "createClient" } }, + { + "id": "find-async-functions", + "prompt": "Parametrised recipe: list async function-shaped symbols with return_type", + "recipe": "find-async-functions" + }, + { + "id": "find-dynamic-imports", + "prompt": "Recipe: every dynamic import() site with specifier kind and async-fn context", + "recipe": "find-dynamic-imports" + }, + { + "id": "find-barrel-files", + "prompt": "Recipe: barrel files (re-exports only, no local value symbols)", + "recipe": "find-barrel-files" + }, + { + "id": "find-side-effect-files", + "prompt": "Recipe: files with module-level side effects", + "recipe": "find-side-effect-files" + }, + { + "id": "find-re-exported-bindings", + "prompt": "Recipe: bindings resolved via re-export chains", + "recipe": "find-re-exported-bindings" + }, + { + "id": "find-side-effect-imports", + "prompt": "Recipe: side-effect-only import statements", + "recipe": "find-side-effect-imports" + }, + { + "id": "find-jsx-usages", + "prompt": "Recipe: JSX element usages", + "recipe": "find-jsx-usages", + "params": { "component_name": "article" } + }, + { + "id": "find-await-in-loop", + "prompt": "Recipe: await expressions inside loops", + "recipe": "find-await-in-loop" + }, + { + "id": "find-swallowed-errors", + "prompt": "Recipe: catch blocks that only log", + "recipe": "find-swallowed-errors" + }, + { + "id": "find-decorator-usage", + "prompt": "Recipe: decorator sites", + "recipe": "find-decorator-usage" + }, + { + "id": "find-throws-jsdoc", + "prompt": "Recipe: @throws JSDoc tags", + "recipe": "find-throws-jsdoc" + }, { "id": "find-export-sites", "prompt": "Parametrised recipe: where is ProductCard exported (direct + re-exports)?", @@ -229,6 +285,96 @@ "id": "unused-type-members", "prompt": "Members of exported types whose owning type has no detectable importer (advisory; field-level enumeration of `unimported-exports`)", "recipe": "unused-type-members" + }, + { + "id": "boundary-violations", + "prompt": "Config-driven architecture boundary violations (ui-no-api)", + "recipe": "boundary-violations" + }, + { + "id": "unimported-exports", + "prompt": "Exports with no direct importer (orphanHelper)", + "recipe": "unimported-exports" + }, + { + "id": "components-by-hooks", + "prompt": "Components ranked by hooks_used count", + "recipe": "components-by-hooks" + }, + { + "id": "components-touching-deprecated", + "prompt": "Components calling or hooking @deprecated symbols", + "recipe": "components-touching-deprecated" + }, + { + "id": "files-largest", + "prompt": "Largest indexed files by line_count", + "recipe": "files-largest" + }, + { + "id": "fan-in", + "prompt": "Top files by import fan-in", + "recipe": "fan-in" + }, + { + "id": "fan-out", + "prompt": "Top files by import fan-out", + "recipe": "fan-out" + }, + { + "id": "fan-out-sample", + "prompt": "Top fan-out files with GROUP_CONCAT sample targets", + "recipe": "fan-out-sample" + }, + { + "id": "fan-out-sample-json", + "prompt": "Top fan-out files with json_group_array sample targets (JSON1)", + "recipe": "fan-out-sample-json" + }, + { + "id": "refactor-risk-ranking", + "prompt": "Per-file refactor risk (fan-in × coverage gap)", + "recipe": "refactor-risk-ranking" + }, + { + "id": "high-complexity-untested", + "prompt": "High cyclomatic complexity + low coverage", + "recipe": "high-complexity-untested" + }, + { + "id": "text-in-deprecated-functions", + "prompt": "FTS TODO/FIXME/HACK in @deprecated functions with low coverage (requires fts5)", + "recipe": "text-in-deprecated-functions" + }, + { + "id": "markers-by-kind", + "prompt": "Marker inventory by kind (recipe form of markers-all-kinds)", + "recipe": "markers-by-kind" + }, + { + "id": "suppressions-orphan", + "prompt": "codemap-ignore suppressions registered at index time", + "sql": "SELECT file_path, line_number, recipe_id FROM suppressions ORDER BY file_path, line_number" + }, + { + "id": "enum-order-status", + "prompt": "Enum symbol extraction", + "sql": "SELECT name, kind, file_path FROM symbols WHERE name = 'OrderStatus'" + }, + { + "id": "jsdoc-tags-createClient", + "prompt": "Structured JSDoc tags on createClient", + "sql": "SELECT j.tag, j.name, j.type_text FROM jsdoc_tags j JOIN symbols s ON s.id = j.symbol_id WHERE s.name = 'createClient' AND s.file_path = 'src/api/client.ts' ORDER BY j.tag, j.name" + }, + { + "id": "jsx-attributes-product-card", + "prompt": "JSX attribute substrate on ProductCard", + "sql": "SELECT a.name, a.value_kind FROM jsx_attributes a JOIN jsx_elements e ON e.id = a.element_id WHERE e.file_path = 'src/components/shop/ProductCard.tsx' ORDER BY a.name" + }, + { + "id": "try-catch-rethrow-heuristics", + "prompt": "catch_rethrows: nested arrow throw vs direct rethrow (complexity-fixture)", + "sql": "SELECT s.name, t.catch_rethrows FROM try_catch t JOIN symbols s ON s.file_path = t.file_path AND s.kind = 'function' AND t.try_line_start >= s.line_start AND t.try_line_start <= s.line_end WHERE t.file_path = 'src/lib/complexity-fixture.ts' AND s.name IN ('catchInnerArrowRethrow', 'catchDirectRethrow') ORDER BY s.name" } ] } diff --git a/fixtures/minimal/.codemap/config.json b/fixtures/minimal/.codemap/config.json new file mode 100644 index 00000000..0858beb0 --- /dev/null +++ b/fixtures/minimal/.codemap/config.json @@ -0,0 +1,10 @@ +{ + "boundaries": [ + { + "name": "ui-no-api", + "from_glob": "src/components/**", + "to_glob": "src/api/**" + } + ], + "fts5": true +} diff --git a/fixtures/minimal/README.md b/fixtures/minimal/README.md index aea44ecf..18a1f3fc 100644 --- a/fixtures/minimal/README.md +++ b/fixtures/minimal/README.md @@ -4,24 +4,32 @@ Stable tree exercising every codemap surface — used by `src/benchmark.ts`, gol ## What's exercised -| Codemap surface | Fixture coverage | -| --------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `symbols` (function / const / interface / class) | `usePermissions`, `createClient`, `setupTransport`, `openSocket`, `handshake`, `legacyClient`, `now`, `nanoseconds`, `_epochSeconds`, `_hiResEpoch`, `epochMs`, `nowIso`, `FormatPrice`, `ShopButton`, `ProductCard`, `get`, `invalidate`, `read`, `write`, `run` | -| `imports` / `exports` (named + default + re-export) | `consumer.ts` named imports; `components/shop/index.ts` barrel re-exports; `ShopButton.default.ts` default export | -| `dependencies` (resolved file→file edges) | TS imports across `api/`, `lib/`, `components/shop/`, `utils/`, `usePermissions` | -| `components` (React) | `ShopButton`, `ProductCard` (both call `usePermissions` — fan-in) | -| `calls` (caller→callee, depth >1, with cycle) | `run → createClient → setupTransport → openSocket → handshake`; non-cyclic `cache.get → store.read`; 2-node cycle `cache.invalidate ↔ store.write` | -| `markers` (TODO / FIXME / HACK / NOTE) | `notes.md` + `consumer.ts` (`XXX` is not yet a recognised kind) | -| `type_members` | `ClientConfig`, `Transport`, `ProductCardProps` | -| Visibility tags (`@internal` / `@beta` / `@alpha` / `@private`) | `_epochSeconds`, `nowIso`, `nanoseconds`, `_hiResEpoch` | -| `@deprecated` | `now`, `legacyClient`, `epochMs` (3 rows for SARIF / GH-annotations) | -| `css_variables` | `theme.css` (`--color-brand`, `--spacing-md`) | -| `css_classes` | `theme.css` (`.container`), `button.module.css` (`.primary`) | -| `css_keyframes` | `button.module.css` (`fadeIn`) | -| `--group-by owner` | `CODEOWNERS` (4 owners) | -| Project-local recipes | `.codemap/recipes/shop-symbols.{sql,md}` (with frontmatter actions) — file shape valid; loader currently runs at parse time before bootstrap, so `--recipe shop-symbols` is rejected as "unknown" until that's deferred to the runner (known limitation) | -| Self-managed `.gitignore` | `.codemap/.gitignore` (codemap-managed) | -| `coverage` (Istanbul + LCOV ingest) | `coverage/coverage-final.json` (Istanbul) + `coverage/lcov.info` (LCOV) — equivalent partial coverage shape; bundled recipes `untested-and-dead`, `files-by-coverage`, `worst-covered-exports` exercise the `coverage ↔ symbols` join across exported functions of every visibility tag (`@deprecated`, `@internal`, `@alpha`, `@private`, untagged) | +| Codemap surface | Fixture coverage | +| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Tier 1 — position + calls + imports** | Column-precise `symbols` / `imports` / `markers`; `calls.{args_count,is_method_call,is_constructor_call,is_optional_chain}` (`consumer.ts` spread + `new ApiCache()` + optional chain); side-effect `import_specifiers` (`polyfill.ts`); `import_id` FK | +| **Tier 2 — references / bindings** | `find-references`, `find-write-sites`, `find-symbol-references`, `find-re-exported-bindings` via shop barrel + `consumer.ts` | +| **Tier 3 — JSX** | `ProductCard.tsx` — fragments, nested elements, spread/boolean/expression attrs, self-closing ``, lowercase tags | +| **Tier 4 — types on symbols** | `return_type` / `is_async` on `prefetch`; `@param` / `@returns` / `@throws` → `jsdoc_tags` on `createClient` | +| **Tier 5 — behavioral** | `await` in loop (`prefetch`); swallowed catch (`cache.ts`); `catch_rethrows` heuristics (`complexity-fixture.ts`); `@sealed` decorator (`decorated.ts`); `@throws` jsdoc | +| **Tier 6 — module graph** | `files.is_barrel` (`components/shop/index.ts`); `has_side_effects` (`polyfill.ts`); `dynamic_imports` (`prefetch`) | +| **`symbols`** | function / const / interface / class / enum / method; visibility + `@deprecated` tags | +| **`imports` / `exports`** | Named, default, namespace (`date` util), re-exports, side-effect import | +| **`dependencies`** | Resolved edges + 2-node cycle (`cache ↔ store`) + boundary violation (`ApiBridge → api`) | +| **`components`** | `ShopButton`, `ProductCard` — `usePermissions` fan-in; `components-touching-deprecated` via `now()` | +| **`calls`** | Depth >1 chain (`createClient → … → handshake`); cycle edges; optional chain; constructor; spread args | +| **`markers`** | `notes.md` + inline `FIXME`/`HACK` in `consumer.ts` / `format.ts` | +| **`type_members`** | `ClientConfig`, `Transport`, `ProductCardProps` | +| **`css_*`** | Variables, classes, keyframes, `@import` | +| **`test_suites`** | `src/__tests__/smoke.test.ts` — skip / only / todo / nested describe (vitest) | +| **`file_metrics` / complexity** | `lib/complexity-fixture.ts` — `large-functions`, `deeply-nested-functions`, `high-complexity-untested`, `catch_rethrows` heuristics | +| **`runtime_markers`** | `console.*`, `process.env` (`env.ts`), `throw` path in cache | +| **`suppressions`** | `codemap-ignore-next-line` in `orphan.ts` | +| **`boundaries`** | `.codemap/config.json` — `ui-no-api` deny rule → `boundary-violations` recipe | +| **`fts5`** | `fts5: true` in config — powers `text-in-deprecated-functions` | +| **`coverage`** | Istanbul + LCOV under `coverage/` — killer recipes + refactor-risk | +| **`orphan` exports** | `orphan.ts` — `unimported-exports` | +| **Project-local recipes** | `.codemap/recipes/shop-symbols.{sql,md}` | +| **`CODEOWNERS`** | `--group-by owner` | ## Use @@ -29,20 +37,14 @@ Stable tree exercising every codemap surface — used by `src/benchmark.ts`, gol # Index the fixture from the codemap repo CODEMAP_ROOT="$(pwd)/fixtures/minimal" bun run dev --full +# Golden queries (updates goldens after fixture changes) +bun run test:golden -- --update + # Benchmark CODEMAP_ROOT="$(pwd)/fixtures/minimal" bun run benchmark -# Project-local recipe (known limitation: currently rejected as "unknown" — see -# the "Project-local recipes" row above; will work once recipe loading is -# deferred past bootstrap) -CODEMAP_ROOT="$(pwd)/fixtures/minimal" bun src/index.ts query --recipe shop-symbols --json - -# Static coverage ingest — Istanbul (every modern JS test runner that emits -# coverage-final.json) or LCOV (e.g. `bun test --coverage`). Format auto-detected. +# Coverage ingest + killer recipe CODEMAP_ROOT="$(pwd)/fixtures/minimal" bun src/index.ts ingest-coverage coverage/coverage-final.json -CODEMAP_ROOT="$(pwd)/fixtures/minimal" bun src/index.ts ingest-coverage coverage/lcov.info - -# After ingest — the killer recipe (exported + no callers + zero coverage) CODEMAP_ROOT="$(pwd)/fixtures/minimal" bun src/index.ts query --recipe untested-and-dead --json ``` diff --git a/fixtures/minimal/src/__tests__/smoke.test.ts b/fixtures/minimal/src/__tests__/smoke.test.ts new file mode 100644 index 00000000..658faf8f --- /dev/null +++ b/fixtures/minimal/src/__tests__/smoke.test.ts @@ -0,0 +1,25 @@ +import { describe, expect, it } from "vitest"; + +import { labyrinth } from "../lib/complexity-fixture"; + +describe("smoke", () => { + it.skip("skipped example", () => { + expect(labyrinth(0)).toBe(0); + }); + + it.only("focused example", () => { + expect(labyrinth(1)).toBeGreaterThanOrEqual(0); + }); + + it.todo("todo example"); + + it("passing", () => { + expect(1).toBe(1); + }); +}); + +describe("nested suite", () => { + it("inner case", () => { + expect(true).toBe(true); + }); +}); diff --git a/fixtures/minimal/src/api/client.ts b/fixtures/minimal/src/api/client.ts index ec52a6c4..b5cc09c8 100644 --- a/fixtures/minimal/src/api/client.ts +++ b/fixtures/minimal/src/api/client.ts @@ -12,6 +12,11 @@ export interface Transport { readonly handshakeMs: number; } +/** + * @param config Client connection settings + * @returns A lightweight client handle + * @throws {Error} when config is invalid + */ export function createClient(config?: ClientConfig) { const transport = setupTransport( config?.baseUrl ?? "https://api.example.com", diff --git a/fixtures/minimal/src/api/decorated.ts b/fixtures/minimal/src/api/decorated.ts new file mode 100644 index 00000000..aab42bc1 --- /dev/null +++ b/fixtures/minimal/src/api/decorated.ts @@ -0,0 +1,4 @@ +function sealed(_target: unknown) {} + +@sealed +export class ApiCache {} diff --git a/fixtures/minimal/src/components/shop/ApiBridge.tsx b/fixtures/minimal/src/components/shop/ApiBridge.tsx new file mode 100644 index 00000000..eace03b0 --- /dev/null +++ b/fixtures/minimal/src/components/shop/ApiBridge.tsx @@ -0,0 +1,7 @@ +import { createClient } from "~/api/client"; + +/** Boundary-violation fixture: `src/components/**` → `src/api/**`. */ +export function ApiBridge() { + createClient(); + return null; +} diff --git a/fixtures/minimal/src/components/shop/ProductCard.tsx b/fixtures/minimal/src/components/shop/ProductCard.tsx index 9b8a4107..ef571dc4 100644 --- a/fixtures/minimal/src/components/shop/ProductCard.tsx +++ b/fixtures/minimal/src/components/shop/ProductCard.tsx @@ -1,19 +1,22 @@ import { usePermissions } from "../../usePermissions"; +import { now } from "../../utils/date"; interface ProductCardProps { readonly id: number; readonly title: string; } -// React component fixture — exercises `components` table fan-in to -// `usePermissions` (also used by ShopButton.tsx); pair with the barrel -// re-export in `./index.ts` to surface fan-in via the `dependencies` graph. +// React component fixture — JSX substrate (fragments, attrs, nesting, lowercase tags). export function ProductCard(props: ProductCardProps) { const perms = usePermissions(); + const spread = { className: "card" }; return ( -
-

{props.title}

- {perms.canEdit ? : null} -
+ <> + + ); } diff --git a/fixtures/minimal/src/components/shop/ShopButton.tsx b/fixtures/minimal/src/components/shop/ShopButton.tsx index f0dd05d0..168c6b12 100644 --- a/fixtures/minimal/src/components/shop/ShopButton.tsx +++ b/fixtures/minimal/src/components/shop/ShopButton.tsx @@ -1,4 +1,5 @@ import { usePermissions } from "../../usePermissions"; +import { now } from "../../utils/date"; export function FormatPrice(cents: number): string { return `$${(cents / 100).toFixed(2)}`; @@ -6,6 +7,7 @@ export function FormatPrice(cents: number): string { export function ShopButton() { const perms = usePermissions(); + const _stamp = now(); return (