fix(svelte): stamp dynamic-import stub source_file to target, not importer (#712)#715
Open
jippi wants to merge 1 commit intosafishamsi:v7from
Open
fix(svelte): stamp dynamic-import stub source_file to target, not importer (#712)#715jippi wants to merge 1 commit intosafishamsi:v7from
jippi wants to merge 1 commit intosafishamsi:v7from
Conversation
…orter (safishamsi#712) When extract_svelte()'s regex pass for `import('...')` resolved a target path (relative or via tsconfig alias) and created a stub node for it, the stub's source_file was stamped to str(path) — the IMPORTER's path, not the target's path. build_from_json does last-write-wins on node attributes (G.add_node overwrites). When the target file is later extracted by _extract_generic on its own, both nodes share the same id (_make_id(str(target))) and merge. Whether the stub's wrong source_file or the real correct one wins depends purely on file-iteration order — non-deterministic. Effect: downstream tools that read source_file off file nodes (display, "where is X defined", blast-radius queries, community summaries) see the file as living inside whichever component first imported it. On a real 1,873-file SvelteKit codebase, 16 .svelte file nodes were corrupted this way — every dynamically-imported component sampled. The fix threads the resolved target path through to source_file: - relative imports use str(resolved) - alias imports use str(resolved_alias) - bare/scoped externals leave source_file empty (we genuinely don't know where node_modules live, and stamping the importer would lie) The stub edge's source_file is unchanged — that legitimately is the importer (where the import statement lives). 7 new tests in tests/test_svelte_dynamic_import_stub.py: - relative import stub points to target - relative import stub does NOT carry importer's path - alias import resolves and points to target - two importers of same target produce consistent source_file - stub doesn't clobber target's own extraction (merge-order safety) - bare-module stub doesn't claim to be importer - dynamic_import edge source_file remains the importer (no over-correction) 6 of 7 fail against unpatched v7 (proving they're real regression guards); the 7th is the over-correction check which intentionally documents what should NOT change.
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.
Fixes #712. Independent of #714 — branched off
v7, applies cleanly with or without #714 merged first.Problem
extract_svelte()'s regex pass forimport('...')resolved a target path (relative or via tsconfig alias) and created a stub node for it — but stamped the stub'ssource_filetostr(path), which is the importer's path, not the target's.build_from_jsondoes last-write-wins on node attributes (G.add_nodeoverwrites). When the target file is later extracted by_extract_genericon its own, both nodes share the same id (_make_id(str(target))) and merge. Whether the stub's wrongsource_fileor the real correct one wins depends purely on file-iteration order — non-deterministic.Effect: downstream tools that read
source_fileoff file nodes (display, "where is X defined", blast-radius queries, community summaries) see the file as living inside whichever component first imported it. On a real 1,873-file SvelteKit codebase, 16.sveltefile nodes were corrupted this way — every dynamically-imported component sampled.Fix
Thread the resolved target path through to
source_file:str(resolved)$lib/...) →str(resolved_alias)source_fileempty (we genuinely don't know wherenode_moduleslive, and stamping the importer would lie)The stub edge's
source_fileis unchanged — that legitimately is the importer (where the import statement lives). Edge vs node distinction is preserved.Tests
7 new tests in
tests/test_svelte_dynamic_import_stub.py:test_relative_dynamic_import_stub_points_to_targettest_relative_dynamic_import_stub_does_not_carry_importer_pathtest_alias_dynamic_import_stub_points_to_resolved_path$lib/...aliases resolve correctlytest_two_importers_agree_on_target_source_filetest_target_extraction_does_not_clobber_correct_source_filetest_bare_module_dynamic_import_does_not_corrupt_source_filetest_dynamic_import_edge_source_file_is_importer6 of 7 fail against unpatched v7 — confirming they're real regression guards. The 7th is the over-correction check that intentionally documents what should NOT change (edge source_file remains the importer).
Test plan
pytest tests/test_svelte_dynamic_import_stub.py— 7/7 passpytest tests/— 556 pass, 7 pre-existing failures unrelated to this change