Skip to content

fix(affected): parse multi-line, side-effect, and re-export imports (closes #189)#192

Merged
Wolfvin merged 1 commit into
mainfrom
fix/issue-189-affected-bfs-keys
Jul 4, 2026
Merged

fix(affected): parse multi-line, side-effect, and re-export imports (closes #189)#192
Wolfvin merged 1 commit into
mainfrom
fix/issue-189-affected-bfs-keys

Conversation

@Wolfvin

@Wolfvin Wolfvin commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Closes #189

Root Cause (verified)

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.

Investigation followed the three steps from issue #189:

  1. all_known_files from _build_import_graph — for a workspace where login.ts uses a multi-line import, auth/google-auth-cache.ts was NOT in all_known_files at all (it had no imports itself, and the parser missed the inbound import in login.ts). This is the literal "keys don't match input path" symptom.
  2. cf_rel — normalized correctly to auth/google-auth-cache.ts; matched a real file at workspace/cf_rel, so it was added to resolved_changed. BFS started (visited_total: 1) but had no outbound edges to walk.
  3. _parse_js_imports regex — 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, ESLint multi-line rule, common in real TS codebases) was silently skipped.

Fix: Replace .*? with [\s\S]*? to match across newlines.

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 (the importing module depends on the side-effect module).

Fix: Add a dedicated import\s+["']...["'] regex. It is disjoint from the from form (requires a quote immediately after import+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, never export ... from. Barrel files (e.g. auth/index.ts re-exporting from auth/core.ts) were invisible to the reverse graph, so changing core.ts would not flag index.ts or 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_graph loses an edge. If the changed file's only inbound edge was the missed import:

  • The changed file is NOT in all_known_files (it has no imports itself, and the missed import means no inbound edge).
  • Wait — actually, the changed file DOES resolve via the os.path.isfile(workspace/cf_rel) fallback, so it lands in resolved_changed.
  • BFS starts (visited_total: 1) but reverse_graph.get(changed_file, set()) is empty, so there are no edges to walk.
  • affected_count stays at 0.

Net effect for the user: codelens affected <ws> auth/google-auth-cache.ts returns affected_count: 0 and unresolved: [], even though auth/login.ts clearly imports from google-auth-cache.ts. This matches the issue title "BFS never starts".

Tests

5 new tests in TestIssue189ImportParserPatterns:

Test Bug exposed Pre-fix Post-fix
test_multiline_import_resolves_and_bfs_finds_dependents Multi-line import {\n foo\n} from './bar' FAIL PASS
test_side_effect_import_resolves_and_bfs_finds_dependents import './polyfills' (no from) FAIL PASS
test_reexport_creates_dependency_edge export { x } from './core' FAIL PASS
test_multiline_include_source_returns_all_dependents Multi-line + --include-source FAIL PASS
test_existing_ts_workspace_fixture_still_finds_affected DoD sanity check (existing fixture) PASS PASS

All 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 passed
  • tests/test_js_backend_parser.py + test_js_frontend_parser.py + test_formatters.py + test_formatters_base.py + test_orient.py: 151 passed, 5 skipped
  • No new failures. test_cli.py::TestArgparseFormatConflictRegression::test_scan_with_format_long_does_not_crash times out on codelens scan . — verified pre-existing on main (60s timeout, unrelated to this PR).

Definition of Done (issue #189)

Sebelum → Sesudah

Sebelum (CodeLens main HEAD = ab0d789, with multi-line import in fixture):

  • _build_import_graph keys: ['auth/login.ts', 'tests/login.test.ts']auth/google-auth-cache.ts is MISSING
  • affected_count: 0, visited_total: 1

Sesudah (this PR):

  • _build_import_graph keys: ['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.

…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)
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@sonarqubecloud

sonarqubecloud Bot commented Jul 3, 2026

Copy link
Copy Markdown

@Wolfvin Wolfvin merged commit f5971cb into main Jul 4, 2026
2 of 8 checks passed
@Wolfvin Wolfvin deleted the fix/issue-189-affected-bfs-keys branch July 4, 2026 01:18
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.

fix(affected): BFS never starts — _build_import_graph keys don't match input path

1 participant