From 5f5b59309c617949de46b8064d8d64b8aca55861 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Mon, 4 May 2026 22:47:29 +0200 Subject: [PATCH] test(extract): cover .svelte.js + hybrid TS/JS Svelte 5 rune files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The generalized resolver already handles .svelte.js because the append loop iterates _JS_RESOLVE_EXTS = (.ts, .tsx, .svelte, .js, .jsx, .mjs). Adds three explicit tests to pin the behaviour and document the priority choice: - test_resolve_svelte_to_svelte_js_for_javascript_rune_files JS-only Svelte 5 project: .svelte → .svelte.js works the same way as .svelte.ts in TS projects. No special-casing needed — the generalized append loop covers both. - test_resolve_svelte_prefers_svelte_ts_over_svelte_js Hybrid case (both files exist, e.g. .svelte.ts source plus .svelte.js build artifact): .ts wins. Documents the deliberate source-first priority — graphify is a source-code tool, not a runtime resolver, so we differ from Vite's default JS-first order. - test_resolve_real_svelte_file_wins_over_svelte_ts_sibling Existence check short-circuits before any extension append, so a real .svelte file always wins over a .svelte.ts sibling. --- tests/test_import_extension_resolution.py | 45 +++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tests/test_import_extension_resolution.py b/tests/test_import_extension_resolution.py index e81c35cd..c57122e3 100644 --- a/tests/test_import_extension_resolution.py +++ b/tests/test_import_extension_resolution.py @@ -89,6 +89,51 @@ def test_resolve_svelte_to_svelte_ts_for_rune_files(tmp_path): ) +def test_resolve_svelte_to_svelte_js_for_javascript_rune_files(tmp_path): + """JS variant of the rune file pattern: a `.svelte.js` file (used in + JavaScript-only Svelte 5 projects, no TypeScript). `from './foo.svelte'` + must resolve to `foo.svelte.js` when no `.ts` variant exists. + + Same code path as the .svelte.ts case — the generalized resolver tries + every extension in priority order, so JS-only and TS-only projects + both work without special-casing.""" + target = _write(tmp_path / "store.svelte.js", + "export const count = $state(0)") + written_as = tmp_path / "store.svelte" + resolved = _resolve_js_module_path(written_as) + assert resolved == target + + +def test_resolve_svelte_prefers_svelte_ts_over_svelte_js(tmp_path): + """When both `.svelte.ts` and `.svelte.js` exist (hybrid project mid- + migration, or a build artifact alongside the source), `.ts` wins — + matching the resolver's stated TypeScript-first priority order. + + Note: Vite's default `resolve.extensions` puts `.js` before `.ts`, but + in practice TypeScript codebases that emit `.svelte.js` build artifacts + expect tooling to read the `.svelte.ts` source. graphify is a source- + code tool, not a runtime resolver, so source-first ordering is correct + for our use case.""" + ts_target = _write(tmp_path / "store.svelte.ts", + "export const count = $state(0)") + _write(tmp_path / "store.svelte.js", + "export const count = 0 // build artifact") + written_as = tmp_path / "store.svelte" + resolved = _resolve_js_module_path(written_as) + assert resolved == ts_target + + +def test_resolve_real_svelte_file_wins_over_svelte_ts_sibling(tmp_path): + """If `foo.svelte` IS a real markup file, importing `./foo.svelte` + must resolve to that — not get hijacked to a sibling `foo.svelte.ts` + rune file. The existence-check short-circuits before any append.""" + real = _write(tmp_path / "Card.svelte", "
card markup
") + _write(tmp_path / "Card.svelte.ts", + "export const helpers = {} // rune sibling, not the import target") + resolved = _resolve_js_module_path(real) + assert resolved == real + + def test_resolve_js_to_ts_when_real_file_is_ts(tmp_path): """TS ESM convention: imports written as .js but the actual file is .ts.""" target = _write(tmp_path / "foo.ts", "export const x = 1")