Skip to content

Commit f454151

Browse files
committed
JS: Convert TypeScript import assertions
1 parent 3af085a commit f454151

File tree

4 files changed

+1162
-7
lines changed

4 files changed

+1162
-7
lines changed

javascript/extractor/lib/typescript/src/main.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ const astProperties: string[] = [
224224
"argument",
225225
"argumentExpression",
226226
"arguments",
227+
"assertClause",
227228
"assertsModifier",
228229
"asteriskToken",
229230
"attributes",

javascript/extractor/src/com/semmle/ts/extractor/TypeScriptASTConverter.java

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,10 @@ private Node convertNodeUntyped(JsonObject node, String defaultKind) throws Pars
342342
return convertArrowFunction(node, loc);
343343
case "AsExpression":
344344
return convertTypeAssertionExpression(node, loc);
345+
case "AssertClause":
346+
return convertAssertClause(node, loc);
347+
case "AssertEntry":
348+
return convertAssertEntry(node, loc);
345349
case "SatisfiesExpression":
346350
return convertSatisfiesExpression(node, loc);
347351
case "AwaitExpression":
@@ -887,8 +891,8 @@ private Node convertBreakStatement(JsonObject node, SourceLocation loc) throws P
887891

888892
private Node convertCallExpression(JsonObject node, SourceLocation loc) throws ParseError {
889893
List<Expression> arguments = convertChildren(node, "arguments");
890-
if (arguments.size() == 1 && hasKind(node.get("expression"), "ImportKeyword")) {
891-
return new DynamicImport(loc, arguments.get(0), null); // TODO: preserve import attributes
894+
if (arguments.size() >= 1 && hasKind(node.get("expression"), "ImportKeyword")) {
895+
return new DynamicImport(loc, arguments.get(0), arguments.size() > 1 ? arguments.get(1) : null);
892896
}
893897
Expression callee = convertChild(node, "expression");
894898
List<ITypeExpression> typeArguments = convertChildrenAsTypes(node, "typeArguments");
@@ -1193,15 +1197,16 @@ private Node convertExportAssignment(JsonObject node, SourceLocation loc) throws
11931197

11941198
private Node convertExportDeclaration(JsonObject node, SourceLocation loc) throws ParseError {
11951199
Literal source = tryConvertChild(node, "moduleSpecifier", Literal.class);
1200+
Expression assertion = convertChild(node, "assertClause");
11961201
if (hasChild(node, "exportClause")) {
11971202
boolean hasTypeKeyword = node.get("isTypeOnly").getAsBoolean();
11981203
List<ExportSpecifier> specifiers =
11991204
hasKind(node.get("exportClause"), "NamespaceExport")
12001205
? Collections.singletonList(convertChild(node, "exportClause"))
12011206
: convertChildren(node.get("exportClause").getAsJsonObject(), "elements");
1202-
return new ExportNamedDeclaration(loc, null, specifiers, source, null, hasTypeKeyword); // TODO: preserve import assertions
1207+
return new ExportNamedDeclaration(loc, null, specifiers, source, assertion, hasTypeKeyword);
12031208
} else {
1204-
return new ExportAllDeclaration(loc, source, null); // TODO: preserve import assertions
1209+
return new ExportAllDeclaration(loc, source, assertion);
12051210
}
12061211
}
12071212

@@ -1383,6 +1388,7 @@ private Node convertImportClause(JsonObject node, SourceLocation loc) throws Par
13831388

13841389
private Node convertImportDeclaration(JsonObject node, SourceLocation loc) throws ParseError {
13851390
Literal src = tryConvertChild(node, "moduleSpecifier", Literal.class);
1391+
Expression assertion = convertChild(node, "assertClause");
13861392
List<ImportSpecifier> specifiers = new ArrayList<>();
13871393
boolean hasTypeKeyword = false;
13881394
if (hasChild(node, "importClause")) {
@@ -1400,7 +1406,7 @@ private Node convertImportDeclaration(JsonObject node, SourceLocation loc) throw
14001406
}
14011407
hasTypeKeyword = importClause.get("isTypeOnly").getAsBoolean();
14021408
}
1403-
ImportDeclaration importDecl = new ImportDeclaration(loc, specifiers, src, null, hasTypeKeyword); // TODO: preserve import assertions
1409+
ImportDeclaration importDecl = new ImportDeclaration(loc, specifiers, src, assertion, hasTypeKeyword);
14041410
attachSymbolInformation(importDecl, node);
14051411
return importDecl;
14061412
}
@@ -1746,7 +1752,7 @@ private Node convertNamespaceDeclaration(JsonObject node, SourceLocation loc) th
17461752
if (hasFlag(node, "NestedNamespace")) {
17471753
// In a nested namespace declaration `namespace A.B`, the nested namespace `B`
17481754
// is implicitly exported.
1749-
return new ExportNamedDeclaration(loc, decl, new ArrayList<>(), null, null); // TODO: preserve import assertion
1755+
return new ExportNamedDeclaration(loc, decl, new ArrayList<>(), null, null);
17501756
} else {
17511757
return fixExports(loc, decl);
17521758
}
@@ -2276,6 +2282,24 @@ private Node convertTypeAssertionExpression(JsonObject node, SourceLocation loc)
22762282
return new TypeAssertion(loc, convertChild(node, "expression"), type, false);
22772283
}
22782284

2285+
private Node convertAssertClause(JsonObject node, SourceLocation loc) throws ParseError {
2286+
List<Property> properties = new ArrayList<>();
2287+
for (INode child : convertChildren(node, "elements")) {
2288+
properties.add((Property)child);
2289+
}
2290+
return new ObjectExpression(loc, properties);
2291+
}
2292+
2293+
private Node convertAssertEntry(JsonObject node, SourceLocation loc) throws ParseError {
2294+
return new Property(
2295+
loc,
2296+
convertChild(node, "key"),
2297+
convertChild(node, "value"),
2298+
"init",
2299+
false,
2300+
false);
2301+
}
2302+
22792303
private Node convertSatisfiesExpression(JsonObject node, SourceLocation loc) throws ParseError {
22802304
ITypeExpression type = convertChildAsType(node, "type");
22812305
return new SatisfiesExpr(loc, convertChild(node, "expression"), type);
@@ -2455,7 +2479,7 @@ private Node fixExports(SourceLocation loc, Node decl) {
24552479
advance(loc, skipped);
24562480
// capture group 1 is `default`, if present
24572481
if (m.group(1) == null)
2458-
return new ExportNamedDeclaration(outerLoc, (Statement) decl, new ArrayList<>(), null, null); // TODO: preserve import assertions
2482+
return new ExportNamedDeclaration(outerLoc, (Statement) decl, new ArrayList<>(), null, null);
24592483
return new ExportDefaultDeclaration(outerLoc, decl);
24602484
}
24612485
return decl;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import "module" assert { type: "json" };
2+
import * as v1 from "module" assert { type: "json" };
3+
import { v2 } from "module" assert { type: "json" };
4+
import v3 from "module" assert { type: "json" };
5+
6+
export { v4 } from "module" assert { type: "json" };
7+
export * from "module" assert { type: "json" };
8+
export * as v5 from "module" assert { type: "json" };
9+
10+
const v6 = import("module", { assert: { type: "json" } });
11+
12+
import "module"; // missing semicolon
13+
assert({ type: "json" }); // function call, not import assertion

0 commit comments

Comments
 (0)