mirror of
https://github.com/github/codeql.git
synced 2026-01-07 11:40:27 +01:00
Merge branch 'main' into henrymercer/polish-diagnostics
This commit is contained in:
@@ -314,7 +314,8 @@ public class ESNextParser extends JSXParser {
|
||||
this.parseExportSpecifiersMaybe(specifiers, exports);
|
||||
}
|
||||
Literal source = (Literal) this.parseExportFrom(specifiers, null, true);
|
||||
return this.finishNode(new ExportNamedDeclaration(exportStart, null, specifiers, source));
|
||||
Expression assertion = this.parseImportOrExportAssertionAndSemicolon();
|
||||
return this.finishNode(new ExportNamedDeclaration(exportStart, null, specifiers, source, assertion));
|
||||
}
|
||||
|
||||
return super.parseExportRest(exportStart, exports);
|
||||
@@ -330,7 +331,8 @@ public class ESNextParser extends JSXParser {
|
||||
List<ExportSpecifier> specifiers = CollectionUtil.makeList(nsSpec);
|
||||
this.parseExportSpecifiersMaybe(specifiers, exports);
|
||||
Literal source = (Literal) this.parseExportFrom(specifiers, null, true);
|
||||
return this.finishNode(new ExportNamedDeclaration(exportStart, null, specifiers, source));
|
||||
Expression assertion = this.parseImportOrExportAssertionAndSemicolon();
|
||||
return this.finishNode(new ExportNamedDeclaration(exportStart, null, specifiers, source, assertion));
|
||||
}
|
||||
|
||||
return super.parseExportAll(exportStart, starLoc, exports);
|
||||
@@ -435,8 +437,15 @@ public class ESNextParser extends JSXParser {
|
||||
*/
|
||||
private DynamicImport parseDynamicImport(Position startLoc) {
|
||||
Expression source = parseMaybeAssign(false, null, null);
|
||||
Expression attributes = null;
|
||||
if (this.eat(TokenType.comma)) {
|
||||
if (this.type != TokenType.parenR) { // Skip if the comma was a trailing comma
|
||||
attributes = this.parseMaybeAssign(false, null, null);
|
||||
this.eat(TokenType.comma); // Allow trailing comma
|
||||
}
|
||||
}
|
||||
this.expect(TokenType.parenR);
|
||||
DynamicImport di = this.finishNode(new DynamicImport(new SourceLocation(startLoc), source));
|
||||
DynamicImport di = this.finishNode(new DynamicImport(new SourceLocation(startLoc), source, attributes));
|
||||
return di;
|
||||
}
|
||||
|
||||
|
||||
@@ -1648,13 +1648,13 @@ public class Parser {
|
||||
return this.finishNode(node);
|
||||
} else if (this.type == TokenType.pound) {
|
||||
Position startLoc = this.startLoc;
|
||||
// there is only one case where this is valid, and that is "Ergonomic brand checks for Private Fields", i.e. `#name in obj`.
|
||||
// there is only one case where this is valid, and that is "Ergonomic brand checks for Private Fields", i.e. `#name in obj`.
|
||||
Identifier id = parseIdent(true);
|
||||
String op = String.valueOf(this.value);
|
||||
if (!op.equals("in")) {
|
||||
this.unexpected(startLoc);
|
||||
}
|
||||
return this.parseExprOp(id, this.start, startLoc, -1, false);
|
||||
return this.parseExprOp(id, this.start, startLoc, -1, false);
|
||||
} else if (this.type == TokenType.name) {
|
||||
Position startLoc = this.startLoc;
|
||||
Identifier id = this.parseIdent(this.type != TokenType.name);
|
||||
@@ -2783,7 +2783,7 @@ public class Parser {
|
||||
boolean isBreak = keyword.equals("break");
|
||||
this.next();
|
||||
Identifier label = null;
|
||||
if (this.eat(TokenType.semi) || this.insertSemicolon()) {
|
||||
if (this.eagerlyTrySemicolon()) {
|
||||
label = null;
|
||||
} else if (this.type != TokenType.name) {
|
||||
this.unexpected();
|
||||
@@ -2893,6 +2893,15 @@ public class Parser {
|
||||
new IfStatement(new SourceLocation(startLoc), test, consequent, alternate));
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumes or inserts a semicolon if possible, and returns true if a semicolon was consumed or inserted.
|
||||
*
|
||||
* Returns false if there was no semicolon and insertion was not possible.
|
||||
*/
|
||||
protected boolean eagerlyTrySemicolon() {
|
||||
return this.eat(TokenType.semi) || this.insertSemicolon();
|
||||
}
|
||||
|
||||
protected ReturnStatement parseReturnStatement(Position startLoc) {
|
||||
if (!this.inFunction && !this.options.allowReturnOutsideFunction())
|
||||
this.raise(this.start, "'return' outside of function");
|
||||
@@ -2902,7 +2911,7 @@ public class Parser {
|
||||
// optional arguments, we eagerly look for a semicolon or the
|
||||
// possibility to insert one.
|
||||
Expression argument;
|
||||
if (this.eat(TokenType.semi) || this.insertSemicolon()) {
|
||||
if (this.eagerlyTrySemicolon()) {
|
||||
argument = null;
|
||||
} else {
|
||||
argument = this.parseExpression(false, null);
|
||||
@@ -3404,6 +3413,7 @@ public class Parser {
|
||||
Statement declaration;
|
||||
List<ExportSpecifier> specifiers;
|
||||
Expression source = null;
|
||||
Expression assertion = null;
|
||||
if (this.shouldParseExportStatement()) {
|
||||
declaration = this.parseStatement(true, false);
|
||||
if (declaration == null) return null;
|
||||
@@ -3419,11 +3429,13 @@ public class Parser {
|
||||
declaration = null;
|
||||
specifiers = this.parseExportSpecifiers(exports);
|
||||
source = parseExportFrom(specifiers, source, false);
|
||||
assertion = parseImportOrExportAssertionAndSemicolon();
|
||||
}
|
||||
return this.finishNode(
|
||||
new ExportNamedDeclaration(loc, declaration, specifiers, (Literal) source));
|
||||
new ExportNamedDeclaration(loc, declaration, specifiers, (Literal) source, assertion));
|
||||
}
|
||||
|
||||
/** Parses the 'from' clause of an export, not including the assertion or semicolon. */
|
||||
protected Expression parseExportFrom(
|
||||
List<ExportSpecifier> specifiers, Expression source, boolean expectFrom) {
|
||||
if (this.eatContextual("from")) {
|
||||
@@ -3442,14 +3454,14 @@ public class Parser {
|
||||
|
||||
source = null;
|
||||
}
|
||||
this.semicolon();
|
||||
return source;
|
||||
}
|
||||
|
||||
protected ExportDeclaration parseExportAll(
|
||||
SourceLocation loc, Position starLoc, Set<String> exports) {
|
||||
Expression source = parseExportFrom(null, null, true);
|
||||
return this.finishNode(new ExportAllDeclaration(loc, (Literal) source));
|
||||
Expression assertion = parseImportOrExportAssertionAndSemicolon();
|
||||
return this.finishNode(new ExportAllDeclaration(loc, (Literal) source, assertion));
|
||||
}
|
||||
|
||||
private void checkExport(Set<String> exports, String name, Position pos) {
|
||||
@@ -3514,6 +3526,16 @@ public class Parser {
|
||||
return parseImportRest(loc);
|
||||
}
|
||||
|
||||
protected Expression parseImportOrExportAssertionAndSemicolon() {
|
||||
Expression result = null;
|
||||
if (!this.eagerlyTrySemicolon()) {
|
||||
this.expectContextual("assert");
|
||||
result = this.parseObj(false, null);
|
||||
this.semicolon();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected ImportDeclaration parseImportRest(SourceLocation loc) {
|
||||
List<ImportSpecifier> specifiers;
|
||||
Literal source;
|
||||
@@ -3527,9 +3549,9 @@ public class Parser {
|
||||
if (this.type != TokenType.string) this.unexpected();
|
||||
source = (Literal) this.parseExprAtom(null);
|
||||
}
|
||||
this.semicolon();
|
||||
Expression assertion = this.parseImportOrExportAssertionAndSemicolon();
|
||||
if (specifiers == null) return null;
|
||||
return this.finishNode(new ImportDeclaration(loc, specifiers, source));
|
||||
return this.finishNode(new ImportDeclaration(loc, specifiers, source, assertion));
|
||||
}
|
||||
|
||||
// Parses a comma-separated list of module imports.
|
||||
|
||||
@@ -943,10 +943,12 @@ public class FlowParser extends ESNextParser {
|
||||
// `export type { foo, bar };`
|
||||
List<ExportSpecifier> specifiers = this.parseExportSpecifiers(exports);
|
||||
this.parseExportFrom(specifiers, null, false);
|
||||
this.parseImportOrExportAssertionAndSemicolon();
|
||||
return null;
|
||||
} else if (this.eat(TokenType.star)) {
|
||||
if (this.eatContextual("as")) this.parseIdent(true);
|
||||
this.parseExportFrom(null, null, true);
|
||||
this.parseImportOrExportAssertionAndSemicolon();
|
||||
return null;
|
||||
} else {
|
||||
// `export type Foo = Bar;`
|
||||
|
||||
@@ -2,16 +2,23 @@ package com.semmle.js.ast;
|
||||
|
||||
public class DynamicImport extends Expression {
|
||||
private final Expression source;
|
||||
private final Expression attributes;
|
||||
|
||||
public DynamicImport(SourceLocation loc, Expression source) {
|
||||
public DynamicImport(SourceLocation loc, Expression source, Expression attributes) {
|
||||
super("DynamicImport", loc);
|
||||
this.source = source;
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
public Expression getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
/** Returns the second "argument" provided to the import, such as <code>{ assert: { type: "json" }}</code>. */
|
||||
public Expression getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
|
||||
@@ -9,16 +9,22 @@ package com.semmle.js.ast;
|
||||
*/
|
||||
public class ExportAllDeclaration extends ExportDeclaration {
|
||||
private final Literal source;
|
||||
private final Expression assertion;
|
||||
|
||||
public ExportAllDeclaration(SourceLocation loc, Literal source) {
|
||||
public ExportAllDeclaration(SourceLocation loc, Literal source, Expression assertion) {
|
||||
super("ExportAllDeclaration", loc);
|
||||
this.source = source;
|
||||
this.assertion = assertion;
|
||||
}
|
||||
|
||||
public Literal getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public Expression getAssertion() {
|
||||
return assertion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
|
||||
@@ -15,20 +15,22 @@ public class ExportNamedDeclaration extends ExportDeclaration {
|
||||
private final Statement declaration;
|
||||
private final List<ExportSpecifier> specifiers;
|
||||
private final Literal source;
|
||||
private final Expression assertion;
|
||||
private final boolean hasTypeKeyword;
|
||||
|
||||
public ExportNamedDeclaration(
|
||||
SourceLocation loc, Statement declaration, List<ExportSpecifier> specifiers, Literal source) {
|
||||
this(loc, declaration, specifiers, source, false);
|
||||
SourceLocation loc, Statement declaration, List<ExportSpecifier> specifiers, Literal source, Expression assertion) {
|
||||
this(loc, declaration, specifiers, source, assertion, false);
|
||||
}
|
||||
|
||||
public ExportNamedDeclaration(
|
||||
SourceLocation loc, Statement declaration, List<ExportSpecifier> specifiers, Literal source,
|
||||
boolean hasTypeKeyword) {
|
||||
Expression assertion, boolean hasTypeKeyword) {
|
||||
super("ExportNamedDeclaration", loc);
|
||||
this.declaration = declaration;
|
||||
this.specifiers = specifiers;
|
||||
this.source = source;
|
||||
this.assertion = assertion;
|
||||
this.hasTypeKeyword = hasTypeKeyword;
|
||||
}
|
||||
|
||||
@@ -57,6 +59,11 @@ 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 true if this is an <code>export type</code> declaration. */
|
||||
public boolean hasTypeKeyword() {
|
||||
return hasTypeKeyword;
|
||||
|
||||
@@ -23,18 +23,21 @@ public class ImportDeclaration extends Statement implements INodeWithSymbol {
|
||||
/** The module from which declarations are imported. */
|
||||
private final Literal source;
|
||||
|
||||
private final Expression assertion;
|
||||
|
||||
private int symbol = -1;
|
||||
|
||||
private boolean hasTypeKeyword;
|
||||
|
||||
public ImportDeclaration(SourceLocation loc, List<ImportSpecifier> specifiers, Literal source) {
|
||||
this(loc, specifiers, source, false);
|
||||
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, boolean hasTypeKeyword) {
|
||||
public ImportDeclaration(SourceLocation loc, List<ImportSpecifier> specifiers, Literal source, Expression assertion, boolean hasTypeKeyword) {
|
||||
super("ImportDeclaration", loc);
|
||||
this.specifiers = specifiers;
|
||||
this.source = source;
|
||||
this.assertion = assertion;
|
||||
this.hasTypeKeyword = hasTypeKeyword;
|
||||
}
|
||||
|
||||
@@ -46,6 +49,11 @@ 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
|
||||
@@ -523,7 +523,7 @@ public class NodeCopier implements Visitor<Void, INode> {
|
||||
|
||||
@Override
|
||||
public ExportAllDeclaration visit(ExportAllDeclaration nd, Void c) {
|
||||
return new ExportAllDeclaration(visit(nd.getLoc()), copy(nd.getSource()));
|
||||
return new ExportAllDeclaration(visit(nd.getLoc()), copy(nd.getSource()), copy(nd.getAssertion()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -537,7 +537,8 @@ public class NodeCopier implements Visitor<Void, INode> {
|
||||
visit(nd.getLoc()),
|
||||
copy(nd.getDeclaration()),
|
||||
copy(nd.getSpecifiers()),
|
||||
copy(nd.getSource()));
|
||||
copy(nd.getSource()),
|
||||
copy(nd.getAssertion()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -558,7 +559,7 @@ 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()));
|
||||
visit(nd.getLoc()), copy(nd.getSpecifiers()), copy(nd.getSource()), copy(nd.getAssertion()), nd.hasTypeKeyword());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -678,7 +679,7 @@ public class NodeCopier implements Visitor<Void, INode> {
|
||||
|
||||
@Override
|
||||
public INode visit(DynamicImport nd, Void c) {
|
||||
return new DynamicImport(visit(nd.getLoc()), copy(nd.getSource()));
|
||||
return new DynamicImport(visit(nd.getLoc()), copy(nd.getSource()), copy(nd.getAttributes()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1759,6 +1759,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);
|
||||
return lbl;
|
||||
}
|
||||
|
||||
@@ -1774,6 +1775,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);
|
||||
IdContext childContext =
|
||||
nd.hasSource()
|
||||
? IdContext.LABEL
|
||||
@@ -1797,6 +1799,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);
|
||||
IdContext childContext =
|
||||
nd.hasTypeKeyword()
|
||||
? IdContext.TYPE_ONLY_IMPORT
|
||||
@@ -1972,6 +1975,7 @@ public class ASTExtractor {
|
||||
public Label visit(DynamicImport nd, Context c) {
|
||||
Label key = super.visit(nd, c);
|
||||
visit(nd.getSource(), key, 0);
|
||||
visit(nd.getAttributes(), key, 1);
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
@@ -177,6 +177,7 @@ public class TypeScriptASTConverter {
|
||||
private static final Pattern EXPORT_DECL_START =
|
||||
Pattern.compile("^export" + "(" + WHITESPACE_CHAR + "+default)?" + WHITESPACE_CHAR + "+");
|
||||
private static final Pattern TYPEOF_START = Pattern.compile("^typeof" + WHITESPACE_CHAR + "+");
|
||||
private static final Pattern ASSERT_START = Pattern.compile("^assert" + WHITESPACE_CHAR + "+");
|
||||
private static final Pattern WHITESPACE_END_PAREN =
|
||||
Pattern.compile("^" + WHITESPACE_CHAR + "*\\)");
|
||||
|
||||
@@ -342,7 +343,11 @@ public class TypeScriptASTConverter {
|
||||
return convertArrowFunction(node, loc);
|
||||
case "AsExpression":
|
||||
return convertTypeAssertionExpression(node, loc);
|
||||
case "SatisfiesExpression":
|
||||
case "AssertClause":
|
||||
return convertAssertClause(node, loc);
|
||||
case "AssertEntry":
|
||||
return convertAssertEntry(node, loc);
|
||||
case "SatisfiesExpression":
|
||||
return convertSatisfiesExpression(node, loc);
|
||||
case "AwaitExpression":
|
||||
return convertAwaitExpression(node, loc);
|
||||
@@ -887,8 +892,8 @@ public class TypeScriptASTConverter {
|
||||
|
||||
private Node convertCallExpression(JsonObject node, SourceLocation loc) throws ParseError {
|
||||
List<Expression> arguments = convertChildren(node, "arguments");
|
||||
if (arguments.size() == 1 && hasKind(node.get("expression"), "ImportKeyword")) {
|
||||
return new DynamicImport(loc, arguments.get(0));
|
||||
if (arguments.size() >= 1 && hasKind(node.get("expression"), "ImportKeyword")) {
|
||||
return new DynamicImport(loc, arguments.get(0), arguments.size() > 1 ? arguments.get(1) : null);
|
||||
}
|
||||
Expression callee = convertChild(node, "expression");
|
||||
List<ITypeExpression> typeArguments = convertChildrenAsTypes(node, "typeArguments");
|
||||
@@ -1193,15 +1198,16 @@ public class TypeScriptASTConverter {
|
||||
|
||||
private Node convertExportDeclaration(JsonObject node, SourceLocation loc) throws ParseError {
|
||||
Literal source = tryConvertChild(node, "moduleSpecifier", Literal.class);
|
||||
Expression assertion = convertChild(node, "assertClause");
|
||||
if (hasChild(node, "exportClause")) {
|
||||
boolean hasTypeKeyword = node.get("isTypeOnly").getAsBoolean();
|
||||
List<ExportSpecifier> specifiers =
|
||||
hasKind(node.get("exportClause"), "NamespaceExport")
|
||||
? Collections.singletonList(convertChild(node, "exportClause"))
|
||||
: convertChildren(node.get("exportClause").getAsJsonObject(), "elements");
|
||||
return new ExportNamedDeclaration(loc, null, specifiers, source, hasTypeKeyword);
|
||||
return new ExportNamedDeclaration(loc, null, specifiers, source, assertion, hasTypeKeyword);
|
||||
} else {
|
||||
return new ExportAllDeclaration(loc, source);
|
||||
return new ExportAllDeclaration(loc, source, assertion);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1383,6 +1389,7 @@ public class TypeScriptASTConverter {
|
||||
|
||||
private Node convertImportDeclaration(JsonObject node, SourceLocation loc) throws ParseError {
|
||||
Literal src = tryConvertChild(node, "moduleSpecifier", Literal.class);
|
||||
Expression assertion = convertChild(node, "assertClause");
|
||||
List<ImportSpecifier> specifiers = new ArrayList<>();
|
||||
boolean hasTypeKeyword = false;
|
||||
if (hasChild(node, "importClause")) {
|
||||
@@ -1400,7 +1407,7 @@ public class TypeScriptASTConverter {
|
||||
}
|
||||
hasTypeKeyword = importClause.get("isTypeOnly").getAsBoolean();
|
||||
}
|
||||
ImportDeclaration importDecl = new ImportDeclaration(loc, specifiers, src, hasTypeKeyword);
|
||||
ImportDeclaration importDecl = new ImportDeclaration(loc, specifiers, src, assertion, hasTypeKeyword);
|
||||
attachSymbolInformation(importDecl, node);
|
||||
return importDecl;
|
||||
}
|
||||
@@ -1746,7 +1753,7 @@ public class TypeScriptASTConverter {
|
||||
if (hasFlag(node, "NestedNamespace")) {
|
||||
// In a nested namespace declaration `namespace A.B`, the nested namespace `B`
|
||||
// is implicitly exported.
|
||||
return new ExportNamedDeclaration(loc, decl, new ArrayList<>(), null);
|
||||
return new ExportNamedDeclaration(loc, decl, new ArrayList<>(), null, null);
|
||||
} else {
|
||||
return fixExports(loc, decl);
|
||||
}
|
||||
@@ -2276,6 +2283,29 @@ public class TypeScriptASTConverter {
|
||||
return new TypeAssertion(loc, convertChild(node, "expression"), type, false);
|
||||
}
|
||||
|
||||
private Node convertAssertClause(JsonObject node, SourceLocation loc) throws ParseError {
|
||||
List<Property> properties = new ArrayList<>();
|
||||
for (INode child : convertChildren(node, "elements")) {
|
||||
properties.add((Property)child);
|
||||
}
|
||||
// Adjust location to skip over the `assert` keyword.
|
||||
Matcher m = ASSERT_START.matcher(loc.getSource());
|
||||
if (m.find()) {
|
||||
advance(loc, m.group(0));
|
||||
}
|
||||
return new ObjectExpression(loc, properties);
|
||||
}
|
||||
|
||||
private Node convertAssertEntry(JsonObject node, SourceLocation loc) throws ParseError {
|
||||
return new Property(
|
||||
loc,
|
||||
convertChild(node, "key"),
|
||||
convertChild(node, "value"),
|
||||
"init",
|
||||
false,
|
||||
false);
|
||||
}
|
||||
|
||||
private Node convertSatisfiesExpression(JsonObject node, SourceLocation loc) throws ParseError {
|
||||
ITypeExpression type = convertChildAsType(node, "type");
|
||||
return new SatisfiesExpr(loc, convertChild(node, "expression"), type);
|
||||
@@ -2455,7 +2485,7 @@ public class TypeScriptASTConverter {
|
||||
advance(loc, skipped);
|
||||
// capture group 1 is `default`, if present
|
||||
if (m.group(1) == null)
|
||||
return new ExportNamedDeclaration(outerLoc, (Statement) decl, new ArrayList<>(), null);
|
||||
return new ExportNamedDeclaration(outerLoc, (Statement) decl, new ArrayList<>(), null, null);
|
||||
return new ExportDefaultDeclaration(outerLoc, decl);
|
||||
}
|
||||
return decl;
|
||||
|
||||
Reference in New Issue
Block a user