Skip to content

v1.7.0

Choose a tag to compare

@dannote dannote released this 23 Apr 13:29
· 343 commits to master since this release

JavaScript frontend & cross-language analysis

Reach now parses JavaScript and TypeScript via QuickBEAM bytecode disassembly and traces data flow across the Elixir ↔ JavaScript boundary.

New

  • JavaScript/TypeScript frontend — parses JS/TS source files into Reach IR. Handles functions, closures, async/await, method calls, property read/write, object literals, control flow reconstruction from bytecode basic blocks. TypeScript stripped via OXC, ES module syntax handled via OXC AST patching. Requires {:quickbeam, "~> 0.10", optional: true}.

  • QuickBEAM plugin — cross-language analysis for Elixir + JS projects. Detects QuickBEAM.eval(rt, "js source") with string literals, parses embedded JS, injects function nodes into the graph. Creates :js_eval, {:js_call, name}, and {:beam_call, name} edges. Classifies effects for QuickBEAM, OXC, and Vize APIs. Auto-detected when :quickbeam is loaded.

  • Plugin API: analyze_embedded/2 — new optional callback returning {nodes, edges} for plugins to inject IR from embedded code and connect it to the host graph.

  • Uniform CFG visualization — JS functions render with the same entry/body/exit structure as Elixir in the HTML report. JS syntax highlighting via makeup_js. Orange edges for cross-language calls in the call graph.

Improved

  • Dead code — near-zero false positives across Phoenix, Ecto, Oban, QuickBEAM, and Elixir stdlib (395 files). Fixed: compiler directives, type annotations, closure variable capture, with clause values, receive timeouts, struct patterns, unquote/unquote_splicing, {:ok, _} return types, inferred-type purity for NIF modules.

  • File I/O classificationFile.read/stat/exists?:read, File.write/cp/rm/mkdir:write.

  • Smell detectionEnum.map(rows, &List.first/1) no longer false-flagged as pipeline anti-pattern.

  • OTP analysis — catch-all handlers respected in unmatched-message detection.

Fixed

  • with body translation — pre-existing bug where entire with do...end body was silently lost.
  • PDG containment edges for :case, :fn, :receive, :try, :guard.
  • :case and :fn classified as :pure (control flow, not side effects).
  • Code and Module added to @impure_modules.

Full changelog: https://github.com/dannote/reach/blob/master/CHANGELOG.md