mirror of
https://github.com/safishamsi/graphify.git
synced 2026-07-13 02:47:00 +00:00
Fix: support array form of tsconfig extends (TypeScript 5.0) (#1017)
TS 5.0 allows `"extends": ["./a", "./b"]`. _read_tsconfig_aliases called
`extends.startswith("@")` directly, so an array raised
`AttributeError: 'list' object has no attribute 'startswith'`. _safe_extract
caught it and skipped the WHOLE file — and since alias resolution fires on any
path-aliased import, every TS file using `@/`-style imports in a repo with
array-extends tsconfig was dropped, yielding an empty graph.
Normalize `extends` to a list (str -> [str], list kept, else []), process
entries in order (later overrides earlier, current config's paths override all
parents per TS semantics), and skip scoped npm configs (`@...`) per entry as
before.
Adds regression test test_tsconfig_array_extends_alias_resolves_existing_ts_file.
This commit is contained in:
+17
-2
@@ -190,9 +190,24 @@ def _read_tsconfig_aliases(tsconfig: Path, base_dir: Path, seen: set) -> dict[st
|
||||
return {}
|
||||
|
||||
aliases: dict[str, str] = {}
|
||||
# `extends` may be a string or, since TypeScript 5.0, an array of paths.
|
||||
# For an array, parents are processed in order with later entries
|
||||
# overriding earlier ones; the extending config (paths below) overrides
|
||||
# all parents. Without the list branch, an array `extends` raised
|
||||
# `AttributeError: 'list' object has no attribute 'startswith'`, which
|
||||
# _safe_extract turned into a skip of the whole file.
|
||||
extends = data.get("extends")
|
||||
if extends and not extends.startswith("@"):
|
||||
extended_path = (base_dir / extends).resolve()
|
||||
if isinstance(extends, str):
|
||||
extends_list = [extends]
|
||||
elif isinstance(extends, list):
|
||||
extends_list = [e for e in extends if isinstance(e, str)]
|
||||
else:
|
||||
extends_list = []
|
||||
for ext in extends_list:
|
||||
# Skip scoped npm package configs (e.g. @tsconfig/svelte) — not on disk.
|
||||
if not ext or ext.startswith("@"):
|
||||
continue
|
||||
extended_path = (base_dir / ext).resolve()
|
||||
if not extended_path.suffix:
|
||||
extended_path = extended_path.with_suffix(".json")
|
||||
if extended_path.exists():
|
||||
|
||||
@@ -334,6 +334,32 @@ def test_tsconfig_alias_import_resolves_existing_ts_file(tmp_path: Path):
|
||||
assert _has_edge(result, "src/routes/page.ts", "src/lib/types/type-helpers.ts")
|
||||
|
||||
|
||||
def test_tsconfig_array_extends_alias_resolves_existing_ts_file(tmp_path: Path):
|
||||
# TypeScript 5.0 allows `extends` as an array; later entries override
|
||||
# earlier ones. The `paths` alias is inherited from the second parent.
|
||||
# Regression: an array `extends` previously raised
|
||||
# `AttributeError: 'list' object has no attribute 'startswith'`, which
|
||||
# _safe_extract turned into a skip of every file using the alias.
|
||||
_write(tmp_path / "tsconfig.base.json", json.dumps({"compilerOptions": {"strict": True}}))
|
||||
_write(
|
||||
tmp_path / "tsconfig.paths.json",
|
||||
json.dumps({"compilerOptions": {"baseUrl": ".", "paths": {"$lib/*": ["src/lib/*"]}}}),
|
||||
)
|
||||
_write(
|
||||
tmp_path / "tsconfig.json",
|
||||
json.dumps({"extends": ["./tsconfig.base.json", "./tsconfig.paths.json"]}),
|
||||
)
|
||||
target = _write(tmp_path / "src/lib/types/type-helpers.ts", "export type Helper = string\n")
|
||||
importer = _write(
|
||||
tmp_path / "src/routes/page.ts",
|
||||
"import type { Helper } from '$lib/types/type-helpers'\nconst value: Helper = 'x'\n",
|
||||
)
|
||||
|
||||
result = _extract_for([target, importer], tmp_path)
|
||||
|
||||
assert _has_edge(result, "src/routes/page.ts", "src/lib/types/type-helpers.ts")
|
||||
|
||||
|
||||
def test_pnpm_workspace_package_import_resolves_package_entry(tmp_path: Path):
|
||||
_write(
|
||||
tmp_path / "pnpm-workspace.yaml",
|
||||
|
||||
Reference in New Issue
Block a user