Repository navigation
fix(extraction): a build folder inside src/ is indexed for its TypeScript, JSX, Vue, Svelte and Astro files - #2681
Merged
Conversation
…ript, JSX, Vue, Svelte and Astro files The default ignore list skipped every folder named build as build output, so a JS/TS feature kept in one, like luci-go milo's src/build/, was never indexed and the routes that lazily load its pages linked nothing. A build folder below src/ is now walked, and its hand-written source (.ts .tsx .mts .cts .ets, .jsx, .vue, .svelte, .astro, never .d.ts) is indexed. What a build step may have written there, JavaScript and every other type, stays out, as does every build folder outside src/. JVM packages named build keep every file (#1642). The project's own root rules still decide first: an exclude excludes the folder, and re-including it (!src/build/) keeps every type, as before. The rule reads paths only and lives in the two default matchers every scope consumer builds on, so the full index, the git-status sync, scoped sync and the watcher share it (#1728). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 19, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The default ignore list skips every folder named
build, at any depth, as build output (DEFAULT_IGNORE_DIRS→build/). JVM source roots were already exempt (#1642). JS/TS apps keep real source there too. luci-go's milo/ui keeps its whole LUCI "build" feature insrc/build/(src/build/legacy/build_page/build_page.tsx,src/build/pages/builder_page/…). A fresh index of it had 0 files undersrc/build/, so its routes' 19 lazy loads into@/build/...could never link, and none of that feature was visible tocodegraph_explore.The rule
Inside a
src/folder, a folder namedbuild(any case) is walked. Only the files no compiler or bundler writes are indexed from it:.ts,.tsx,.mts,.cts, ArkTS.ets),.jsx,.vue,.svelteand.astro..d.tsdeclarations, JavaScript (.js,.mjs,.cjs) and every other type, since a build may have written them. Everybuild/folder outsidesrc/also stays out, whatever it holds.Unchanged:
src/build/node_modules/,src/build/dist/).buildkeep every file, as with codegraph explore "RealtimePlusService" No relevant code found for "RealtimePlusService" #1642..gitignoreorcodegraph.jsonexcludeof the folder excludes it;!src/build/, the documented opt-in) keeps every type in it, as before.Implementation, all in
src/extraction/index.ts:'!**/src/**/build/'joinsDEFAULT_IGNORE_PATTERNS.buildDefaultIgnore/defaultsOnlyIgnorereturn a matcher whoseignores()applies the per-file rule on top of the patterns.ScopeIgnore(scoped sync and the watcher), and theincludecollector. So the indexer, sync and watcher share one scope (Watcher scope diverges from indexer scope (.git/info/exclude, nested .gitignore) and every file event forces a full-project reconcile — 174k handles, 1.5-142s per single-file sync #1728).Why this rule: measured first
file:(^|/)src/(.+/)?build/, exhaustive: 200,725 files in 3,572 repos, grouped into 8,147build/folders. Leaving out folders inside another default-ignored folder (a committednode_modulesetc.) and JVM roots:packages/next/src/build, astro'ssrc/core/build, docusaurus, nx executors, twenty, payload, mastra, pnpm, backstage, kibana, shopware, stencil, nitro, vitepress, RuoYi'ssrc/views/tool/build/*.vue, milo. Six also hold output markers. These are mixed folders (a build script beside its output), and one of them only has TypeScript inside its own committednode_modules/, which stays excluded.pdf.worker.js, three.js, toastr, bootstrap plugins, YUI, CRA and Vite builds of apps nested undersrc/, Chrome devtools extension builds, Symfony Encore and Laravelpublic/build, WordPresswp-includes/build, Moodleamd/build, Vaadin bundles, Sphinx HTML. The rest is real JavaScript (SvelteKit'ssrc/exports/vite/build/*.js, three-mesh-bvh, Yoast).static/,public/,assets/,resources/,webapp/orwwwroot/ancestors would drop source (astro'ssrc/assets/build, primate'ssrc/public/build, komodo'sui/src/resources/build, shopware) and still keep 60+ output folders.package.jsonundersrc/is either output (only JavaScript) or build tooling (kibana'ssrc/dev/build, shopware's Vite plugins, both TypeScript). The per-file rule handles both without reading the disk.src/build/only. 4,648.ts, 151.tsx, 117.vuefiles against 2,176.js. 479 folders were classified by listing each repo's tree:.py, which is why Python stays out of the rule.build/folders belowsrc/. All three are TypeScript.Considered and not done:
require('../build/main.js'), a SvelteKit adapter'sbuild/handler.js). The scope would also depend on file contents, so the watcher and sync would need persisted state to agree with the indexer.Verification
__tests__/src-build-folders.test.ts, 6 tests:buildDefaultIgnore,buildScopeIgnore,scanDirectory,scanDirectoryAsync, every folder on the way walkable);!src/build/opt-in;@/build/...link, and an edit, a new page and new output undersrc/build/go throughgetGitChangedFilesandcg.sync();srcevents are dropped, and a removed subfolder schedules the full reconcile.src/extraction/index.tsof origin/main 24ea3c5 and pass with the change.react-router-lazy-barrel.test.tsheader said its fixture had to avoidbuild/. That comment is updated.tsc --noEmitis clean.CODEGRAPH_KERNEL_EXPECT=1,--maxWorkers=4 --minWorkers=1): 7,595 tests, 7,515 passed, 0 failed, 80 skipped.extraction.test.ts(including the codegraph explore "RealtimePlusService" No relevant code found for "RealtimePlusService" #1642 suite),watcher.test.tsand every kernel parity suite: 19 files, 1,073 tests, all passed, none skipped.A/B on real repos
Arms: origin/main 24ea3c5, and this branch on it. They differ only in
dist/extraction/index.js, and both carry the same kernel. Each repo was indexed fresh withcodegraph init -yand dumped withscripts/dump-graph.mjs.src/build/, +5 generated protos insrc/proto/**/build/)packages/astro).vue)packages/docusaurus)milo: every one of the 19 lazy-route refs into
@/build/...now links.22 controls byte-identical between arms:
src/:server/src/main/resources/static/;build/nested in Games-and-Go'ssrc/, and Mimi.jl'ssrc/explorer/mimiexplorer-app/build;src/main/webapp/build;src/public/build;src/extension/build;src/build.package.json: supertokens/dashboard, mihailgaberov/chat.build/tooling;src/build/package, which stays out because it isn't JS/TS;src/exports/vite/build.src/: excalidraw, bulletproof-react, react-redux-realworld, proshop-v2, takenote, create-t3-turbo, matx, mantis, Folo, ghostfolio.Triage of every edge that changed outside the newly indexed files:
useBuildsClientcalls and imports from@/build/hooks/prpc_clientshad been name-matched to a namesake insrc/common/hooks/../build/assets.ts,../../src/build/virtual/{app,cache,public-assets}.tsand../../src/build/unbundled/plugins.tshad been guessed onto other files and now resolve as imports.remote.test.tsimportsdist/assets/build/remote.jsand now reachessrc/assets/build/remote.ts.router.tsx.this.getModuleInfo()(6 calls),import build from '../dist/core/build/index.js'and zod'sz.output;}).start().import download from './download'passed as$downloadhad been linked to adownloadfunction insrc/utils/request.js. With a third namesake it is left unresolved, and silent beats wrong.PartDetailrenders more thanMAX_JSX_CHILDREN(30) components.BuildOrderTablefromsrc/tables/build/now takes the 30th slot, and the laterPageDetailtag falls past the cap. It has 30 children in both arms.src/gitiles/components/commit_table/context/index.tswritesexport { DefaultExpandedProvider, … } from './context'. The named re-exports resolve by name match, not through./context, on main too.src/build/components/build_table/context.tsdeclares the same two constants, and the match moves there.buildfolder involved:export { Provider } from './context'links to another file'sProvider. I'll fix that separately (see Follow-ups).Cost: the extra files only. Index times are within noise (milo 35.5 s → 32.0 s, nitro 7.6 s → 8.3 s, astro 17.8 s → 16.0 s).
Upgrading:
codegraph syncwith this build adds thesrc/build/files to an index main built, on the git path (docusaurus) and in a plain folder (milo), so no re-index is needed.Follow-ups (separate PRs)
export { X } from './m') resolve through the module they name, not by name.src/go/build), 294 in 222 for Rust (turbopack, tauri, dioxus) and 130 in 77 for C# (roslyn, dotnet/wpf). PHP (WordPress writesbuild/*.php) and Python (frozen apps copy.pyintobuild/) are not safe.Not done:
build(SvelteKit'ssrc/exports/vite/build). In the survey they are as often output as source, and no path-only signal tells them apart.src/(config/build/*.tswebpack configs, VS Code'sbuild/tooling).🤖 Generated with Claude Code