Skip to content

fix(resolution): inherit tsconfig baseUrl through extends - #3591

Open
DevChiniwala wants to merge 4 commits into
Graphify-Labs:v8from
DevChiniwala:fix/2200-tsconfig-baseurl-extends
Open

DevChiniwala wants to merge 4 commits into
Graphify-Labs:v8from
DevChiniwala:fix/2200-tsconfig-baseurl-extends

Conversation

@DevChiniwala

@DevChiniwala DevChiniwala commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes #2200 by resolving baseUrl through local tsconfig/jsconfig extends chains. Each declaration is relative to its own config, later parents take precedence, and the child overrides its parents. JSONC, null options, circular chains, and absolute Windows/UNC path guards remain covered.

The audit follow-up fixes diamond inheritance: when two parents share an ancestor, the later parent's inherited baseUrl must still override the earlier parent's explicit value. Cycle detection now receives a separate ancestor set for each branch. TypeScript 5.8.3 independently produces the same effective base URL as the new extraction regression.

This complements #2355's ${configDir} expansion work; it does not implement package-based extends resolution.

Current validation

At 2ddb6529c8b6a914f845680d4e83b344866ae7a5:

  • The new shared-ancestor extraction regression fails before the follow-up, resolving to left-src; afterward it resolves to shared-src, matching TypeScript.
  • BaseUrl and JS import-resolution suites: 108 passed on Windows/Python 3.14.8 with frozen all-extras dependencies.
  • Whole-repository Ruff passes; all 134 skill-generation artifacts match.
  • graphify update . completes in AST-only mode; local graph output is not committed.
  • Pyright remains non-green: the same 632 diagnostic signatures occur before and after this follow-up, with none added.
  • The complete 7,771-case Windows collection was accounted for across the original run and its continuation: 7,723 passed, 44 skipped, four failed. All four failures also reproduce on unchanged merge base a9860f70dc3cc2e9c2d8cb923484cfa0592b9067 (three hook runtime/path failures and one relative-root watch-path expectation). This is not a clean full-suite pass.
  • Diff hygiene passes. The current pushed commit needs its own GitHub version-matrix and other check results.

Compatibility

Nearest-config behavior and child overrides are preserved. Dynamic/package config loading remains outside this first-pass resolver. The previous absolute-path advisory is addressed for POSIX absolute paths and Windows drive/UNC forms, including tests running on another host platform.

AI-assisted audit, regression and follow-up fix: Codex (commit trailer included).

Copilot AI lite review requested due to automatic review settings September 16, 2026 05:45

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@graphify-labs graphify-labs Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.

Formal verification. No changes could be formally verified in this run.


Graphify review — findings

Resolves compilerOptions.baseUrl through a tsconfig's extends chain via the new _read_tsconfig_base_url, with each config's baseUrl taken relative to its own directory, later parents overriding earlier ones, and the child config winning over all parents. Hardens _read_tsconfig_aliases and the baseUrl reader against malformed configs by coercing non-dict compilerOptions/paths (including compilerOptions: null) to empty, so JSONC parents and broken options no longer abort resolution. Adds tests covering inherited baseUrl, child-over-parent override, and the malformed-config cases.

Worth a look

  • Absolute tsconfig extends can load baseUrl from outside the workspace — graphify/extractors/resolution.py:264 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 1991 functions depend on the 186 functions this change touches.

Health — this change adds coupling hotspots:

  • new: extract() — 640 callers, 45 callees
  • new: _rebuild_code() — 123 callers, 53 callees
  • new: _extract_generic() — 18 callers, 29 callees
  • new: extract_js() — 85 callers, 4 callees
  • new: extract_xaml() — 19 callers, 17 callees
  • new: _resolve_js_module_path() — 34 callers, 9 callees
  • new: dispatch_command() — 2 callers, 125 callees
  • new: extract_objc() — 27 callers, 9 callees
  • …and 36 more — each is listed as a finding

Verification — 1991 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 892 function(s) in the blast radius were not formally verified this run

Test selection

Test selection

35 of 283 test file(s) selected (12%) via static blast radius.

  • tests/test_astro_extraction.py — impact
  • tests/test_build.py — impact
  • tests/test_cjs_module_extension.py — impact
  • tests/test_cpp_nested_and_cli.py — impact
  • tests/test_dotnet.py — impact
  • tests/test_extract.py — impact
  • tests/test_forwarding_review_findings.py — impact
  • tests/test_import_extension_resolution.py — impact
  • tests/test_indirect_dispatch.py — impact
  • tests/test_indirect_dispatch_assign_return.py — impact
  • tests/test_indirect_dispatch_getattr.py — impact
  • tests/test_js_exported_scalar_bindings.py — impact
  • tests/test_jsconfig_baseurl.py — impact, changed-test
  • tests/test_languages.py — impact
  • tests/test_multilang.py — impact
  • tests/test_package_json_subpath_imports.py — impact
  • tests/test_pascal.py — impact
  • tests/test_pascal_resolution.py — impact
  • tests/test_phantom_external_import.py — impact
  • tests/test_python_import_resolution.py — impact
  • tests/test_python_parse_memoization.py — impact
  • tests/test_python_underscore_resolution.py — impact
  • tests/test_rationale.py — impact
  • tests/test_resolve_memoization.py — impact
  • tests/test_ruby_resolution.py — impact
  • tests/test_scala_self_type.py — impact
  • tests/test_source_key_memoization.py — impact
  • tests/test_src_layout_import_resolution.py — impact
  • tests/test_swift_computed_properties.py — impact
  • tests/test_trailing_newline_not_a_syntax_error.py — impact
  • tests/test_ts_new_expression_calls.py — impact
  • tests/test_typescript_module_extensions.py — impact
  • tests/test_unmapped_at_alias_resolution.py — impact
  • tests/test_vue_extraction.py — impact
  • tests/test_walk_python_tree_iterative.py — impact

Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.

Formal verification

Could not verify: Could not verify \_load\_tsconfig\_base\_url.

The verifier did not have enough to check \_load\_tsconfig\_base\_url, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: no capturable inputs from the test suite; property tier: parameter `start_dir` is annotated `Path` — outside the synthesizable primitive/collection set

Could not verify: Could not verify \_read\_tsconfig\_aliases.

The verifier did not have enough to check \_read\_tsconfig\_aliases, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: no capturable inputs from the test suite; property tier: parameter `tsconfig` is annotated `Path` — outside the synthesizable primitive/collection set

· 44 more finding(s) on lines outside this diff (see the check run).

@DevChiniwala

Copy link
Copy Markdown
Contributor Author

Addressed the absolute tsconfig extends advisory in 1160bb3. Config inheritance now ignores absolute/drive/UNC extends paths for both baseUrl and aliases, while preserving relative local extends; the regression test verifies an external config contributes neither setting. Verification: focused tests (17 passed), and GitHub CI passed on Python 3.10, 3.12, 3.13, 3.14, security-scan, and skillgen-check.

@DevChiniwala
DevChiniwala force-pushed the fix/2200-tsconfig-baseurl-extends branch from 1160bb3 to b6b0335 Compare October 13, 2026 02:25
@DevChiniwala

Copy link
Copy Markdown
Contributor Author

Follow-up validation after upstream advanced to v0.9.88:

  • rebased the branch onto current v8
  • added regression coverage for Windows drive-letter and UNC extends paths, including POSIX-hosted test execution
  • focused resolver/import suites: 131 passed
  • Ruff: passed
  • graphify update .: completed; only expected optional-parser and local permission warnings were emitted

The branch was updated with --force-with-lease; no unrelated files are included.

Keep cycle detection local to each extends branch so later parents can inherit a shared ancestor again. The extraction regression matches TypeScript configuration precedence.

Co-Authored-By: Codex <noreply@openai.com>
@DevChiniwala

Copy link
Copy Markdown
Contributor Author

The audit found a shared-parent precedence defect and fixed it in 2ddb652. Cycle detection now stays within each inheritance path, so a later parent can inherit the same ancestor again. The real extraction regression fails before the change and matches TypeScript 5.8.3 afterward.

Validation: 108 resolver/import tests, whole-repository Ruff, all 134 generated-artifact checks, and AST graph update pass. The complete Windows collection is accounted for: 7,723 passed, 44 skipped, and four failures that also reproduce on unchanged base. Pyright retains the same 632 diagnostics; neither check is represented as a clean pass.

The normal push is verified. The description now records this evidence and the remaining current-head CI gate.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JS/TS resolution: honor baseUrl declared in an extended tsconfig, and add a JSONC config test

2 participants