fix(affected): parse multi-line, side-effect, and re-export imports (closes #189)#192
Merged
Merged
Conversation
…loses #189) PR #184 fixed the workspace-as-first-arg heuristic in commands/affected.py so the existing ts_workspace fixture (single-line `import { x } from './y'`) returned affected_count > 0. But get_affected_files still returned affected_count: 0 for three common real-world TS/JS import shapes, because _parse_js_imports silently skipped them — leaving reverse_graph incomplete so BFS had no edges to traverse. Root cause (verified by tracing _build_import_graph output): 1. Multi-line imports — `import {\n foo,\n} from './bar'` The ES import regex used `.*?` which does not cross newlines, so any import statement split across lines (Prettier default, ESLint `multi-line` rule) was silently skipped. 2. Side-effect imports — `import './polyfills'` (no `from` clause) The ES import regex required `from`, so side-effect imports were silently skipped even though they create a real dependency edge. 3. Re-exports — `export { x } from './bar'`, `export * from './bar'`, `export type { Foo } from './bar'` The parser only looked for `import`, never `export ... from`, so barrel files (index.ts re-exporting from core.ts) were invisible to the reverse graph. When the parser misses an import, reverse_graph loses an edge. If the changed file's only inbound edge was the missed import, BFS finds no dependents and affected_count stays at 0 — the "BFS never starts" symptom from issue #189. Fix: - Replace `.*?` with `[\s\S]*?` in the ES import regex so it matches across newlines (multi-line imports). - Add a dedicated `import\s+["']...["']` regex for side-effect imports. The regex is disjoint from the `from` form (requires a quote immediately after import+whitespace), so order does not matter. - Add a new `export\s+[\s\S]*?from\s+["']...["']` regex for re-exports. Tests: 5 new tests in TestIssue189ImportParserPatterns covering multi-line imports, side-effect imports, re-exports, the existing ts_workspace fixture (DoD sanity check), and --include-source with multi-line imports. All 4 bug-exposing tests fail on the pre-fix code and pass after the fix; the 5th (DoD sanity check) passes both before and after. Regression: 63 passed in tests/test_affected_command.py (58 existing + 5 new). 107 passed across affected_command + command_registry + command_count + doctor. 151 passed across parser + formatter + orient suites (5 skipped, pre-existing). No new failures. Definition of Done (issue #189): - [x] codelens affected <ts-workspace> auth/google-auth-cache.ts returns affected_count > 0 (verified via test_existing_ts_workspace_fixture_still_finds_affected) - [x] unresolved[] is empty when input file exists and is imported by other files (asserted in every new regression test) - [x] Use existing ts_workspace fixture and assert affected_count >= 1 (test_existing_ts_workspace_fixture_still_finds_affected)
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
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.



Closes #189
Root Cause (verified)
PR #184 fixed the workspace-as-first-arg heuristic in
commands/affected.pyso the existingts_workspacefixture (single-lineimport { x } from './y') returnedaffected_count > 0. Butget_affected_filesstill returnedaffected_count: 0for three common real-world TS/JS import shapes, because_parse_js_importssilently skipped them — leavingreverse_graphincomplete so BFS had no edges to traverse.Investigation followed the three steps from issue #189:
all_known_filesfrom_build_import_graph— for a workspace wherelogin.tsuses a multi-line import,auth/google-auth-cache.tswas NOT inall_known_filesat all (it had no imports itself, and the parser missed the inbound import inlogin.ts). This is the literal "keys don't match input path" symptom.cf_rel— normalized correctly toauth/google-auth-cache.ts; matched a real file atworkspace/cf_rel, so it was added toresolved_changed. BFS started (visited_total: 1) but had no outbound edges to walk._parse_js_importsregex — confirmed three blind spots (details below).Three Parser Bugs Fixed
1. Multi-line imports —
import {\n foo,\n} from './bar'The ES import regex used
.*?which does not cross newlines. Any import statement split across lines (Prettier default, ESLintmulti-linerule, common in real TS codebases) was silently skipped.Fix: Replace
.*?with[\s\S]*?to match across newlines.2. Side-effect imports —
import './polyfills'(nofromclause)The ES import regex required
from, so side-effect imports were silently skipped even though they create a real dependency edge (the importing module depends on the side-effect module).Fix: Add a dedicated
import\s+["']...["']regex. It is disjoint from thefromform (requires a quote immediately afterimport+whitespace), so order does not matter.3. Re-exports —
export { x } from './bar',export * from './bar',export type { Foo } from './bar'The parser only looked for
import, neverexport ... from. Barrel files (e.g.auth/index.tsre-exporting fromauth/core.ts) were invisible to the reverse graph, so changingcore.tswould not flagindex.tsor any of its consumers as affected.Fix: Add
export\s+[\s\S]*?from\s+["']...["']regex (with multi-line support).Why this caused "BFS never starts"
When the parser misses an import,
reverse_graphloses an edge. If the changed file's only inbound edge was the missed import:all_known_files(it has no imports itself, and the missed import means no inbound edge).os.path.isfile(workspace/cf_rel)fallback, so it lands inresolved_changed.reverse_graph.get(changed_file, set())is empty, so there are no edges to walk.affected_countstays at 0.Net effect for the user:
codelens affected <ws> auth/google-auth-cache.tsreturnsaffected_count: 0andunresolved: [], even thoughauth/login.tsclearly imports fromgoogle-auth-cache.ts. This matches the issue title "BFS never starts".Tests
5 new tests in
TestIssue189ImportParserPatterns:test_multiline_import_resolves_and_bfs_finds_dependentsimport {\n foo\n} from './bar'test_side_effect_import_resolves_and_bfs_finds_dependentsimport './polyfills'(nofrom)test_reexport_creates_dependency_edgeexport { x } from './core'test_multiline_include_source_returns_all_dependents--include-sourcetest_existing_ts_workspace_fixture_still_finds_affectedAll 4 bug-exposing tests fail on the pre-fix code (verified via
git stash) and pass after the fix. The 5th (DoD sanity check) passes both before and after — it is the explicit Definition-of-Done assertion from issue #189.Regression
tests/test_affected_command.py: 63 passed (58 existing + 5 new)tests/test_command_registry.py+test_command_count.py+test_doctor.py: 44 passedtests/test_js_backend_parser.py+test_js_frontend_parser.py+test_formatters.py+test_formatters_base.py+test_orient.py: 151 passed, 5 skippedtest_cli.py::TestArgparseFormatConflictRegression::test_scan_with_format_long_does_not_crashtimes out oncodelens scan .— verified pre-existing onmain(60s timeout, unrelated to this PR).Definition of Done (issue #189)
codelens affected <ts-workspace> auth/google-auth-cache.tsreturnsaffected_count > 0for a workspace where other files import from that fileunresolved[]is empty when input file exists and is imported by other filests_workspacefixture intests/test_affected_command.py(from PR fix(affected): resolve TypeScript workspaces + path normalization (closes #176) #184) and assertaffected_count >= 1Sebelum → Sesudah
Sebelum (CodeLens
mainHEAD =ab0d789, with multi-line import in fixture):_build_import_graphkeys:['auth/login.ts', 'tests/login.test.ts']—auth/google-auth-cache.tsis MISSINGaffected_count: 0,visited_total: 1Sesudah (this PR):
_build_import_graphkeys:['auth/google-auth-cache.ts', 'auth/login.ts', 'tests/login.test.ts']affected_count: 1,visited_total: 3,affected: ['tests/login.test.ts']Findings
None outside scope.