Skip to content

Commit 4b51ca9

Browse files
committed
Add some case
1 parent 5a1af04 commit 4b51ca9

25 files changed

+1028
-34
lines changed

src/compiler/checker.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -39882,11 +39882,11 @@ namespace ts {
3988239882
checkGrammarForDisallowedTrailingComma(nodeArguments);
3988339883
}
3988439884
else {
39885-
if (nodeArguments.length > 2) {
39885+
if (nodeArguments.length !== 1 && nodeArguments.length !== 2) {
3988639886
return grammarErrorOnNode(node, Diagnostics.Dynamic_import_must_have_a_specifier_as_arguments_and_an_optional_assertion);
3988739887
}
3988839888
}
39889-
return false
39889+
return false;
3989039890
}
3989139891

3989239892
function checkGrammarImportCallExpression(node: ImportCall): boolean {
@@ -39904,7 +39904,7 @@ namespace ts {
3990439904
}
3990539905
// see: parseArgumentOrArrayLiteralElement...we use this function which parse arguments of callExpression to parse specifier for dynamic import.
3990639906
// parseArgumentOrArrayLiteralElement allows spread element to be in an argument list which is not allowed as specifier in dynamic import.
39907-
if (isSpreadElement(nodeArguments[0])) {
39907+
if (nodeArguments.length && isSpreadElement(nodeArguments[0])) {
3990839908
return grammarErrorOnNode(nodeArguments[0], Diagnostics.Specifier_of_dynamic_import_cannot_be_spread_element);
3990939909
}
3991039910
return false;

src/compiler/emitter.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -3188,21 +3188,23 @@ namespace ts {
31883188
emitExpression(node.moduleSpecifier);
31893189
if (node.assertClause) {
31903190
writeSpace();
3191-
emit(node.assertClause)
3191+
emit(node.assertClause);
31923192
}
31933193
writeTrailingSemicolon();
31943194
}
31953195

31963196
function emitAssertClause(node: AssertClause) {
3197+
emitTokenWithComment(SyntaxKind.AssertKeyword, node.pos, writeKeyword, node);
3198+
writeSpace();
31973199
const elements = node.elements;
3198-
emitExpressionList(node, elements, ListFormat.ImportClauseEntries);
3200+
emitNodeList(emitAssertEntry, node, elements, ListFormat.ImportClauseEntries);
31993201
}
32003202

32013203
function emitAssertEntry(node: AssertEntry) {
32023204
emit(node.name);
32033205
writePunctuation(":");
32043206
writeSpace();
3205-
3207+
32063208
const value = node.value;
32073209
/** @see emitPropertyAssignment */
32083210
if (emitTrailingCommentsOfPosition && (getEmitFlags(value) & EmitFlags.NoLeadingComments) === 0) {
@@ -3275,6 +3277,10 @@ namespace ts {
32753277
writeSpace();
32763278
emitExpression(node.moduleSpecifier);
32773279
}
3280+
if (node.assertClause) {
3281+
writeSpace();
3282+
emit(node.assertClause);
3283+
}
32783284
writeTrailingSemicolon();
32793285
}
32803286

src/compiler/factory/nodeFactory.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -3856,17 +3856,19 @@ namespace ts {
38563856
}
38573857

38583858
// @api
3859-
function createAssertClause(elements: NodeArray<AssertEntry> | undefined): AssertClause {
3859+
function createAssertClause(elements: NodeArray<AssertEntry>, multiLine?: boolean): AssertClause {
38603860
const node = createBaseNode<AssertClause>(SyntaxKind.AssertClause);
38613861
node.elements = elements;
3862+
node.multiLine = multiLine;
38623863
node.transformFlags |= TransformFlags.ContainsESNext;
38633864
return node;
38643865
}
38653866

38663867
// @api
3867-
function updateAssertClause(node: AssertClause, elements: NodeArray<AssertEntry> | undefined): AssertClause {
3868+
function updateAssertClause(node: AssertClause, elements: NodeArray<AssertEntry>, multiLine?: boolean): AssertClause {
38683869
return node.elements !== elements
3869-
? update(createAssertClause(elements), node)
3870+
|| node.multiLine !== multiLine
3871+
? update(createAssertClause(elements, multiLine), node)
38703872
: node;
38713873
}
38723874

@@ -3880,7 +3882,7 @@ namespace ts {
38803882
}
38813883

38823884
// @api
3883-
function updateAssertEntry (node: AssertEntry, name: AssertionKey, value: StringLiteral): AssertEntry {
3885+
function updateAssertEntry(node: AssertEntry, name: AssertionKey, value: StringLiteral): AssertEntry {
38843886
return node.name !== name
38853887
|| node.value !== value
38863888
? update(createAssertEntry(name, value), node)

src/compiler/parser.ts

+28-15
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,8 @@ namespace ts {
394394
return visitNodes(cbNode, cbNodes, node.decorators) ||
395395
visitNodes(cbNode, cbNodes, node.modifiers) ||
396396
visitNode(cbNode, (<ImportDeclaration>node).importClause) ||
397-
visitNode(cbNode, (<ImportDeclaration>node).moduleSpecifier);
397+
visitNode(cbNode, (<ImportDeclaration>node).moduleSpecifier) ||
398+
visitNode(cbNode, (<ImportDeclaration>node).assertClause);
398399
case SyntaxKind.ImportClause:
399400
return visitNode(cbNode, (<ImportClause>node).name) ||
400401
visitNode(cbNode, (<ImportClause>node).namedBindings);
@@ -417,7 +418,8 @@ namespace ts {
417418
return visitNodes(cbNode, cbNodes, node.decorators) ||
418419
visitNodes(cbNode, cbNodes, node.modifiers) ||
419420
visitNode(cbNode, (<ExportDeclaration>node).exportClause) ||
420-
visitNode(cbNode, (<ExportDeclaration>node).moduleSpecifier);
421+
visitNode(cbNode, (<ExportDeclaration>node).moduleSpecifier) ||
422+
visitNode(cbNode, (<ExportDeclaration>node).assertClause);
421423
case SyntaxKind.ImportSpecifier:
422424
case SyntaxKind.ExportSpecifier:
423425
return visitNode(cbNode, (<ImportOrExportSpecifier>node).propertyName) ||
@@ -1698,7 +1700,7 @@ namespace ts {
16981700
function isAssertionKey(): boolean {
16991701
return tokenIsIdentifierOrKeyword(token()) ||
17001702
token() === SyntaxKind.StringLiteral;
1701-
}
1703+
}
17021704

17031705
function parsePropertyNameWorker(allowComputedPropertyNames: boolean): PropertyName {
17041706
if (token() === SyntaxKind.StringLiteral || token() === SyntaxKind.NumericLiteral) {
@@ -1865,7 +1867,7 @@ namespace ts {
18651867
case ParsingContext.ObjectBindingElements:
18661868
return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName();
18671869
case ParsingContext.AssertEntries:
1868-
return isAssertionKey()
1870+
return isAssertionKey();
18691871
case ParsingContext.HeritageClauseElement:
18701872
// If we see `{ ... }` then only consume it as an expression if it is followed by `,` or `{`
18711873
// That way we won't consume the body of a class in its heritage clause.
@@ -6915,30 +6917,42 @@ namespace ts {
69156917
parseExpected(SyntaxKind.FromKeyword);
69166918
}
69176919
const moduleSpecifier = parseModuleSpecifier();
6918-
const afterSpecifierPos = scanner.getStartPos();
69196920

69206921
let assertClause: AssertClause | undefined;
69216922
if (token() === SyntaxKind.AssertKeyword && !scanner.hasPrecedingLineBreak()) {
6922-
assertClause = parseAssertClause(afterSpecifierPos);
6923+
assertClause = parseAssertClause();
69236924
}
69246925

69256926
parseSemicolon();
69266927
const node = factory.createImportDeclaration(decorators, modifiers, importClause, moduleSpecifier, assertClause);
69276928
return withJSDoc(finishNode(node, pos), hasJSDoc);
69286929
}
69296930

6930-
function parseAssertEntry () {
6931+
function parseAssertEntry() {
69316932
const pos = getNodePos();
69326933
const name = tokenIsIdentifierOrKeyword(token()) ? parseIdentifierName() : parseLiteralLikeNode(SyntaxKind.StringLiteral) as StringLiteral;
6933-
parseExpected(SyntaxKind.ColonToken)
6934+
parseExpected(SyntaxKind.ColonToken);
69346935
const value = parseLiteralLikeNode(SyntaxKind.StringLiteral) as StringLiteral;
69356936
return finishNode(factory.createAssertEntry(name, value), pos);
69366937
}
69376938

6938-
function parseAssertClause(pos: number) {
6939-
parseExpected(SyntaxKind.AssertKeyword)
6940-
const elements = parseList(ParsingContext.AssertEntries, parseAssertEntry)
6941-
return finishNode(factory.createAssertClause(elements), pos);
6939+
function parseAssertClause() {
6940+
const pos = getNodePos();
6941+
parseExpected(SyntaxKind.AssertKeyword);
6942+
const openBracePosition = scanner.getTokenPos();
6943+
parseExpected(SyntaxKind.OpenBraceToken);
6944+
const multiLine = scanner.hasPrecedingLineBreak();
6945+
const elements = parseDelimitedList(ParsingContext.AssertEntries, parseAssertEntry, /*considerSemicolonAsDelimiter*/ true);
6946+
if (!parseExpected(SyntaxKind.CloseBraceToken)) {
6947+
const lastError = lastOrUndefined(parseDiagnostics);
6948+
if (lastError && lastError.code === Diagnostics._0_expected.code) {
6949+
addRelatedInfo(
6950+
lastError,
6951+
createDetachedDiagnostic(fileName, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_to_match_the_token_here)
6952+
);
6953+
}
6954+
}
6955+
return finishNode(factory.createAssertClause(elements, multiLine), pos);
69426956
}
69436957

69446958
function tokenAfterImportDefinitelyProducesImportDeclaration() {
@@ -7111,9 +7125,8 @@ namespace ts {
71117125
moduleSpecifier = parseModuleSpecifier();
71127126
}
71137127
}
7114-
if (token() === SyntaxKind.AssertKeyword && !scanner.hasPrecedingLineBreak()) {
7115-
const posAfterSpecifier = getNodePos();
7116-
assertClause = parseAssertClause(posAfterSpecifier);
7128+
if (moduleSpecifier && token() === SyntaxKind.AssertKeyword && !scanner.hasPrecedingLineBreak()) {
7129+
assertClause = parseAssertClause();
71177130
}
71187131
parseSemicolon();
71197132
setAwaitContext(savedAwaitContext);

src/compiler/scanner.ts

+1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ namespace ts {
8080
any: SyntaxKind.AnyKeyword,
8181
as: SyntaxKind.AsKeyword,
8282
asserts: SyntaxKind.AssertsKeyword,
83+
assert: SyntaxKind.AssertKeyword,
8384
bigint: SyntaxKind.BigIntKeyword,
8485
boolean: SyntaxKind.BooleanKeyword,
8586
break: SyntaxKind.BreakKeyword,

src/compiler/types.ts

+6-5
Original file line numberDiff line numberDiff line change
@@ -2987,12 +2987,13 @@ namespace ts {
29872987
readonly parent: AssertClause;
29882988
readonly name: AssertionKey;
29892989
readonly value: StringLiteral;
2990-
}
2990+
}
29912991

2992-
export interface AssertClause extends Node {
2992+
export interface AssertClause extends Node {
29932993
readonly kind: SyntaxKind.AssertClause;
29942994
readonly parent: ImportDeclaration | ExportDeclaration
2995-
readonly elements?: NodeArray<AssertEntry>
2995+
readonly elements: NodeArray<AssertEntry>;
2996+
readonly multiLine?: boolean;
29962997
}
29972998

29982999
export interface NamespaceImport extends NamedDeclaration {
@@ -7009,8 +7010,8 @@ namespace ts {
70097010
updateImportDeclaration(node: ImportDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, assertClause: AssertClause | undefined): ImportDeclaration;
70107011
createImportClause(isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause;
70117012
updateImportClause(node: ImportClause, isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause;
7012-
createAssertClause(elements: NodeArray<AssertEntry> | undefined): AssertClause;
7013-
updateAssertClause(node: AssertClause, elements: NodeArray<AssertEntry> | undefined): AssertClause;
7013+
createAssertClause(elements: NodeArray<AssertEntry>, multiLine?: boolean): AssertClause;
7014+
updateAssertClause(node: AssertClause, elements: NodeArray<AssertEntry>, multiLine?: boolean): AssertClause;
70147015
createAssertEntry(name: AssertionKey, value: StringLiteral): AssertEntry;
70157016
updateAssertEntry (node: AssertEntry, name: AssertionKey, value: StringLiteral): AssertEntry;
70167017
createNamespaceImport(name: Identifier): NamespaceImport;

src/compiler/visitorPublic.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -946,13 +946,14 @@ namespace ts {
946946

947947
case SyntaxKind.AssertClause:
948948
return factory.updateAssertClause(<AssertClause>node,
949-
nodesVisitor((node as AssertClause).elements, visitor, isAssertEntry));
949+
nodesVisitor((node as AssertClause).elements, visitor, isAssertEntry),
950+
(node as AssertClause).multiLine);
950951

951952
case SyntaxKind.AssertEntry:
952953
return factory.updateAssertEntry(<AssertEntry>node,
953954
nodeVisitor((<AssertEntry>node).name, visitor, isAssertionKey),
954955
nodeVisitor((<AssertEntry>node).value, visitor, isStringLiteral));
955-
956+
956957
case SyntaxKind.NamespaceImport:
957958
return factory.updateNamespaceImport(<NamespaceImport>node,
958959
nodeVisitor((<NamespaceImport>node).name, visitor, isIdentifier));

src/testRunner/unittests/transform.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ namespace ts {
256256
const exports = [{ name: "x" }];
257257
const exportSpecifiers = exports.map(e => factory.createExportSpecifier(e.name, e.name));
258258
const exportClause = factory.createNamedExports(exportSpecifiers);
259-
const newEd = factory.updateExportDeclaration(ed, ed.decorators, ed.modifiers, ed.isTypeOnly, exportClause, ed.moduleSpecifier);
259+
const newEd = factory.updateExportDeclaration(ed, ed.decorators, ed.modifiers, ed.isTypeOnly, exportClause, ed.moduleSpecifier, ed.assertClause);
260260

261261
return newEd as Node as T;
262262
}
@@ -293,7 +293,8 @@ namespace ts {
293293
/*name*/ undefined,
294294
factory.createNamespaceImport(factory.createIdentifier("i0"))
295295
),
296-
/*moduleSpecifier*/ factory.createStringLiteral("./comp1"));
296+
/*moduleSpecifier*/ factory.createStringLiteral("./comp1"),
297+
/*assertClause*/ undefined);
297298
return factory.updateSourceFile(sf, [importStar]);
298299
}
299300
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
tests/cases/conformance/esnext/importAssertion/1.ts(1,14): error TS2796: Import assertions are not available when targeting lower than esnext.
2+
tests/cases/conformance/esnext/importAssertion/1.ts(2,28): error TS2796: Import assertions are not available when targeting lower than esnext.
3+
tests/cases/conformance/esnext/importAssertion/1.ts(3,28): error TS2796: Import assertions are not available when targeting lower than esnext.
4+
tests/cases/conformance/esnext/importAssertion/2.ts(1,28): error TS2796: Import assertions are not available when targeting lower than esnext.
5+
tests/cases/conformance/esnext/importAssertion/2.ts(2,38): error TS2796: Import assertions are not available when targeting lower than esnext.
6+
tests/cases/conformance/esnext/importAssertion/3.ts(2,11): error TS1324: Dynamic import must have one specifier as an argument.
7+
tests/cases/conformance/esnext/importAssertion/3.ts(3,11): error TS1324: Dynamic import must have one specifier as an argument.
8+
tests/cases/conformance/esnext/importAssertion/3.ts(4,11): error TS1324: Dynamic import must have one specifier as an argument.
9+
tests/cases/conformance/esnext/importAssertion/3.ts(6,11): error TS1324: Dynamic import must have one specifier as an argument.
10+
tests/cases/conformance/esnext/importAssertion/3.ts(7,11): error TS1324: Dynamic import must have one specifier as an argument.
11+
tests/cases/conformance/esnext/importAssertion/3.ts(8,11): error TS1324: Dynamic import must have one specifier as an argument.
12+
13+
14+
==== tests/cases/conformance/esnext/importAssertion/0.ts (0 errors) ====
15+
export const a = 1;
16+
export const b = 2;
17+
18+
==== tests/cases/conformance/esnext/importAssertion/1.ts (3 errors) ====
19+
import './0' assert { type: "json" }
20+
~~~~~~~~~~~~~~~~~~~~~~~
21+
!!! error TS2796: Import assertions are not available when targeting lower than esnext.
22+
import { a, b } from './0' assert { "type": "json" }
23+
~~~~~~~~~~~~~~~~~~~~~~~~~
24+
!!! error TS2796: Import assertions are not available when targeting lower than esnext.
25+
import * as foo from './0' assert { type: "json" }
26+
~~~~~~~~~~~~~~~~~~~~~~~
27+
!!! error TS2796: Import assertions are not available when targeting lower than esnext.
28+
a;
29+
b;
30+
foo.a;
31+
foo.b;
32+
33+
==== tests/cases/conformance/esnext/importAssertion/2.ts (2 errors) ====
34+
import { a, b } from './0' assert {}
35+
~~~~~~~~~
36+
!!! error TS2796: Import assertions are not available when targeting lower than esnext.
37+
import { a as c, b as d } from './0' assert { a: "a", b: "b", c: "c" }
38+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
39+
!!! error TS2796: Import assertions are not available when targeting lower than esnext.
40+
a;
41+
b;
42+
c;
43+
d;
44+
45+
==== tests/cases/conformance/esnext/importAssertion/3.ts (6 errors) ====
46+
const a = import('./0')
47+
const b = import('./0', { type: "json" })
48+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
49+
!!! error TS1324: Dynamic import must have one specifier as an argument.
50+
const c = import('./0', { type: "json", ttype: "typo" })
51+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
52+
!!! error TS1324: Dynamic import must have one specifier as an argument.
53+
const d = import('./0', { })
54+
~~~~~~~~~~~~~~~~~~
55+
!!! error TS1324: Dynamic import must have one specifier as an argument.
56+
declare function foo(): any;
57+
const e = import('./0', foo())
58+
~~~~~~~~~~~~~~~~~~~~
59+
!!! error TS1324: Dynamic import must have one specifier as an argument.
60+
const f = import()
61+
~~~~~~~~
62+
!!! error TS1324: Dynamic import must have one specifier as an argument.
63+
const g = import('./0', {}, {})
64+
~~~~~~~~~~~~~~~~~~~~~
65+
!!! error TS1324: Dynamic import must have one specifier as an argument.
66+

0 commit comments

Comments
 (0)