Skip to main content
JavaScript and TypeScript share semantic mappings. The native build links separate grammars for JavaScript/JSX, TypeScript (.ts, .mts, .cts), and TSX (.tsx).

What it detects

  • Functions: declarations, expressions, and arrow functions all become Function
  • Methods: method_definition becomes Method
  • Classes: declarations and expressions become Class
  • Interfaces: interface_declaration becomes Interface
  • Types: type_alias_declaration becomes TypeDef
  • Enums: enum_declaration becomes Enum
  • Imports: import_statement becomes Import, with NamedImports / NamespaceImport children
  • Exports: export_statement and export_default become Export
  • Variables: variable_declaration (var) and lexical_declaration (let/const) become Variable, labeled with the declarator name
  • JSX: elements, attributes, and expressions are their own concepts
  • Control flow: if / for / while / switch / try / return / throw
  • Literals and expressions: strings, numbers, templates, regex, booleans, objects, arrays, calls, member access, operators, await / yield

Node type mapping

Node types without a mapping keep their raw tree-sitter type name. Most declaration labels come from Tree-sitter’s name field. For var, let, and const, the Rust label extractor reads the first variable_declarator child. The implementation lives in crates/differens-tiers/src/code/labels.rs.

Example: a TypeScript refactor

Rename computeTotal to calculateTotalAmount, add a discount parameter, and change the function body:
before.ts
after.ts
Running differens before.ts after.ts:
The human report groups the parameter and body edits under the function names. Use --format=json to read each action. When comparing directories or repository revisions, Differens can also detect moves across files. Modified declaration moves must keep the same name; moving and renaming a function together may produce an addition and a removal.

Example: move and edit a helper across files

Compare two directory snapshots. The destination module already exists, and the helper keeps its name while its body changes. This separates a modified move from the within-file rename example above:
old/src/utils.ts
new/src/utils.ts
old/src/pricing.ts
new/src/pricing.ts
Terminal output names the move; LLM output adds edited for a modified declaration move, and JSON exposes modified: true. The move summary pairs the supported declaration edits. Other edits, such as a new import, remain in the report. Renaming the helper during the move can prevent that pairing; use the original per-file JSON actions when investigating it.

Known limitations

  • Multi-declarator variables: const a = 1, b = 2 labels the Variable with the first declarator’s name only.
  • Interface members are distinct concepts: property_signature, call_signature, and method_signature are separate concepts, not a unified “member”.
  • JSX text is a flat node: jsx_text collapses contiguous text, so inline formatting changes inside JSX text can read as a single update.
  • No type-flow inference: the extractor does not distinguish a value used as a type from a type used as a value.
  • Unmapped node types pass through: anything outside the map keeps its raw tree-sitter type name.