# Phase 4 Summary: TypeScript/JavaScript Adapters and Security

## What Was Built

Phase 4 extended the static analysis pipeline from Python-only to a three-language system (Python, TypeScript, JavaScript) and added a security layer. A shared internal module handles the common tree-sitter parsing logic for JS/TS: traversing parse trees, extracting import statements (both ES module `import` and CommonJS `require()`), extracting function/class/method definitions, detecting entry points (Express app creation, `app.listen()`, `module.exports`), and calculating cyclomatic complexity. The TypeScript and JavaScript adapters are thin wrappers that select the right grammar, parse the content, and delegate to this shared module. The security layer adds two independent capabilities: secret detection (scanning source files for hardcoded API keys, passwords, etc. via `detect-secrets`) and dependency CVE scanning (running `pip-audit` for Python manifests and `npm audit` for JavaScript, both via subprocess). Security results are assembled into a `SecurityResult` dataclass and attached to `AnalysisResult` as Stage 9 of the orchestrator pipeline.

## Key Decisions

1. **Shared `_treesitter_utils.py` internal module** — TypeScript and JavaScript adapters share ~80% of their parsing logic. Rather than duplicating it or adding a base class, a prefixed internal module (`_`) provides the common functions. Two real consumers justify the extraction; it's not premature. The adapters remain thin and their difference (CommonJS support in JS) is visible locally.

2. **`noqa: TC003` on Path import in vulnerabilities.py** — ruff's TC003 rule (move import to TYPE_CHECKING block) is a false positive here; `Path` is used at runtime as a function argument type check, not just for annotations.

3. **Severity inference for pip-audit** — pip-audit v2+ doesn't include severity in its JSON output for Python packages. Rather than treating everything as "unknown", we keyword-match the description (RCE → critical, XSS/SQLi → high) and default to "moderate" for anything with a known CVE. This produces actionable output at the cost of some imprecision.

4. **Separate TS and TSX language objects** — The `tree-sitter-typescript` package exposes two separate grammars: `language_typescript()` and `language_tsx()`. TSX requires the TSX grammar to correctly parse JSX syntax inside `.tsx` files; using the plain TS grammar would fail to parse JSX. The adapter selects by extension at parse time.

5. **Extension order differs between adapters** — TypeScript tries `.ts, .tsx, .js, .jsx`; JavaScript tries `.js, .jsx, .ts, .tsx`. This prioritizes the "native" extension for each adapter and correctly handles mixed-language projects where a TS file imports a JS utility.

## Complex Logic Explained

### 1. Tree-sitter cursor traversal (`_treesitter_utils.traverse`)

Tree-sitter provides a `TreeCursor` for efficient iterative traversal. The cursor has three movement methods: `goto_first_child()`, `goto_next_sibling()`, `goto_parent()`, each returning True/False on success. The `visited` flag tracks whether the current node has been yielded. When `visited=True` (node already yielded), the algorithm tries to descend or move sideways before backtracking upward. This avoids stack overflow on deeply nested files that recursive traversal would cause. **Note: See code review findings — the visited flag logic may have a subtle re-traversal bug; verify with manual tests.**

### 2. Import resolution with `src/` layout support (`TypeScriptAdapter.resolve_import`)

JavaScript/TypeScript project layouts vary widely. A file at `src/views/Home.tsx` importing `../components/Button` should resolve to `src/components/Button.tsx`. The naive approach: join the importing file's directory with the import target. But many repos also use a `src/` layout where files discovered via git have paths like `src/components/Button.tsx`. The adapter tries the direct candidate first, then falls back to a suffix-match: searching `repo_files` for any path that ends with `/candidate`. This handles `src/` layout, `app/` layout, and monorepo structures without needing to understand the project configuration.

### 3. npm audit `via` field polymorphism (`_parse_npm_audit_output`)

npm audit's JSON schema has a `via` field that is a list of either objects (advisory details) or strings (references to other package names in the `vulnerabilities` dict). A string entry means "this package is vulnerable because it depends on X which is vulnerable" — it's an indirect reference, not advisory data. The parser skips string entries and only processes dict entries where the full advisory data is available. Additionally, `fixAvailable` can be a boolean (`false`) or an object (`{name, version, isSemVerMajor}`) — the code checks `isinstance(fix_available, dict)` before extracting the version.

## Connection to Previous Phases

Phase 4 builds directly on Phase 3's infrastructure without modifying its core contracts:
- Implements the `LanguageAdapter` protocol from `adapters/protocol.py` (Phase 3)
- Returns the same `ParsedFile`, `ParsedImport`, `FunctionDef`, `EntryPoint` dataclasses defined in `analysis/models.py` (Phase 3)
- Registers adapters in `create_default_registry()` — the orchestrator's Stage 3 parsing loop picks them up automatically, no orchestrator changes needed for new adapters
- Adds Stage 9 to `orchestrator.py` and the `SecurityResult`/`SecretFinding`/`VulnerabilityFinding` dataclasses to `models.py`

For Phase 6 (LLM integration): the security results attached to `AnalysisResult.security` feed directly into briefing generation. The `manifests_scanned`, `secrets`, and `vulnerabilities` fields are designed to produce a "security posture summary" without requiring Phase 6 to know anything about how the scanning was done.
