Skip to content

fix(affected): resolve TypeScript workspaces + path normalization (closes #176)#184

Merged
Wolfvin merged 1 commit into
mainfrom
fix/issue-176-affected-typescript
Jul 3, 2026
Merged

fix(affected): resolve TypeScript workspaces + path normalization (closes #176)#184
Wolfvin merged 1 commit into
mainfrom
fix/issue-176-affected-typescript

Conversation

@Wolfvin

@Wolfvin Wolfvin commented Jul 3, 2026

Copy link
Copy Markdown
Owner

What

Fixes codelens affected returning affected_count: 0 and putting the workspace path in unresolved[] when run against a TypeScript project. Three root causes identified and fixed.

Why (issue #176)

codelens affected /path/to/ts-workspace auth/google-auth-cache.ts was a no-op for TypeScript projects. The command returned:

{
  "unresolved": ["/path/to/ts-workspace", "auth/google-auth-cache.ts"],
  "affected_count": 0
}

Three root causes:

Root cause 1: argparse greedy-absorb

affected.py defines files with nargs="*" (greedy) and workspace with nargs="?". argparse assigns ALL positional args to files, leaving workspace=None. The CLI dispatcher then auto-detects workspace to cwd — wrong when user explicitly passed a workspace path.

Fix: In execute(), detect if the first item in files is an existing directory that differs from the resolved workspace. If so, treat it as the intended workspace and remove it from the changed-files list. Non-breaking: if the first arg is a file (not a dir), old behavior is preserved.

Root cause 2: lstrip("./") bug

cf.replace('\\','/').lstrip('./') is a char-set strip, not a prefix strip. lstrip treats the argument as a set of characters to remove, so "../foo.ts" becomes "foo.ts" (corrupted!).

Fix: Replace with a while loop that strips "./" prefix only:

while cf_norm.startswith('./'):
    cf_norm = cf_norm[2:]

Root cause 3: path separator mismatch

os.path.relpath uses backslashes on Windows, but user input (e.g. from git diff --name-only) uses forward slashes. Direct comparison fails.

Fix: Normalize all known files to forward slashes before matching, and build a norm_to_orig mapping to resolve back to the original form.

Files touched

  • scripts/commands/affected.py — workspace detection heuristic (18 lines added)
  • scripts/dependents_engine.py — path normalization + lstrip fix (33 lines changed)
  • tests/test_affected_command.py — 8 new tests in TestIssue176TypeScriptAffected (163 lines added)

Verification

New tests — 8 passed

tests/test_affected_command.py::TestIssue176TypeScriptAffected::test_workspace_as_first_arg_resolves PASSED
tests/test_affected_command.py::TestIssue176TypeScriptAffected::test_ts_affected_count_nonzero PASSED
tests/test_affected_command.py::TestIssue176TypeScriptAffected::test_ts_include_source_returns_all_dependents PASSED
tests/test_affected_command.py::TestIssue176TypeScriptAffected::test_ts_absolute_changed_path_resolves PASSED
tests/test_affected_command.py::TestIssue176TypeScriptAffected::test_ts_basename_only_resolves PASSED
tests/test_affected_command.py::TestIssue176TypeScriptAffected::test_ts_dot_slash_prefix_resolves PASSED
tests/test_affected_command.py::TestIssue176TypeScriptAffected::test_ts_parent_dir_path_not_corrupted PASSED
tests/test_affected_command.py::TestIssue176TypeScriptAffected::test_ts_no_workspace_arg_uses_cwd PASSED

Regression — 146 passed, 0 failed

tests/test_cli.py + tests/test_doctor.py + tests/test_affected_command.py +
tests/test_command_registry.py + tests/test_command_count.py
146 passed in 19.62s

All 58 test_affected_command.py pass (50 existing + 8 new).

Manual test (Definition of Done)

TS fixture: auth/google-auth-cache.tsauth/login.tstests/login.test.ts

$ codelens affected /tmp/ts-fixture auth/google-auth-cache.ts
{
  "status": "ok",
  "workspace": "/tmp/ts-fixture",
  "changed_files": ["auth/google-auth-cache.ts"],
  "unresolved": [],
  "affected": ["tests/login.test.ts"],
  "affected_by_source": {"auth/google-auth-cache.ts": ["tests/login.test.ts"]},
  "stats": {"affected_count": 1, "affected_test_count": 1, ...}
}

All DoD scenarios verified:

  • --include-source returns 3 files (google-auth-cache + login + test)
  • Absolute path for changed file resolves
  • Basename-only resolves via basename match
  • ./ prefix strips correctly
  • ../ path not corrupted (lstrip bug regression)
  • Backward compat: no workspace arg uses cwd

Definition of Done (issue #176)

  • codelens affected <workspace> auth/google-auth-cache.ts returns correct dependents
  • Works on Unix (/) and Windows (\) path separators (normalization added)
  • unresolved[] is empty when the input file exists in the scan graph
  • Test added: TS fixture with import chain, asserts affected returns known dependents

Issue link

Closes #176#176

…oses #176)

Bug: codelens affected /path/to/ws auth/file.ts returned affected_count: 0
and put the workspace path in unresolved[]. Three root causes:

1. Argparse greedy-absorb: files (nargs="*") absorbed ALL positional
   args, leaving workspace=None. CLI dispatcher auto-detected workspace
   to cwd, which was wrong. Fix: in execute(), detect if first item in
   files is an existing directory that differs from the resolved
   workspace — treat it as the intended workspace.

2. lstrip('./') bug: cf.replace('\\','/').lstrip('./') is a char-set
   strip, not a prefix strip. It corrupted '../foo.ts' into 'foo.ts'.
   Fix: replace with a while loop that strips './' prefix only.

3. Path separator mismatch: os.path.relpath uses backslashes on Windows,
   but user input (e.g. from git diff --name-only) uses forward slashes.
   Fix: normalize all known files to forward slashes before matching,
   and build a norm_to_orig mapping to resolve back to original form.

Tests: 8 new tests in TestIssue176TypeScriptAffected covering:
- workspace-as-first-arg resolution
- affected_count > 0 for TS file with dependents
- --include-source returns all dependents
- absolute changed path resolves
- basename-only resolves
- ./ prefix strips correctly (lstrip bug regression)
- ../ path not corrupted (lstrip bug regression)
- backward compat: no workspace arg uses cwd

All 58 test_affected_command.py pass (50 existing + 8 new).
Regression: 146 passed (test_cli + test_doctor + test_affected +
test_command_registry + test_command_count).

Definition of Done (issue #176):
- [x] codelens affected <workspace> auth/file.ts returns correct dependents
- [x] Works on Unix (/) and Windows (backslash) path separators
- [x] unresolved[] is empty when input file exists in scan graph
- [x] Test added: TS fixture with import chain, asserts affected returns
      known dependents
@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 aa425f5 into main Jul 3, 2026
2 of 8 checks passed
@Wolfvin Wolfvin deleted the fix/issue-176-affected-typescript branch July 3, 2026 09:29
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): unresolved result for TypeScript workspaces — affected_count always 0

1 participant