Summary
scanner/sg-rules/javascript.yml's js-imports rule only matches double-quoted import/require string literals. Single-quoted CommonJS require() calls — extremely common in real-world JS, and the default style under most Prettier/ESLint configs (singleQuote: true) — are silently invisible to --importers / the MCP get_importers tool, which then reports a confident "No files import X" for files that are demonstrably imported elsewhere.
This is a correctness issue, not just a wording one: it produces a confident false negative on exactly the kind of blast-radius check someone runs before editing a shared/security-sensitive file.
Root cause
scanner/sg-rules/javascript.yml:
id: js-imports
language: javascript
rule:
any:
- pattern: import $$$_ from "$PATH"
- pattern: import "$PATH"
- pattern: require("$PATH")
All three patterns are literal-text ast-grep patterns hardcoded to double-quoted strings. Verified directly with ast-grep (0.45.1) against this exact rule:
// single.js
const memberRoutes = require('./routes/members');
→ ast-grep scan --rule rule.yml single.js produces zero matches.
// double.js
const memberRoutes = require("./routes/members");
→ produces a match.
By contrast, scanner/sg-rules/typescript.yml / tsx.yml / jsx.yml all use a structural, quote-agnostic rule:
id: ts-imports
language: typescript
rule:
kind: import_statement
which correctly matches regardless of quote style. Only the plain .js rule uses literal-text patterns, and only for double quotes.
Impact
On a real Node/Express codebase (100% single-quoted require() throughout — the standard style), this means codemap --importers <any-required-file>.js reports zero importers for files that have many. Confirmed on two separate repos, e.g. services/layoutInputService.js — 14 real requirers via grep -rn "require(.*layoutInputService", codemap --importers reports "No files import services/layoutInputService.js."
Separately (already fixed as of current main, noting for context): codemap v4.4.0's renderImportersReportCLI printed the "Go resolves imports at package level" explanatory note unconditionally on every zero-importer result, regardless of file extension — confirmed by diffing blast_radius.go at the v4.4.0 tag vs current main, where it's now gated behind filepath.Ext(report.File) == ".go". That fix (presumably landed in v4.4.2, "Add Go parser fallback" (#123), the last commit to touch that file) stops the misleading wording, but doesn't touch this quote-style detection gap — upgrading alone won't fix the false negative described above.
Suggested fix
Match both quote styles (and ideally template-literal requires) in javascript.yml, e.g.:
rule:
any:
- pattern: import $$$_ from "$PATH"
- pattern: import $$$_ from '$PATH'
- pattern: import "$PATH"
- pattern: import '$PATH'
- pattern: require("$PATH")
- pattern: require('$PATH')
or better, switch to a structural kind:-based rule the way typescript.yml/tsx.yml/jsx.yml already do, so quote style stops being a concern entirely.
Environment
- codemap 4.4.0 (also reproduced against
scanner/sg-rules/javascript.yml and blast_radius.go as they currently stand on main)
- ast-grep 0.45.1
- macOS, Homebrew install (
jordancoin/tap/codemap)
Summary
scanner/sg-rules/javascript.yml'sjs-importsrule only matches double-quotedimport/requirestring literals. Single-quoted CommonJSrequire()calls — extremely common in real-world JS, and the default style under most Prettier/ESLint configs (singleQuote: true) — are silently invisible to--importers/ the MCPget_importerstool, which then reports a confident "No files import X" for files that are demonstrably imported elsewhere.This is a correctness issue, not just a wording one: it produces a confident false negative on exactly the kind of blast-radius check someone runs before editing a shared/security-sensitive file.
Root cause
scanner/sg-rules/javascript.yml:All three patterns are literal-text ast-grep patterns hardcoded to double-quoted strings. Verified directly with
ast-grep(0.45.1) against this exact rule:→
ast-grep scan --rule rule.yml single.jsproduces zero matches.→ produces a match.
By contrast,
scanner/sg-rules/typescript.yml/tsx.yml/jsx.ymlall use a structural, quote-agnostic rule:which correctly matches regardless of quote style. Only the plain
.jsrule uses literal-text patterns, and only for double quotes.Impact
On a real Node/Express codebase (100% single-quoted
require()throughout — the standard style), this meanscodemap --importers <any-required-file>.jsreports zero importers for files that have many. Confirmed on two separate repos, e.g.services/layoutInputService.js— 14 real requirers viagrep -rn "require(.*layoutInputService",codemap --importersreports "No files importservices/layoutInputService.js."Separately (already fixed as of current
main, noting for context): codemap v4.4.0'srenderImportersReportCLIprinted the "Go resolves imports at package level" explanatory note unconditionally on every zero-importer result, regardless of file extension — confirmed by diffingblast_radius.goat thev4.4.0tag vs currentmain, where it's now gated behindfilepath.Ext(report.File) == ".go". That fix (presumably landed in v4.4.2, "Add Go parser fallback" (#123), the last commit to touch that file) stops the misleading wording, but doesn't touch this quote-style detection gap — upgrading alone won't fix the false negative described above.Suggested fix
Match both quote styles (and ideally template-literal requires) in
javascript.yml, e.g.:or better, switch to a structural
kind:-based rule the waytypescript.yml/tsx.yml/jsx.ymlalready do, so quote style stops being a concern entirely.Environment
scanner/sg-rules/javascript.ymlandblast_radius.goas they currently stand onmain)jordancoin/tap/codemap)