Skip to main content

Module js

Module js 

Source
Expand description

The JS/TS static scan — a real parse on oxc.

oxc is pure Rust, so keel init still needs no Node toolchain (the design constraint the old line-oriented scan existed to satisfy — this replaces that documented simplification with an actual AST walk, dx-spec §2). Per file, [ast] extracts:

  • HTTP in use: a fetch(…) call, or an import/require/dynamic-import of a known outbound client (undici, node:http/https, axios, got, node-fetch, superagent, DB clients like pg/redis) — including multi-line and aliased forms the old regex missed.
  • provider SDKs: openai, @anthropic-ai/sdk (also bare anthropic), AI-SDK provider packages → llm:* targets. TS import type is excluded: type-only imports are erased at runtime and are not evidence.
  • URL literals: hosts from string literals and template-literal quasis (`https://api.x.com/${id}` resolves; `${scheme}://x` no longer false-positives).
  • effect call sites with enclosing-function attribution (super::CallSite) for keel flows suggest, and a relative-import module graph (JsScan::imports).

The tradeoff (accepted here): a URL built by concatenation, or an exotic import form, is missed — exactly the ~20% the import-time and observed-run evidence sources exist to catch (dx-spec §2). Line numbers are exact.

§Function attribution (for keel flows suggest)

[ast::ScanVisitor] tracks a real enclosing-scope stack, so attribution is exact scope containment, not a line heuristic. A super::FunctionFacts entry opens for a function bound directly at module top level: a function declaration (function f(…) {, export async function f(…) {), a named function expression, or an arrow assigned directly to a top-level const/let/var (const f = () => {…}, const f = function () {…}). Everything lexically nested inside it — inner arrows, callbacks, helper closures — attributes to that top-level entry, exactly like the Python pass’s real ast containment (scan::python).

Class methods and object-literal methods do not open their own entry — even though the scope walk names them (Class.method shows up in super::CallSite::function for call-site evidence), a class body is not a flow entrypoint any more than a Python class body is. A fetch inside class Api { async load() {…} } is evidenced in the file-level scan (host literals, call sites) but not credited to a function. The same holds for anonymous top-level values (export default function () {…}): still evidenced, never a flow candidate. This is strictly more precise than the old line-heuristic scan it replaces, which additionally missed Allman-brace functions and desynced on template-literal interpolation.

A file that fails to parse is warned about on stderr and skipped — never a crash, and never silent narrowing (mirrors the Python pass’s parse-or-skip). files_scanned counts parsed files only.

Structs§

JsScan
The JS pass result.

Functions§

scan
Scan project for JS/TS effect seams.