Skip to content

JS: Parse alternative import syntax - #22417

Open
MathiasVP wants to merge 2 commits into
github:mainfrom
MathiasVP:js-parse-weird-module-import
Open

JS: Parse alternative import syntax#22417
MathiasVP wants to merge 2 commits into
github:mainfrom
MathiasVP:js-parse-weird-module-import

Conversation

@MathiasVP

@MathiasVP MathiasVP commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

This PR implements support for ... "alternative module import syntax" in JS. The motivation can be seen in this old version of handlebars:

module Utils from "./utils";

This is not valid JS, but we obviously still want to be able to create a CodeQL database for such projects. So this PR changes the JS parser so that it outputs TRAP equivalent to:

import * as Utils from "./utils";

Copilot AI balanced review requested due to automatic review settings August 24, 2026 19:19
@MathiasVP
MathiasVP requested review from a team as code owners August 24, 2026 19:19
@github-actions github-actions Bot added the JS label Aug 24, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds parsing support for legacy module X from "..." syntax as namespace imports.

Changes:

  • Detects and parses legacy module imports.
  • Adds extraction input and expected TRAP output.
Show a summary per file
File Description
Parser.java Implements legacy import parsing.
import8.js Adds parser test input.
import8.js.trap Adds expected extraction output.

Review details

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Suppressed comments (2)

javascript/extractor/src/com/semmle/jcorn/Parser.java:2801

  • This recognizes the declaration only after source-type detection has already classified the file. JSExtractor.establishSourceType recognizes only import, export, and goog.module (JSExtractor.java:36-39,97-106), so a file containing only this syntax remains a script. The added TRAP fixture confirms that outcome: it has no is_module/is_es2015_module tuple and binds Utils in the global scope, unlike the equivalent namespace import in import5.js.trap. This breaks the promised equivalence and prevents the file from being represented as an ES2015Module; extend source-type detection to recognize this legacy declaration too.
    } else if (topLevel && this.isLegacyModuleImport()) {
      if (!this.options.allowImportExportEverywhere() && !this.inModule)
        this.raise(this.start, "Legacy module imports may appear only with 'sourceType: module'");
      return this.parseLegacyModuleImport(startLoc);

javascript/extractor/src/com/semmle/jcorn/Parser.java:3616

  • The namespace specifier is finished only after parsing from, the source, and the semicolon, so its source range incorrectly spans Utils from "./utils";. The generated fixture shows this as location 1:8–1:28, whereas an ImportNamespaceSpecifier should cover only the syntactic specifier (the equivalent standard import covers * as foo). Finish this node immediately after parsing local, before consuming from.
    List<ImportSpecifier> specifiers = new ArrayList<ImportSpecifier>();
    specifiers.add(this.finishNode(new ImportNamespaceSpecifier(specifierLoc, local)));
  • Files reviewed: 3/3 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment on lines +121 to +122
private static final Pattern LEGACY_MODULE_IMPORT_TAIL =
Pattern.compile("\\s+[A-Za-z_$][A-Za-z0-9_$]*\\s+from\\s*['\"]");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants