Merge pull request #14484 from aibaars/ts53-js

JS: Support import attributes
This commit is contained in:
Arthur Baars
2023-10-16 10:47:49 +02:00
committed by GitHub
18 changed files with 2734 additions and 1418 deletions

View File

@@ -314,8 +314,9 @@ public class ESNextParser extends JSXParser {
this.parseExportSpecifiersMaybe(specifiers, exports);
}
Literal source = (Literal) this.parseExportFrom(specifiers, null, true);
Expression assertion = this.parseImportOrExportAssertionAndSemicolon();
return this.finishNode(new ExportNamedDeclaration(exportStart, null, specifiers, source, assertion));
Expression attributes = this.parseImportOrExportAttributesAndSemicolon();
return this.finishNode(
new ExportNamedDeclaration(exportStart, null, specifiers, source, attributes));
}
return super.parseExportRest(exportStart, exports);
@@ -331,8 +332,9 @@ public class ESNextParser extends JSXParser {
List<ExportSpecifier> specifiers = CollectionUtil.makeList(nsSpec);
this.parseExportSpecifiersMaybe(specifiers, exports);
Literal source = (Literal) this.parseExportFrom(specifiers, null, true);
Expression assertion = this.parseImportOrExportAssertionAndSemicolon();
return this.finishNode(new ExportNamedDeclaration(exportStart, null, specifiers, source, assertion));
Expression attributes = this.parseImportOrExportAttributesAndSemicolon();
return this.finishNode(
new ExportNamedDeclaration(exportStart, null, specifiers, source, attributes));
}
return super.parseExportAll(exportStart, starLoc, exports);

View File

@@ -3447,7 +3447,7 @@ public class Parser {
Statement declaration;
List<ExportSpecifier> specifiers;
Expression source = null;
Expression assertion = null;
Expression attributes = null;
if (this.shouldParseExportStatement()) {
declaration = this.parseStatement(true, false);
if (declaration == null) return null;
@@ -3463,10 +3463,10 @@ public class Parser {
declaration = null;
specifiers = this.parseExportSpecifiers(exports);
source = parseExportFrom(specifiers, source, false);
assertion = parseImportOrExportAssertionAndSemicolon();
attributes = parseImportOrExportAttributesAndSemicolon();
}
return this.finishNode(
new ExportNamedDeclaration(loc, declaration, specifiers, (Literal) source, assertion));
new ExportNamedDeclaration(loc, declaration, specifiers, (Literal) source, attributes));
}
/** Parses the 'from' clause of an export, not including the assertion or semicolon. */
@@ -3494,8 +3494,8 @@ public class Parser {
protected ExportDeclaration parseExportAll(
SourceLocation loc, Position starLoc, Set<String> exports) {
Expression source = parseExportFrom(null, null, true);
Expression assertion = parseImportOrExportAssertionAndSemicolon();
return this.finishNode(new ExportAllDeclaration(loc, (Literal) source, assertion));
Expression attributes = parseImportOrExportAttributesAndSemicolon();
return this.finishNode(new ExportAllDeclaration(loc, (Literal) source, attributes));
}
private void checkExport(Set<String> exports, String name, Position pos) {
@@ -3560,10 +3560,12 @@ public class Parser {
return parseImportRest(loc);
}
protected Expression parseImportOrExportAssertionAndSemicolon() {
protected Expression parseImportOrExportAttributesAndSemicolon() {
Expression result = null;
if (!this.eagerlyTrySemicolon()) {
this.expectContextual("assert");
if (!this.eatContextual("assert")) {
this.expect(TokenType._with);
}
result = this.parseObj(false, null);
this.semicolon();
}
@@ -3583,9 +3585,9 @@ public class Parser {
if (this.type != TokenType.string) this.unexpected();
source = (Literal) this.parseExprAtom(null);
}
Expression assertion = this.parseImportOrExportAssertionAndSemicolon();
Expression attributes = this.parseImportOrExportAttributesAndSemicolon();
if (specifiers == null) return null;
return this.finishNode(new ImportDeclaration(loc, specifiers, source, assertion));
return this.finishNode(new ImportDeclaration(loc, specifiers, source, attributes));
}
// Parses a comma-separated list of module imports.

View File

@@ -943,12 +943,12 @@ public class FlowParser extends ESNextParser {
// `export type { foo, bar };`
List<ExportSpecifier> specifiers = this.parseExportSpecifiers(exports);
this.parseExportFrom(specifiers, null, false);
this.parseImportOrExportAssertionAndSemicolon();
this.parseImportOrExportAttributesAndSemicolon();
return null;
} else if (this.eat(TokenType.star)) {
if (this.eatContextual("as")) this.parseIdent(true);
this.parseExportFrom(null, null, true);
this.parseImportOrExportAssertionAndSemicolon();
this.parseImportOrExportAttributesAndSemicolon();
return null;
} else {
// `export type Foo = Bar;`

View File

@@ -14,7 +14,10 @@ public class DynamicImport extends Expression {
return source;
}
/** Returns the second "argument" provided to the import, such as <code>{ assert: { type: "json" }}</code>. */
/**
* Returns the second "argument" provided to the import, such as <code>{ "with": { type: "json" }}
* </code>.
*/
public Expression getAttributes() {
return attributes;
}

View File

@@ -9,20 +9,20 @@ package com.semmle.js.ast;
*/
public class ExportAllDeclaration extends ExportDeclaration {
private final Literal source;
private final Expression assertion;
private final Expression attributes;
public ExportAllDeclaration(SourceLocation loc, Literal source, Expression assertion) {
public ExportAllDeclaration(SourceLocation loc, Literal source, Expression attributes) {
super("ExportAllDeclaration", loc);
this.source = source;
this.assertion = assertion;
this.attributes = attributes;
}
public Literal getSource() {
return source;
}
public Expression getAssertion() {
return assertion;
public Expression getAttributes() {
return attributes;
}
@Override

View File

@@ -15,22 +15,30 @@ public class ExportNamedDeclaration extends ExportDeclaration {
private final Statement declaration;
private final List<ExportSpecifier> specifiers;
private final Literal source;
private final Expression assertion;
private final Expression attributes;
private final boolean hasTypeKeyword;
public ExportNamedDeclaration(
SourceLocation loc, Statement declaration, List<ExportSpecifier> specifiers, Literal source, Expression assertion) {
this(loc, declaration, specifiers, source, assertion, false);
SourceLocation loc,
Statement declaration,
List<ExportSpecifier> specifiers,
Literal source,
Expression attributes) {
this(loc, declaration, specifiers, source, attributes, false);
}
public ExportNamedDeclaration(
SourceLocation loc, Statement declaration, List<ExportSpecifier> specifiers, Literal source,
Expression assertion, boolean hasTypeKeyword) {
SourceLocation loc,
Statement declaration,
List<ExportSpecifier> specifiers,
Literal source,
Expression attributes,
boolean hasTypeKeyword) {
super("ExportNamedDeclaration", loc);
this.declaration = declaration;
this.specifiers = specifiers;
this.source = source;
this.assertion = assertion;
this.attributes = attributes;
this.hasTypeKeyword = hasTypeKeyword;
}
@@ -59,9 +67,12 @@ public class ExportNamedDeclaration extends ExportDeclaration {
return v.visit(this, c);
}
/** Returns the expression after the <code>assert</code> keyword, if any, such as <code>{ type: "json" }</code>. */
public Expression getAssertion() {
return assertion;
/**
* Returns the expression after the <code>with</code> keyword, if any, such as <code>
* { type: "json" }</code>.
*/
public Expression getAttributes() {
return attributes;
}
/** Returns true if this is an <code>export type</code> declaration. */

View File

@@ -1,8 +1,7 @@
package com.semmle.js.ast;
import java.util.List;
import com.semmle.ts.ast.INodeWithSymbol;
import java.util.List;
/**
* An import declaration, which can be of one of the following forms:
@@ -23,21 +22,27 @@ public class ImportDeclaration extends Statement implements INodeWithSymbol {
/** The module from which declarations are imported. */
private final Literal source;
private final Expression assertion;
private final Expression attributes;
private int symbol = -1;
private boolean hasTypeKeyword;
public ImportDeclaration(SourceLocation loc, List<ImportSpecifier> specifiers, Literal source, Expression assertion) {
this(loc, specifiers, source, assertion, false);
public ImportDeclaration(
SourceLocation loc, List<ImportSpecifier> specifiers, Literal source, Expression attributes) {
this(loc, specifiers, source, attributes, false);
}
public ImportDeclaration(SourceLocation loc, List<ImportSpecifier> specifiers, Literal source, Expression assertion, boolean hasTypeKeyword) {
public ImportDeclaration(
SourceLocation loc,
List<ImportSpecifier> specifiers,
Literal source,
Expression attributes,
boolean hasTypeKeyword) {
super("ImportDeclaration", loc);
this.specifiers = specifiers;
this.source = source;
this.assertion = assertion;
this.attributes = attributes;
this.hasTypeKeyword = hasTypeKeyword;
}
@@ -49,9 +54,12 @@ public class ImportDeclaration extends Statement implements INodeWithSymbol {
return specifiers;
}
/** Returns the expression after the <code>assert</code> keyword, if any, such as <code>{ type: "json" }</code>. */
public Expression getAssertion() {
return assertion;
/**
* Returns the expression after the <code>with</code> keyword, if any, such as <code>
* { type: "json" }</code>.
*/
public Expression getAttributes() {
return attributes;
}
@Override

View File

@@ -1,8 +1,5 @@
package com.semmle.js.ast;
import java.util.ArrayList;
import java.util.List;
import com.semmle.js.ast.jsx.JSXAttribute;
import com.semmle.js.ast.jsx.JSXClosingElement;
import com.semmle.js.ast.jsx.JSXElement;
@@ -42,16 +39,18 @@ import com.semmle.ts.ast.OptionalTypeExpr;
import com.semmle.ts.ast.ParenthesizedTypeExpr;
import com.semmle.ts.ast.PredicateTypeExpr;
import com.semmle.ts.ast.RestTypeExpr;
import com.semmle.ts.ast.SatisfiesExpr;
import com.semmle.ts.ast.TemplateLiteralTypeExpr;
import com.semmle.ts.ast.TupleTypeExpr;
import com.semmle.ts.ast.TypeAliasDeclaration;
import com.semmle.ts.ast.TypeAssertion;
import com.semmle.ts.ast.SatisfiesExpr;
import com.semmle.ts.ast.TypeParameter;
import com.semmle.ts.ast.TypeofTypeExpr;
import com.semmle.ts.ast.UnaryTypeExpr;
import com.semmle.ts.ast.UnionTypeExpr;
import com.semmle.util.data.IntList;
import java.util.ArrayList;
import java.util.List;
/** Deep cloning of AST nodes. */
public class NodeCopier implements Visitor<Void, INode> {
@@ -429,7 +428,8 @@ public class NodeCopier implements Visitor<Void, INode> {
@Override
public TemplateLiteralTypeExpr visit(TemplateLiteralTypeExpr nd, Void q) {
return new TemplateLiteralTypeExpr(visit(nd.getLoc()), copy(nd.getExpressions()), copy(nd.getQuasis()));
return new TemplateLiteralTypeExpr(
visit(nd.getLoc()), copy(nd.getExpressions()), copy(nd.getQuasis()));
}
@Override
@@ -523,7 +523,8 @@ public class NodeCopier implements Visitor<Void, INode> {
@Override
public ExportAllDeclaration visit(ExportAllDeclaration nd, Void c) {
return new ExportAllDeclaration(visit(nd.getLoc()), copy(nd.getSource()), copy(nd.getAssertion()));
return new ExportAllDeclaration(
visit(nd.getLoc()), copy(nd.getSource()), copy(nd.getAttributes()));
}
@Override
@@ -538,7 +539,7 @@ public class NodeCopier implements Visitor<Void, INode> {
copy(nd.getDeclaration()),
copy(nd.getSpecifiers()),
copy(nd.getSource()),
copy(nd.getAssertion()));
copy(nd.getAttributes()));
}
@Override
@@ -559,7 +560,11 @@ public class NodeCopier implements Visitor<Void, INode> {
@Override
public ImportDeclaration visit(ImportDeclaration nd, Void c) {
return new ImportDeclaration(
visit(nd.getLoc()), copy(nd.getSpecifiers()), copy(nd.getSource()), copy(nd.getAssertion()), nd.hasTypeKeyword());
visit(nd.getLoc()),
copy(nd.getSpecifiers()),
copy(nd.getSource()),
copy(nd.getAttributes()),
nd.hasTypeKeyword());
}
@Override
@@ -725,7 +730,8 @@ public class NodeCopier implements Visitor<Void, INode> {
@Override
public INode visit(TupleTypeExpr nd, Void c) {
return new TupleTypeExpr(visit(nd.getLoc()), copy(nd.getElementTypes()), copy(nd.getElementNames()));
return new TupleTypeExpr(
visit(nd.getLoc()), copy(nd.getElementTypes()), copy(nd.getElementNames()));
}
@Override
@@ -787,9 +793,7 @@ public class NodeCopier implements Visitor<Void, INode> {
@Override
public INode visit(SatisfiesExpr nd, Void c) {
return new SatisfiesExpr(
visit(nd.getLoc()),
copy(nd.getExpression()),
copy(nd.getTypeAnnotation()));
visit(nd.getLoc()), copy(nd.getExpression()), copy(nd.getTypeAnnotation()));
}
@Override
@@ -907,7 +911,8 @@ public class NodeCopier implements Visitor<Void, INode> {
@Override
public INode visit(GeneratedCodeExpr nd, Void c) {
return new GeneratedCodeExpr(visit(nd.getLoc()), nd.getOpeningDelimiter(), nd.getClosingDelimiter(), nd.getBody());
return new GeneratedCodeExpr(
visit(nd.getLoc()), nd.getOpeningDelimiter(), nd.getClosingDelimiter(), nd.getBody());
}
@Override

View File

@@ -1,15 +1,5 @@
package com.semmle.js.extractor;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import java.util.regex.Matcher;
import com.semmle.js.ast.AClass;
import com.semmle.js.ast.AFunction;
import com.semmle.js.ast.AFunctionExpression;
@@ -150,11 +140,11 @@ import com.semmle.ts.ast.OptionalTypeExpr;
import com.semmle.ts.ast.ParenthesizedTypeExpr;
import com.semmle.ts.ast.PredicateTypeExpr;
import com.semmle.ts.ast.RestTypeExpr;
import com.semmle.ts.ast.SatisfiesExpr;
import com.semmle.ts.ast.TemplateLiteralTypeExpr;
import com.semmle.ts.ast.TupleTypeExpr;
import com.semmle.ts.ast.TypeAliasDeclaration;
import com.semmle.ts.ast.TypeAssertion;
import com.semmle.ts.ast.SatisfiesExpr;
import com.semmle.ts.ast.TypeExpression;
import com.semmle.ts.ast.TypeParameter;
import com.semmle.ts.ast.TypeofTypeExpr;
@@ -166,6 +156,13 @@ import com.semmle.util.locations.OffsetTranslation;
import com.semmle.util.locations.SourceMap;
import com.semmle.util.trap.TrapWriter;
import com.semmle.util.trap.TrapWriter.Label;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import java.util.regex.Matcher;
/** Extractor for AST-based information; invoked by the {@link JSExtractor}. */
public class ASTExtractor {
@@ -387,7 +384,8 @@ public class ASTExtractor {
return visit(child, parent, childIndex, IdContext.VAR_BIND, binopOperand);
}
private Label visit(INode child, Label parent, int childIndex, IdContext idContext, boolean binopOperand) {
private Label visit(
INode child, Label parent, int childIndex, IdContext idContext, boolean binopOperand) {
if (child == null) return null;
return child.accept(this, new Context(parent, childIndex, idContext, binopOperand));
}
@@ -590,15 +588,28 @@ public class ASTExtractor {
trapwriter.addTuple("literals", valueString, source, key);
Position start = nd.getLoc().getStart();
com.semmle.util.locations.Position startPos = new com.semmle.util.locations.Position(start.getLine(), start.getColumn() + 1 /* Convert from 0-based to 1-based. */, start.getOffset());
com.semmle.util.locations.Position startPos =
new com.semmle.util.locations.Position(
start.getLine(),
start.getColumn() + 1 /* Convert from 0-based to 1-based. */,
start.getOffset());
if (nd.isRegExp()) {
OffsetTranslation offsets = new OffsetTranslation();
offsets.set(0, 1); // skip the initial '/'
SourceMap sourceMap = SourceMap.legacyWithStartPos(SourceMap.fromString(nd.getRaw()).offsetBy(0, offsets), startPos);
SourceMap sourceMap =
SourceMap.legacyWithStartPos(
SourceMap.fromString(nd.getRaw()).offsetBy(0, offsets), startPos);
regexpExtractor.extract(source.substring(1, source.lastIndexOf('/')), sourceMap, nd, false);
} else if (nd.isStringLiteral() && !c.isInsideType() && nd.getRaw().length() < 1000 && !c.isBinopOperand()) {
SourceMap sourceMap = SourceMap.legacyWithStartPos(SourceMap.fromString(nd.getRaw()).offsetBy(0, makeStringLiteralOffsets(nd.getRaw())), startPos);
} else if (nd.isStringLiteral()
&& !c.isInsideType()
&& nd.getRaw().length() < 1000
&& !c.isBinopOperand()) {
SourceMap sourceMap =
SourceMap.legacyWithStartPos(
SourceMap.fromString(nd.getRaw())
.offsetBy(0, makeStringLiteralOffsets(nd.getRaw())),
startPos);
regexpExtractor.extract(valueString, sourceMap, nd, true);
// Scan the string for template tags, if we're in a context where such tags are relevant.
@@ -621,8 +632,8 @@ public class ASTExtractor {
}
/**
* Constant-folds simple string concatenations in `exp` while keeping an offset translation
* that tracks back to the original source.
* Constant-folds simple string concatenations in `exp` while keeping an offset translation that
* tracks back to the original source.
*/
private Pair<String, OffsetTranslation> getStringConcatResult(Expression exp) {
if (exp instanceof BinaryExpression) {
@@ -638,7 +649,9 @@ public class ASTExtractor {
return null;
}
int delta = be.getRight().getLoc().getStart().getOffset() - be.getLeft().getLoc().getStart().getOffset();
int delta =
be.getRight().getLoc().getStart().getOffset()
- be.getLeft().getLoc().getStart().getOffset();
int offset = left.fst().length();
return Pair.make(str, left.snd().append(right.snd(), offset, delta));
}
@@ -748,7 +761,9 @@ public class ASTExtractor {
visit(nd.getProperty(), key, 1, IdContext.TYPE_LABEL);
} else {
IdContext baseIdContext =
(c.idcontext == IdContext.EXPORT || c.idcontext == IdContext.EXPORT_BASE) ? IdContext.EXPORT_BASE : IdContext.VAR_BIND;
(c.idcontext == IdContext.EXPORT || c.idcontext == IdContext.EXPORT_BASE)
? IdContext.EXPORT_BASE
: IdContext.VAR_BIND;
visit(nd.getObject(), key, 0, baseIdContext);
visit(nd.getProperty(), key, 1, nd.isComputed() ? IdContext.VAR_BIND : IdContext.LABEL);
}
@@ -848,8 +863,11 @@ public class ASTExtractor {
@Override
public Label visit(BinaryExpression nd, Context c) {
Label key = super.visit(nd, c);
if (nd.getOperator().equals("in") && nd.getLeft() instanceof Identifier && ((Identifier)nd.getLeft()).getName().startsWith("#")) {
// this happens with Ergonomic brand checks for Private Fields (see https://github.com/tc39/proposal-private-fields-in-in).
if (nd.getOperator().equals("in")
&& nd.getLeft() instanceof Identifier
&& ((Identifier) nd.getLeft()).getName().startsWith("#")) {
// this happens with Ergonomic brand checks for Private Fields (see
// https://github.com/tc39/proposal-private-fields-in-in).
// it's the only case where private field identifiers are used not as a field.
visit(nd.getLeft(), key, 0, IdContext.LABEL, true);
} else {
@@ -875,8 +893,14 @@ public class ASTExtractor {
}
OffsetTranslation offsets = concatResult.snd();
Position start = nd.getLoc().getStart();
com.semmle.util.locations.Position startPos = new com.semmle.util.locations.Position(start.getLine(), start.getColumn() + 1 /* Convert from 0-based to 1-based. */, start.getOffset());
SourceMap sourceMap = SourceMap.legacyWithStartPos(SourceMap.fromString(nd.getLoc().getSource()).offsetBy(0, offsets), startPos);
com.semmle.util.locations.Position startPos =
new com.semmle.util.locations.Position(
start.getLine(),
start.getColumn() + 1 /* Convert from 0-based to 1-based. */,
start.getOffset());
SourceMap sourceMap =
SourceMap.legacyWithStartPos(
SourceMap.fromString(nd.getLoc().getSource()).offsetBy(0, offsets), startPos);
regexpExtractor.extract(foldedString, sourceMap, nd, true);
return;
}
@@ -1759,7 +1783,7 @@ public class ASTExtractor {
public Label visit(ExportAllDeclaration nd, Context c) {
Label lbl = super.visit(nd, c);
visit(nd.getSource(), lbl, 0);
visit(nd.getAssertion(), lbl, -10);
visit(nd.getAttributes(), lbl, -10);
return lbl;
}
@@ -1775,7 +1799,7 @@ public class ASTExtractor {
Label lbl = super.visit(nd, c);
visit(nd.getDeclaration(), lbl, -1);
visit(nd.getSource(), lbl, -2);
visit(nd.getAssertion(), lbl, -10);
visit(nd.getAttributes(), lbl, -10);
IdContext childContext =
nd.hasSource()
? IdContext.LABEL
@@ -1799,7 +1823,7 @@ public class ASTExtractor {
public Label visit(ImportDeclaration nd, Context c) {
Label lbl = super.visit(nd, c);
visit(nd.getSource(), lbl, -1);
visit(nd.getAssertion(), lbl, -10);
visit(nd.getAttributes(), lbl, -10);
IdContext childContext =
nd.hasTypeKeyword()
? IdContext.TYPE_ONLY_IMPORT

View File

@@ -1,3 +1,17 @@
import "module" with { type: "json" };
import * as v1 from "module" with { type: "json" };
import { v2 } from "module" with { type: "json" };
import v3 from "module" with { type: "json" };
export { v4 } from "module" with { type: "json" };
export * from "module" with { type: "json" };
export * as v5 from "module" with { type: "json" };
const v6 = import("module", { with: { type: "json" } });
import "module" // missing semicolon
assert({type: "json"}); // function call, not import assertion
import "module" assert { type: "json" };
import * as v1 from "module" assert { type: "json" };
import { v2 } from "module" assert { type: "json" };
@@ -8,6 +22,3 @@ export * from "module" assert { type: "json" };
export * as v5 from "module" assert { type: "json" };
const v6 = import("module", { assert: { type: "json" } });
import "module" // missing semicolon
assert({type: "json"}); // function call, not import assertion

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
---
category: minorAnalysis
---
* [Import attributes](https://github.com/tc39/proposal-import-attributes) are now supported in JavaScript code.
Note that import attributes are an evolution of an earlier proposal called "import assertions", which were implemented in TypeScript 4.5.
The QL library includes new predicates named `getImportAttributes()` that should be used in favor of the now deprecated `getImportAssertion()`;
in addition, the `getImportAttributes()` method of the `DynamicImportExpr` has been renamed to `getImportOptions()`.

View File

@@ -91,14 +91,27 @@ class ImportDeclaration extends Stmt, Import, @import_declaration {
override PathExpr getImportedPath() { result = this.getChildExpr(-1) }
/**
* Gets the object literal passed as part of the `assert` clause in this import declaration.
* Gets the object literal passed as part of the `with` (or `assert`) clause in this import declaration.
*
* For example, this gets the `{ type: "json" }` object literal in the following:
* ```js
* import foo from "foo" with { type: "json" };
* import foo from "foo" assert { type: "json" };
* ```
*/
ObjectExpr getImportAssertion() { result = this.getChildExpr(-10) }
ObjectExpr getImportAttributes() { result = this.getChildExpr(-10) }
/**
* DEPRECATED: use `getImportAttributes` instead.
* Gets the object literal passed as part of the `with` (or `assert`) clause in this import declaration.
*
* For example, this gets the `{ type: "json" }` object literal in the following:
* ```js
* import foo from "foo" with { type: "json" };
* import foo from "foo" assert { type: "json" };
* ```
*/
deprecated ObjectExpr getImportAssertion() { result = this.getImportAttributes() }
/** Gets the `i`th import specifier of this import declaration. */
ImportSpecifier getSpecifier(int i) { result = this.getChildExpr(i) }
@@ -322,17 +335,33 @@ abstract class ExportDeclaration extends Stmt, @export_declaration {
override string getAPrimaryQlClass() { result = "ExportDeclaration" }
/**
* Gets the object literal passed as part of the `assert` clause, if this is
* Gets the object literal passed as part of the `with` (or `assert`) clause, if this is
* a re-export declaration.
*
* For example, this gets the `{ type: "json" }` expression in each of the following:
* ```js
* export { x } from 'foo' assert { type: "json" };
* export { x } from 'foo' with { type: "json" };
* export * from 'foo' with { type: "json" };
* export * as x from 'foo' with { type: "json" };
* export * from 'foo' assert { type: "json" };
* export * as x from 'foo' assert { type: "json" };
* ```
*/
ObjectExpr getImportAssertion() { result = this.getChildExpr(-10) }
ObjectExpr getImportAttributes() { result = this.getChildExpr(-10) }
/**
* DEPRECATED: use `getImportAttributes` instead.
* Gets the object literal passed as part of the `with` (or `assert`) clause, if this is
* a re-export declaration.
*
* For example, this gets the `{ type: "json" }` expression in each of the following:
* ```js
* export { x } from 'foo' with { type: "json" };
* export * from 'foo' with { type: "json" };
* export * as x from 'foo' with { type: "json" };
* export * from 'foo' assert { type: "json" };
* ```
*/
deprecated ObjectExpr getImportAssertion() { result = this.getImportAttributes() }
}
/**

View File

@@ -2807,7 +2807,7 @@ class FunctionBindExpr extends @bind_expr, Expr {
*
* ```
* import("fs")
* import("foo", { assert: { type: "json" }})
* import("foo", { with: { type: "json" }})
* ```
*/
class DynamicImportExpr extends @dynamic_import, Expr, Import {
@@ -2823,12 +2823,23 @@ class DynamicImportExpr extends @dynamic_import, Expr, Import {
/**
* Gets the second "argument" to the import expression, that is, the `Y` in `import(X, Y)`.
*
* For example, gets the `{ assert: { type: "json" }}` expression in the following:
* For example, gets the `{ with: { type: "json" }}` expression in the following:
* ```js
* import('foo', { assert: { type: "json" }})
* import('foo', { with: { type: "json" }})
* ```
*/
Expr getImportAttributes() { result = this.getChildExpr(1) }
Expr getImportOptions() { result = this.getChildExpr(1) }
/**
* DEPRECATED: use `getImportOptions` instead.
* Gets the second "argument" to the import expression, that is, the `Y` in `import(X, Y)`.
*
* For example, gets the `{ with: { type: "json" }}` expression in the following:
* ```js
* import('foo', { with: { type: "json" }})
* ```
*/
deprecated Expr getImportAttributes() { result = this.getImportOptions() }
override Module getEnclosingModule() { result = this.getTopLevel() }

View File

@@ -1,13 +1,24 @@
import "module" with { type: "json" };
import * as v1 from "module" with { type: "json" };
import { v2 } from "module" with { type: "json" };
import v3 from "module" with { type: "json" };
export { v4 } from "module" with { type: "json" };
export * from "module" with { type: "json" };
export * as v5 from "module" with { type: "json" };
const v6 = import("module", { with: { type: "json" } });
import "module" // missing semicolon
assert({type: "json"}); // function call, not import assertion
import "module" assert { type: "json" };
import * as v1 from "module" assert { type: "json" };
import { v2 } from "module" assert { type: "json" };
import v3 from "module" assert { type: "json" };
export { v4 } from "module" assert { type: "json" };
export { v7 } from "module" assert { type: "json" };
export * from "module" assert { type: "json" };
export * as v5 from "module" assert { type: "json" };
const v6 = import("module", { assert: { type: "json" } });
import "module" // missing semicolon
assert({type: "json"}); // function call, not import assertion

View File

@@ -1,20 +1,28 @@
getImportAssertionFromImport
| js-import-assertions.js:1:1:1:40 | import ... son" }; | js-import-assertions.js:1:24:1:39 | { type: "json" } |
| js-import-assertions.js:2:1:2:53 | import ... son" }; | js-import-assertions.js:2:37:2:52 | { type: "json" } |
| js-import-assertions.js:3:1:3:52 | import ... son" }; | js-import-assertions.js:3:36:3:51 | { type: "json" } |
| js-import-assertions.js:4:1:4:48 | import ... son" }; | js-import-assertions.js:4:32:4:47 | { type: "json" } |
getImportAttributesFromImport
| js-import-assertions.js:1:1:1:38 | import ... son" }; | js-import-assertions.js:1:22:1:37 | { type: "json" } |
| js-import-assertions.js:2:1:2:51 | import ... son" }; | js-import-assertions.js:2:35:2:50 | { type: "json" } |
| js-import-assertions.js:3:1:3:50 | import ... son" }; | js-import-assertions.js:3:34:3:49 | { type: "json" } |
| js-import-assertions.js:4:1:4:46 | import ... son" }; | js-import-assertions.js:4:30:4:45 | { type: "json" } |
| js-import-assertions.js:15:1:15:40 | import ... son" }; | js-import-assertions.js:15:24:15:39 | { type: "json" } |
| js-import-assertions.js:16:1:16:53 | import ... son" }; | js-import-assertions.js:16:37:16:52 | { type: "json" } |
| js-import-assertions.js:17:1:17:52 | import ... son" }; | js-import-assertions.js:17:36:17:51 | { type: "json" } |
| js-import-assertions.js:18:1:18:48 | import ... son" }; | js-import-assertions.js:18:32:18:47 | { type: "json" } |
| ts-import-assertions.ts:3:1:3:40 | import ... son" }; | ts-import-assertions.ts:3:24:3:39 | { type: "json" } |
| ts-import-assertions.ts:4:1:4:53 | import ... son" }; | ts-import-assertions.ts:4:37:4:52 | { type: "json" } |
| ts-import-assertions.ts:5:1:5:52 | import ... son" }; | ts-import-assertions.ts:5:36:5:51 | { type: "json" } |
| ts-import-assertions.ts:6:1:6:48 | import ... son" }; | ts-import-assertions.ts:6:32:6:47 | { type: "json" } |
getImportAssertionFromExport
| js-import-assertions.js:6:1:6:52 | export ... son" }; | js-import-assertions.js:6:36:6:51 | { type: "json" } |
| js-import-assertions.js:7:1:7:47 | export ... son" }; | js-import-assertions.js:7:31:7:46 | { type: "json" } |
| js-import-assertions.js:8:1:8:53 | export ... son" }; | js-import-assertions.js:8:37:8:52 | { type: "json" } |
getImportAttributesFromExport
| js-import-assertions.js:6:1:6:50 | export ... son" }; | js-import-assertions.js:6:34:6:49 | { type: "json" } |
| js-import-assertions.js:7:1:7:45 | export ... son" }; | js-import-assertions.js:7:29:7:44 | { type: "json" } |
| js-import-assertions.js:8:1:8:51 | export ... son" }; | js-import-assertions.js:8:35:8:50 | { type: "json" } |
| js-import-assertions.js:20:1:20:52 | export ... son" }; | js-import-assertions.js:20:36:20:51 | { type: "json" } |
| js-import-assertions.js:21:1:21:47 | export ... son" }; | js-import-assertions.js:21:31:21:46 | { type: "json" } |
| js-import-assertions.js:22:1:22:53 | export ... son" }; | js-import-assertions.js:22:37:22:52 | { type: "json" } |
| ts-import-assertions.ts:8:1:8:52 | export ... son" }; | ts-import-assertions.ts:8:36:8:51 | { type: "json" } |
| ts-import-assertions.ts:9:1:9:47 | export ... son" }; | ts-import-assertions.ts:9:31:9:46 | { type: "json" } |
| ts-import-assertions.ts:10:1:10:53 | export ... son" }; | ts-import-assertions.ts:10:37:10:52 | { type: "json" } |
getImportAttributes
| js-import-assertions.js:10:12:10:57 | import( ... n" } }) | js-import-assertions.js:10:29:10:56 | { asser ... on" } } |
getImportOptions
| js-import-assertions.js:10:12:10:55 | import( ... n" } }) | js-import-assertions.js:10:29:10:54 | { with: ... on" } } |
| js-import-assertions.js:24:12:24:57 | import( ... n" } }) | js-import-assertions.js:24:29:24:56 | { asser ... on" } } |
| ts-import-assertions.ts:12:12:12:57 | import( ... n" } }) | ts-import-assertions.ts:12:29:12:56 | { asser ... on" } } |
errors

View File

@@ -1,13 +1,13 @@
import javascript
query Expr getImportAssertionFromImport(ImportDeclaration decl) {
result = decl.getImportAssertion()
query Expr getImportAttributesFromImport(ImportDeclaration decl) {
result = decl.getImportAttributes()
}
query Expr getImportAssertionFromExport(ExportDeclaration decl) {
result = decl.getImportAssertion()
query Expr getImportAttributesFromExport(ExportDeclaration decl) {
result = decl.getImportAttributes()
}
query Expr getImportAttributes(DynamicImportExpr imprt) { result = imprt.getImportAttributes() }
query Expr getImportOptions(DynamicImportExpr imprt) { result = imprt.getImportOptions() }
query JSParseError errors() { any() }