Skip to content

js-imports rule only matches double-quoted require()/import — single-quoted CommonJS invisible to --importers #147

Description

@nicknsheth-beep

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions