Skip to content

Commit ea6eac3

Browse files
authored
Merge pull request #86 from codellm-devkit/feat/issue-84
feat: analyze JavaScript — discovery, dynamic method idioms, and a loud jelly failure
2 parents 834ed16 + 611cebd commit ea6eac3

38 files changed

Lines changed: 1034 additions & 83 deletions

.github/workflows/ci.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
branches: [release/0.x]
6+
push:
7+
branches: [release/0.x]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Check out code
14+
uses: actions/checkout@v4
15+
16+
- name: Set up Bun
17+
uses: oven-sh/setup-bun@v2
18+
19+
- name: Install dependencies
20+
run: bun install --frozen-lockfile
21+
22+
- name: Typecheck
23+
run: bun run typecheck
24+
25+
- name: Unit + conformance tests
26+
run: bun test
27+
28+
# Container suite is opt-in; ubuntu-latest ships Docker, so testcontainers works out of the box.
29+
- name: Neo4j bolt container tests
30+
run: RUN_CONTAINER_TESTS=1 bun test test/neo4j-bolt.test.ts

CHANGELOG.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [Unreleased]
9+
10+
## [0.6.0] - 2026-08-05
11+
12+
### Added
13+
- **JavaScript is analyzed** (#84). Discovery was restricted to `.ts/.tsx/.mts/.cts`,
14+
so a JavaScript-only project produced an empty symbol table and exited 0 with no
15+
warning — on OWASP NodeGoat, 0 modules and an 84-byte `analysis.json`. `.js`,
16+
`.jsx`, `.mjs` and `.cjs` are now discovered, and `.test.js` / `.spec.js` are
17+
skipped like their TypeScript counterparts. Nothing downstream needed changing:
18+
the compiler already ran with `allowJs`, and Jelly already accepted `.js` — both
19+
were simply never handed a file.
20+
- **Methods declared through dynamic idioms are materialized** (#85):
21+
`this.<name> = fn` inside a constructor function, and object-literal members
22+
(`{ foo(){} }`, `{ foo: function(){} }`). Previously the first landed in
23+
`local_variables` and the second was dropped entirely, so no call could resolve
24+
to either — call-graph edges are gated to signatures present in the symbol table.
25+
This is language-neutral: both were missed in TypeScript too.
26+
27+
### Changed
28+
- **BREAKING: Neo4j labels and relationship types are namespaced per source language** (#88).
29+
Node labels gain a language twin — a `.js` module is `:Module:JSModule`, a `.ts` module is
30+
`:Module:TSModule` — and every relationship type is prefixed: `JS_CALLS`, `TS_DECLARES`,
31+
`JS_HAS_MODULE`, and so on. This matches `codeanalyzer-python`, which already namespaces every
32+
edge (`PY_CALLS`, `PY_DECLARES`, …), so a database holding output from more than one analyzer no
33+
longer mingles them.
34+
35+
An edge takes its **source** module's language, falling back to its target's — so the
36+
application-to-module edge on a JavaScript project is `JS_HAS_MODULE`. Nodes with no language of
37+
their own (the application root, packages, external library symbols) keep the analyzer's own `TS`
38+
namespace, since a sibling analyzer emits its own.
39+
40+
**Migration:** every stored query against a graph produced by 0.5.0 or earlier must be updated —
41+
`MATCH ()-[:CALLS]->()` becomes `MATCH ()-[:TS_CALLS|JS_CALLS]->()`. The Neo4j schema version
42+
moves 1.1.0 → 2.0.0, which forces a full re-upsert on the next incremental push.
43+
44+
- **A failed Jelly leg is now reported at error level on JavaScript-majority
45+
projects.** The union provider degrades to tsc-only when Jelly throws, and
46+
reported that at `info`, which is not printed at default verbosity. On JavaScript
47+
that is a ~81% edge loss with no signal (Jelly supplies 156 of 161 union edges on
48+
NodeGoat). TypeScript projects keep the quieter `info` line. The default provider
49+
is unchanged: `union` is a strict superset of `jelly` on JavaScript, measured both
50+
with and without dependencies installed.
51+
- **Caches from 0.5.0 and earlier are invalidated.** Extraction now produces more
52+
callables from unchanged sources, so `ANALYZER_VERSION` moves with the release and
53+
every cached `analysis_cache.json` is rebuilt on first run.
54+
55+
### Measured on OWASP NodeGoat (dependencies installed, `-a 2`)
56+
57+
| | 0.5.0 | 0.6.0 |
58+
| --- | --- | --- |
59+
| modules | 0 | 27 |
60+
| callables | 0 | 59 |
61+
| call-graph edges | 0 | 184 |
62+
| resolved call sites | 0 | 51 |
63+
64+
59 callables matches the parser-derived count of nameable functions in the source
65+
exactly. The discovered module set equals the set of `.js` files outside
66+
`node_modules`, `vendor` and test trees.
67+
68+
### Known gaps
69+
- CommonJS `require` / `module.exports` are not modelled at module level, so
70+
`imports` and `exports` stay empty on CommonJS input. Relative `require()` **call
71+
targets** do resolve.
72+
- Method calls on an untyped receiver (e.g. `db.collection(...)` where `db` is an
73+
untyped parameter) produce no edge into the library — tracked in #87. The call is
74+
still attributable: it is recorded on the enclosing callable with its receiver
75+
expression, and that callable is reachable from its route.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codeanalyzer-typescript",
3-
"version": "0.5.0",
3+
"version": "0.6.0",
44
"description": "CLDK TypeScript analyzer — emits the canonical CLDK analysis.json (symbol table + resolver-based call graph) via ts-morph.",
55
"type": "module",
66
"module": "src/index.ts",

0 commit comments

Comments
 (0)