Repository navigation
Description
Problem
cants discovers TypeScript files recursively, but type-checks the entire repository with only the single config returned by findProjectConfig(root). In a repository with multiple TypeScript projects, files outside that root config are added to the wrong ts-morph Project, so valid internal types degrade to any and internal call edges disappear.
This is distinct from #53: that issue covers checker-resolved external callees being rejected. This issue covers first-party callees that the checker cannot resolve because the source file is attached to the wrong compiler project.
Reproduction
Analyzed OWASP Juice Shop at 6244c59 with level 2, tests skipped, and dependencies already materialized.
Juice Shop has:
- a root
tsconfig.jsonthat explicitly excludesfrontend/; frontend/tsconfig.json, a solution config referencingfrontend/src/tsconfig.app.jsonandfrontend/src/tsconfig.spec.json.
The generated symbol table contains all frontend files, but every one of the 326 class fields initialized with Angular inject(...) has type: "any".
A conservative audit mapped only calls where:
- the field initializer is
inject(LocalClass); LocalClassis imported from a relative first-party module or declared in the same file;- the target class and method name are unique.
Result: 260 call occurrences / 218 unique internal caller-callee pairs across 55 frontend files are absent from call_graph. None of those 218 pairs is represented.
Examples:
AboutComponent.ngOnInitcallsthis.configurationService.getApplicationConfiguration(), but there is no edge toConfigurationService.getApplicationConfiguration.AboutComponent.populateSlideshowFromFeedbackscallsthis.feedbackService.find(), but there is no edge toFeedbackService.find.- The same pattern affects product, basket, address, challenge, user, payment, and other injected services.
Relevant implementation:
src/build/materialize.ts:findProjectConfig()returns only one root-level config.src/syntactic_analysis/symbolTable.ts: constructs oneProjectwith that config, setsskipAddingFilesFromTsConfig: true, then adds every recursively discovered file to it.
Expected behavior
Each source file should be analyzed under the compiler options and project references that own it. First-party calls through inject(LocalService) should resolve to the local service method.
Acceptance criteria
- Discover and honor solution references and/or nested
tsconfig/jsconfigproject boundaries. - Assign each source file to an appropriate compiler
Program; merge emitted modules and graph edges without duplicate symbol IDs. - In a regression fixture with a root config excluding
frontend/plus a referenced Angular-style project:inject(LocalService)does not becomeany;this.service.method()resolves to the local method signature;- files excluded from one project are not forced into that project's compiler options.
- Preserve
--target-files, cache behavior, and deterministic output.
Activity
feat(analysis): multi-tsconfig program construction — nested programs…