diff --git a/lib/lib.es2022.object.d.ts b/lib/lib.es2022.object.d.ts index 63460100667e4..2fe2a1917f15e 100644 --- a/lib/lib.es2022.object.d.ts +++ b/lib/lib.es2022.object.d.ts @@ -18,7 +18,7 @@ and limitations under the License. /// -interface Object { +interface ObjectConstructor { /** * Determines whether an object has a property with the specified name. * @param o An object. diff --git a/lib/tsc.js b/lib/tsc.js index 7704b1a2be538..636e39ae1f4ff 100644 --- a/lib/tsc.js +++ b/lib/tsc.js @@ -69,7 +69,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { var ts; (function (ts) { ts.versionMajorMinor = "4.6"; - ts.version = "4.6.2"; + ts.version = "4.6.4"; var NativeCollections; (function (NativeCollections) { var globals = typeof globalThis !== "undefined" ? globalThis : @@ -25262,9 +25262,7 @@ var ts; return; } if (initializer) { - if (token() === 18) { - parseErrorAtCurrentToken(ts.Diagnostics._0_expected, ts.tokenToString(26)); - } + parseErrorAtCurrentToken(ts.Diagnostics._0_expected, ts.tokenToString(26)); return; } parseErrorForMissingSemicolonAfter(name); diff --git a/lib/tsserver.js b/lib/tsserver.js index ff74f351d1bd6..60a159a673ef0 100644 --- a/lib/tsserver.js +++ b/lib/tsserver.js @@ -100,7 +100,7 @@ var ts; // The following is baselined as a literal template type without intervention /** The version of the TypeScript compiler release */ // eslint-disable-next-line @typescript-eslint/no-inferrable-types - ts.version = "4.6.2"; + ts.version = "4.6.4"; /* @internal */ var Comparison; (function (Comparison) { @@ -31354,18 +31354,8 @@ var ts; if (tryParseSemicolon()) { return; } - // If an initializer was parsed but there is still an error in finding the next semicolon, - // we generally know there was an error already reported in the initializer... - // class Example { a = new Map([), ) } - // ~ if (initializer) { - // ...unless we've found the start of a block after a property declaration, in which - // case we can know that regardless of the initializer we should complain on the block. - // class Example { a = 0 {} } - // ~ - if (token() === 18 /* OpenBraceToken */) { - parseErrorAtCurrentToken(ts.Diagnostics._0_expected, ts.tokenToString(26 /* SemicolonToken */)); - } + parseErrorAtCurrentToken(ts.Diagnostics._0_expected, ts.tokenToString(26 /* SemicolonToken */)); return; } parseErrorForMissingSemicolonAfter(name); @@ -124974,12 +124964,8 @@ var ts; } } ts.findNextToken = findNextToken; - /** - * Finds the rightmost token satisfying `token.end <= position`, - * excluding `JsxText` tokens containing only whitespace. - */ function findPrecedingToken(position, sourceFile, startNode, excludeJsdoc) { - var result = find(startNode || sourceFile); + var result = find((startNode || sourceFile)); ts.Debug.assert(!(result && isWhiteSpaceOnlyJsxText(result))); return result; function find(n) { @@ -140014,6 +140000,41 @@ var ts; if (ts.scanner.getToken() === 1 /* EndOfFileToken */) { break; } + if (ts.scanner.getToken() === 15 /* TemplateHead */) { + var stack = [ts.scanner.getToken()]; + var token = ts.scanner.scan(); + loop: while (ts.length(stack)) { + switch (token) { + case 1 /* EndOfFileToken */: + break loop; + case 100 /* ImportKeyword */: + tryConsumeImport(); + break; + case 15 /* TemplateHead */: + stack.push(token); + break; + case 18 /* OpenBraceToken */: + if (ts.length(stack)) { + stack.push(token); + } + break; + case 19 /* CloseBraceToken */: + if (ts.length(stack)) { + if (ts.lastOrUndefined(stack) === 15 /* TemplateHead */) { + if (ts.scanner.reScanTemplateToken(/* isTaggedTemplate */ false) === 17 /* TemplateTail */) { + stack.pop(); + } + } + else { + stack.pop(); + } + } + break; + } + token = ts.scanner.scan(); + } + nextToken(); + } // check if at least one of alternative have moved scanner forward if (tryConsumeDeclare() || tryConsumeImport() || @@ -144036,6 +144057,7 @@ var ts; return formatting.getFormattingScanner(sourceFile.text, sourceFile.languageVariant, getScanStartPosition(enclosingNode, originalRange, sourceFile), originalRange.end, function (scanner) { return formatSpanWorker(originalRange, enclosingNode, formatting.SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, formatContext.options), getOwnOrInheritedDelta(enclosingNode, formatContext.options, sourceFile), scanner, formatContext, requestKind, prepareRangeContainsErrorFunction(sourceFile.parseDiagnostics, originalRange), sourceFile); }); } function formatSpanWorker(originalRange, enclosingNode, initialIndentation, delta, formattingScanner, _a, requestKind, rangeContainsError, sourceFile) { + var _b; var options = _a.options, getRules = _a.getRules, host = _a.host; // formatting context is used by rules provider var formattingContext = new formatting.FormattingContext(sourceFile, requestKind, options); @@ -144067,11 +144089,12 @@ var ts; } } if (previousRange && formattingScanner.getStartPos() >= originalRange.end) { - var token = formattingScanner.isOnEOF() ? formattingScanner.readEOFTokenRange() : + var tokenInfo = formattingScanner.isOnEOF() ? formattingScanner.readEOFTokenRange() : formattingScanner.isOnToken() ? formattingScanner.readTokenInfo(enclosingNode).token : undefined; - if (token) { - processPair(token, sourceFile.getLineAndCharacterOfPosition(token.pos).line, enclosingNode, previousRange, previousRangeStartLine, previousParent, enclosingNode, + if (tokenInfo) { + var parent = ((_b = ts.findPrecedingToken(tokenInfo.end, sourceFile, enclosingNode)) === null || _b === void 0 ? void 0 : _b.parent) || previousParent; + processPair(tokenInfo, sourceFile.getLineAndCharacterOfPosition(tokenInfo.pos).line, parent, previousRange, previousRangeStartLine, previousParent, parent, /*dynamicIndentation*/ undefined); } } diff --git a/lib/tsserverlibrary.js b/lib/tsserverlibrary.js index 9290a3661080e..fcb589891a4d5 100644 --- a/lib/tsserverlibrary.js +++ b/lib/tsserverlibrary.js @@ -294,7 +294,7 @@ var ts; // The following is baselined as a literal template type without intervention /** The version of the TypeScript compiler release */ // eslint-disable-next-line @typescript-eslint/no-inferrable-types - ts.version = "4.6.2"; + ts.version = "4.6.4"; /* @internal */ var Comparison; (function (Comparison) { @@ -31548,18 +31548,8 @@ var ts; if (tryParseSemicolon()) { return; } - // If an initializer was parsed but there is still an error in finding the next semicolon, - // we generally know there was an error already reported in the initializer... - // class Example { a = new Map([), ) } - // ~ if (initializer) { - // ...unless we've found the start of a block after a property declaration, in which - // case we can know that regardless of the initializer we should complain on the block. - // class Example { a = 0 {} } - // ~ - if (token() === 18 /* OpenBraceToken */) { - parseErrorAtCurrentToken(ts.Diagnostics._0_expected, ts.tokenToString(26 /* SemicolonToken */)); - } + parseErrorAtCurrentToken(ts.Diagnostics._0_expected, ts.tokenToString(26 /* SemicolonToken */)); return; } parseErrorForMissingSemicolonAfter(name); @@ -125585,12 +125575,8 @@ var ts; } } ts.findNextToken = findNextToken; - /** - * Finds the rightmost token satisfying `token.end <= position`, - * excluding `JsxText` tokens containing only whitespace. - */ function findPrecedingToken(position, sourceFile, startNode, excludeJsdoc) { - var result = find(startNode || sourceFile); + var result = find((startNode || sourceFile)); ts.Debug.assert(!(result && isWhiteSpaceOnlyJsxText(result))); return result; function find(n) { @@ -140625,6 +140611,41 @@ var ts; if (ts.scanner.getToken() === 1 /* EndOfFileToken */) { break; } + if (ts.scanner.getToken() === 15 /* TemplateHead */) { + var stack = [ts.scanner.getToken()]; + var token = ts.scanner.scan(); + loop: while (ts.length(stack)) { + switch (token) { + case 1 /* EndOfFileToken */: + break loop; + case 100 /* ImportKeyword */: + tryConsumeImport(); + break; + case 15 /* TemplateHead */: + stack.push(token); + break; + case 18 /* OpenBraceToken */: + if (ts.length(stack)) { + stack.push(token); + } + break; + case 19 /* CloseBraceToken */: + if (ts.length(stack)) { + if (ts.lastOrUndefined(stack) === 15 /* TemplateHead */) { + if (ts.scanner.reScanTemplateToken(/* isTaggedTemplate */ false) === 17 /* TemplateTail */) { + stack.pop(); + } + } + else { + stack.pop(); + } + } + break; + } + token = ts.scanner.scan(); + } + nextToken(); + } // check if at least one of alternative have moved scanner forward if (tryConsumeDeclare() || tryConsumeImport() || @@ -144647,6 +144668,7 @@ var ts; return formatting.getFormattingScanner(sourceFile.text, sourceFile.languageVariant, getScanStartPosition(enclosingNode, originalRange, sourceFile), originalRange.end, function (scanner) { return formatSpanWorker(originalRange, enclosingNode, formatting.SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, formatContext.options), getOwnOrInheritedDelta(enclosingNode, formatContext.options, sourceFile), scanner, formatContext, requestKind, prepareRangeContainsErrorFunction(sourceFile.parseDiagnostics, originalRange), sourceFile); }); } function formatSpanWorker(originalRange, enclosingNode, initialIndentation, delta, formattingScanner, _a, requestKind, rangeContainsError, sourceFile) { + var _b; var options = _a.options, getRules = _a.getRules, host = _a.host; // formatting context is used by rules provider var formattingContext = new formatting.FormattingContext(sourceFile, requestKind, options); @@ -144678,11 +144700,12 @@ var ts; } } if (previousRange && formattingScanner.getStartPos() >= originalRange.end) { - var token = formattingScanner.isOnEOF() ? formattingScanner.readEOFTokenRange() : + var tokenInfo = formattingScanner.isOnEOF() ? formattingScanner.readEOFTokenRange() : formattingScanner.isOnToken() ? formattingScanner.readTokenInfo(enclosingNode).token : undefined; - if (token) { - processPair(token, sourceFile.getLineAndCharacterOfPosition(token.pos).line, enclosingNode, previousRange, previousRangeStartLine, previousParent, enclosingNode, + if (tokenInfo) { + var parent = ((_b = ts.findPrecedingToken(tokenInfo.end, sourceFile, enclosingNode)) === null || _b === void 0 ? void 0 : _b.parent) || previousParent; + processPair(tokenInfo, sourceFile.getLineAndCharacterOfPosition(tokenInfo.pos).line, parent, previousRange, previousRangeStartLine, previousParent, parent, /*dynamicIndentation*/ undefined); } } diff --git a/lib/typescript.js b/lib/typescript.js index 89cc0ba3ffb18..3be91a8fa92f4 100644 --- a/lib/typescript.js +++ b/lib/typescript.js @@ -294,7 +294,7 @@ var ts; // The following is baselined as a literal template type without intervention /** The version of the TypeScript compiler release */ // eslint-disable-next-line @typescript-eslint/no-inferrable-types - ts.version = "4.6.2"; + ts.version = "4.6.4"; /* @internal */ var Comparison; (function (Comparison) { @@ -31548,18 +31548,8 @@ var ts; if (tryParseSemicolon()) { return; } - // If an initializer was parsed but there is still an error in finding the next semicolon, - // we generally know there was an error already reported in the initializer... - // class Example { a = new Map([), ) } - // ~ if (initializer) { - // ...unless we've found the start of a block after a property declaration, in which - // case we can know that regardless of the initializer we should complain on the block. - // class Example { a = 0 {} } - // ~ - if (token() === 18 /* OpenBraceToken */) { - parseErrorAtCurrentToken(ts.Diagnostics._0_expected, ts.tokenToString(26 /* SemicolonToken */)); - } + parseErrorAtCurrentToken(ts.Diagnostics._0_expected, ts.tokenToString(26 /* SemicolonToken */)); return; } parseErrorForMissingSemicolonAfter(name); @@ -125585,12 +125575,8 @@ var ts; } } ts.findNextToken = findNextToken; - /** - * Finds the rightmost token satisfying `token.end <= position`, - * excluding `JsxText` tokens containing only whitespace. - */ function findPrecedingToken(position, sourceFile, startNode, excludeJsdoc) { - var result = find(startNode || sourceFile); + var result = find((startNode || sourceFile)); ts.Debug.assert(!(result && isWhiteSpaceOnlyJsxText(result))); return result; function find(n) { @@ -140625,6 +140611,41 @@ var ts; if (ts.scanner.getToken() === 1 /* EndOfFileToken */) { break; } + if (ts.scanner.getToken() === 15 /* TemplateHead */) { + var stack = [ts.scanner.getToken()]; + var token = ts.scanner.scan(); + loop: while (ts.length(stack)) { + switch (token) { + case 1 /* EndOfFileToken */: + break loop; + case 100 /* ImportKeyword */: + tryConsumeImport(); + break; + case 15 /* TemplateHead */: + stack.push(token); + break; + case 18 /* OpenBraceToken */: + if (ts.length(stack)) { + stack.push(token); + } + break; + case 19 /* CloseBraceToken */: + if (ts.length(stack)) { + if (ts.lastOrUndefined(stack) === 15 /* TemplateHead */) { + if (ts.scanner.reScanTemplateToken(/* isTaggedTemplate */ false) === 17 /* TemplateTail */) { + stack.pop(); + } + } + else { + stack.pop(); + } + } + break; + } + token = ts.scanner.scan(); + } + nextToken(); + } // check if at least one of alternative have moved scanner forward if (tryConsumeDeclare() || tryConsumeImport() || @@ -144647,6 +144668,7 @@ var ts; return formatting.getFormattingScanner(sourceFile.text, sourceFile.languageVariant, getScanStartPosition(enclosingNode, originalRange, sourceFile), originalRange.end, function (scanner) { return formatSpanWorker(originalRange, enclosingNode, formatting.SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, formatContext.options), getOwnOrInheritedDelta(enclosingNode, formatContext.options, sourceFile), scanner, formatContext, requestKind, prepareRangeContainsErrorFunction(sourceFile.parseDiagnostics, originalRange), sourceFile); }); } function formatSpanWorker(originalRange, enclosingNode, initialIndentation, delta, formattingScanner, _a, requestKind, rangeContainsError, sourceFile) { + var _b; var options = _a.options, getRules = _a.getRules, host = _a.host; // formatting context is used by rules provider var formattingContext = new formatting.FormattingContext(sourceFile, requestKind, options); @@ -144678,11 +144700,12 @@ var ts; } } if (previousRange && formattingScanner.getStartPos() >= originalRange.end) { - var token = formattingScanner.isOnEOF() ? formattingScanner.readEOFTokenRange() : + var tokenInfo = formattingScanner.isOnEOF() ? formattingScanner.readEOFTokenRange() : formattingScanner.isOnToken() ? formattingScanner.readTokenInfo(enclosingNode).token : undefined; - if (token) { - processPair(token, sourceFile.getLineAndCharacterOfPosition(token.pos).line, enclosingNode, previousRange, previousRangeStartLine, previousParent, enclosingNode, + if (tokenInfo) { + var parent = ((_b = ts.findPrecedingToken(tokenInfo.end, sourceFile, enclosingNode)) === null || _b === void 0 ? void 0 : _b.parent) || previousParent; + processPair(tokenInfo, sourceFile.getLineAndCharacterOfPosition(tokenInfo.pos).line, parent, previousRange, previousRangeStartLine, previousParent, parent, /*dynamicIndentation*/ undefined); } } diff --git a/lib/typescriptServices.js b/lib/typescriptServices.js index d1d97fe03d60c..e958d4e4d3a2c 100644 --- a/lib/typescriptServices.js +++ b/lib/typescriptServices.js @@ -294,7 +294,7 @@ var ts; // The following is baselined as a literal template type without intervention /** The version of the TypeScript compiler release */ // eslint-disable-next-line @typescript-eslint/no-inferrable-types - ts.version = "4.6.2"; + ts.version = "4.6.4"; /* @internal */ var Comparison; (function (Comparison) { @@ -31548,18 +31548,8 @@ var ts; if (tryParseSemicolon()) { return; } - // If an initializer was parsed but there is still an error in finding the next semicolon, - // we generally know there was an error already reported in the initializer... - // class Example { a = new Map([), ) } - // ~ if (initializer) { - // ...unless we've found the start of a block after a property declaration, in which - // case we can know that regardless of the initializer we should complain on the block. - // class Example { a = 0 {} } - // ~ - if (token() === 18 /* OpenBraceToken */) { - parseErrorAtCurrentToken(ts.Diagnostics._0_expected, ts.tokenToString(26 /* SemicolonToken */)); - } + parseErrorAtCurrentToken(ts.Diagnostics._0_expected, ts.tokenToString(26 /* SemicolonToken */)); return; } parseErrorForMissingSemicolonAfter(name); @@ -125585,12 +125575,8 @@ var ts; } } ts.findNextToken = findNextToken; - /** - * Finds the rightmost token satisfying `token.end <= position`, - * excluding `JsxText` tokens containing only whitespace. - */ function findPrecedingToken(position, sourceFile, startNode, excludeJsdoc) { - var result = find(startNode || sourceFile); + var result = find((startNode || sourceFile)); ts.Debug.assert(!(result && isWhiteSpaceOnlyJsxText(result))); return result; function find(n) { @@ -140625,6 +140611,41 @@ var ts; if (ts.scanner.getToken() === 1 /* EndOfFileToken */) { break; } + if (ts.scanner.getToken() === 15 /* TemplateHead */) { + var stack = [ts.scanner.getToken()]; + var token = ts.scanner.scan(); + loop: while (ts.length(stack)) { + switch (token) { + case 1 /* EndOfFileToken */: + break loop; + case 100 /* ImportKeyword */: + tryConsumeImport(); + break; + case 15 /* TemplateHead */: + stack.push(token); + break; + case 18 /* OpenBraceToken */: + if (ts.length(stack)) { + stack.push(token); + } + break; + case 19 /* CloseBraceToken */: + if (ts.length(stack)) { + if (ts.lastOrUndefined(stack) === 15 /* TemplateHead */) { + if (ts.scanner.reScanTemplateToken(/* isTaggedTemplate */ false) === 17 /* TemplateTail */) { + stack.pop(); + } + } + else { + stack.pop(); + } + } + break; + } + token = ts.scanner.scan(); + } + nextToken(); + } // check if at least one of alternative have moved scanner forward if (tryConsumeDeclare() || tryConsumeImport() || @@ -144647,6 +144668,7 @@ var ts; return formatting.getFormattingScanner(sourceFile.text, sourceFile.languageVariant, getScanStartPosition(enclosingNode, originalRange, sourceFile), originalRange.end, function (scanner) { return formatSpanWorker(originalRange, enclosingNode, formatting.SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, formatContext.options), getOwnOrInheritedDelta(enclosingNode, formatContext.options, sourceFile), scanner, formatContext, requestKind, prepareRangeContainsErrorFunction(sourceFile.parseDiagnostics, originalRange), sourceFile); }); } function formatSpanWorker(originalRange, enclosingNode, initialIndentation, delta, formattingScanner, _a, requestKind, rangeContainsError, sourceFile) { + var _b; var options = _a.options, getRules = _a.getRules, host = _a.host; // formatting context is used by rules provider var formattingContext = new formatting.FormattingContext(sourceFile, requestKind, options); @@ -144678,11 +144700,12 @@ var ts; } } if (previousRange && formattingScanner.getStartPos() >= originalRange.end) { - var token = formattingScanner.isOnEOF() ? formattingScanner.readEOFTokenRange() : + var tokenInfo = formattingScanner.isOnEOF() ? formattingScanner.readEOFTokenRange() : formattingScanner.isOnToken() ? formattingScanner.readTokenInfo(enclosingNode).token : undefined; - if (token) { - processPair(token, sourceFile.getLineAndCharacterOfPosition(token.pos).line, enclosingNode, previousRange, previousRangeStartLine, previousParent, enclosingNode, + if (tokenInfo) { + var parent = ((_b = ts.findPrecedingToken(tokenInfo.end, sourceFile, enclosingNode)) === null || _b === void 0 ? void 0 : _b.parent) || previousParent; + processPair(tokenInfo, sourceFile.getLineAndCharacterOfPosition(tokenInfo.pos).line, parent, previousRange, previousRangeStartLine, previousParent, parent, /*dynamicIndentation*/ undefined); } } diff --git a/lib/typingsInstaller.js b/lib/typingsInstaller.js index 67aa6f7336aa4..715445fffe2bd 100644 --- a/lib/typingsInstaller.js +++ b/lib/typingsInstaller.js @@ -89,7 +89,7 @@ var ts; // The following is baselined as a literal template type without intervention /** The version of the TypeScript compiler release */ // eslint-disable-next-line @typescript-eslint/no-inferrable-types - ts.version = "4.6.2"; + ts.version = "4.6.4"; /* @internal */ var Comparison; (function (Comparison) { @@ -31343,18 +31343,8 @@ var ts; if (tryParseSemicolon()) { return; } - // If an initializer was parsed but there is still an error in finding the next semicolon, - // we generally know there was an error already reported in the initializer... - // class Example { a = new Map([), ) } - // ~ if (initializer) { - // ...unless we've found the start of a block after a property declaration, in which - // case we can know that regardless of the initializer we should complain on the block. - // class Example { a = 0 {} } - // ~ - if (token() === 18 /* OpenBraceToken */) { - parseErrorAtCurrentToken(ts.Diagnostics._0_expected, ts.tokenToString(26 /* SemicolonToken */)); - } + parseErrorAtCurrentToken(ts.Diagnostics._0_expected, ts.tokenToString(26 /* SemicolonToken */)); return; } parseErrorForMissingSemicolonAfter(name); diff --git a/package.json b/package.json index 709da71b59b40..30243b6a35587 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "typescript", "author": "Microsoft Corp.", "homepage": "https://www.typescriptlang.org/", - "version": "4.6.2", + "version": "4.6.4", "license": "Apache-2.0", "description": "TypeScript is a language for application scale JavaScript development", "keywords": [ diff --git a/src/compiler/corePublic.ts b/src/compiler/corePublic.ts index 2e0d8a0eeff28..e170ec832229e 100644 --- a/src/compiler/corePublic.ts +++ b/src/compiler/corePublic.ts @@ -5,7 +5,7 @@ namespace ts { // The following is baselined as a literal template type without intervention /** The version of the TypeScript compiler release */ // eslint-disable-next-line @typescript-eslint/no-inferrable-types - export const version = "4.6.2" as string; + export const version = "4.6.4" as string; /** * Type of objects whose values are all of the same type. diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index c796e78d45190..0dea81baae43b 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1680,19 +1680,8 @@ namespace ts { return; } - // If an initializer was parsed but there is still an error in finding the next semicolon, - // we generally know there was an error already reported in the initializer... - // class Example { a = new Map([), ) } - // ~ if (initializer) { - // ...unless we've found the start of a block after a property declaration, in which - // case we can know that regardless of the initializer we should complain on the block. - // class Example { a = 0 {} } - // ~ - if (token() === SyntaxKind.OpenBraceToken) { - parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.SemicolonToken)); - } - + parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.SemicolonToken)); return; } diff --git a/src/lib/es2022.object.d.ts b/src/lib/es2022.object.d.ts index 764610213b6ac..7325ef3c343e2 100644 --- a/src/lib/es2022.object.d.ts +++ b/src/lib/es2022.object.d.ts @@ -1,4 +1,4 @@ -interface Object { +interface ObjectConstructor { /** * Determines whether an object has a property with the specified name. * @param o An object. diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index 3b68b44063e62..5a9948cd35f72 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -439,20 +439,21 @@ namespace ts.formatting { } if (previousRange! && formattingScanner.getStartPos() >= originalRange.end) { - const token = + const tokenInfo = formattingScanner.isOnEOF() ? formattingScanner.readEOFTokenRange() : formattingScanner.isOnToken() ? formattingScanner.readTokenInfo(enclosingNode).token : undefined; - if (token) { + if (tokenInfo) { + const parent = findPrecedingToken(tokenInfo.end, sourceFile, enclosingNode)?.parent || previousParent!; processPair( - token, - sourceFile.getLineAndCharacterOfPosition(token.pos).line, - enclosingNode, + tokenInfo, + sourceFile.getLineAndCharacterOfPosition(tokenInfo.pos).line, + parent, previousRange, previousRangeStartLine!, previousParent!, - enclosingNode, + parent, /*dynamicIndentation*/ undefined); } } diff --git a/src/services/preProcess.ts b/src/services/preProcess.ts index 41845616bbe4b..d5c384e9161cc 100644 --- a/src/services/preProcess.ts +++ b/src/services/preProcess.ts @@ -345,6 +345,42 @@ namespace ts { break; } + if (scanner.getToken() === SyntaxKind.TemplateHead) { + const stack = [scanner.getToken()]; + let token = scanner.scan(); + loop: while (length(stack)) { + switch (token) { + case SyntaxKind.EndOfFileToken: + break loop; + case SyntaxKind.ImportKeyword: + tryConsumeImport(); + break; + case SyntaxKind.TemplateHead: + stack.push(token); + break; + case SyntaxKind.OpenBraceToken: + if (length(stack)) { + stack.push(token); + } + break; + case SyntaxKind.CloseBraceToken: + if (length(stack)) { + if (lastOrUndefined(stack) === SyntaxKind.TemplateHead) { + if (scanner.reScanTemplateToken(/* isTaggedTemplate */ false) === SyntaxKind.TemplateTail) { + stack.pop(); + } + } + else { + stack.pop(); + } + } + break; + } + token = scanner.scan(); + } + nextToken(); + } + // check if at least one of alternative have moved scanner forward if (tryConsumeDeclare() || tryConsumeImport() || diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 016eb35227eda..e0465bce94eef 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1256,8 +1256,10 @@ namespace ts { * Finds the rightmost token satisfying `token.end <= position`, * excluding `JsxText` tokens containing only whitespace. */ - export function findPrecedingToken(position: number, sourceFile: SourceFile, startNode?: Node, excludeJsdoc?: boolean): Node | undefined { - const result = find(startNode || sourceFile); + export function findPrecedingToken(position: number, sourceFile: SourceFileLike, startNode: Node, excludeJsdoc?: boolean): Node | undefined; + export function findPrecedingToken(position: number, sourceFile: SourceFile, startNode?: Node, excludeJsdoc?: boolean): Node | undefined; + export function findPrecedingToken(position: number, sourceFile: SourceFileLike, startNode?: Node, excludeJsdoc?: boolean): Node | undefined { + const result = find((startNode || sourceFile) as Node); Debug.assert(!(result && isWhiteSpaceOnlyJsxText(result))); return result; @@ -1322,7 +1324,7 @@ namespace ts { return isToken(n) && !isWhiteSpaceOnlyJsxText(n); } - function findRightmostToken(n: Node, sourceFile: SourceFile): Node | undefined { + function findRightmostToken(n: Node, sourceFile: SourceFileLike): Node | undefined { if (isNonWhitespaceToken(n)) { return n; } @@ -1339,7 +1341,7 @@ namespace ts { /** * Finds the rightmost child to the left of `children[exclusiveStartPosition]` which is a non-all-whitespace token or has constituent tokens. */ - function findRightmostChildNodeWithTokens(children: Node[], exclusiveStartPosition: number, sourceFile: SourceFile, parentKind: SyntaxKind): Node | undefined { + function findRightmostChildNodeWithTokens(children: Node[], exclusiveStartPosition: number, sourceFile: SourceFileLike, parentKind: SyntaxKind): Node | undefined { for (let i = exclusiveStartPosition - 1; i >= 0; i--) { const child = children[i]; diff --git a/src/testRunner/unittests/services/preProcessFile.ts b/src/testRunner/unittests/services/preProcessFile.ts index fb7a7e62649d4..a6369d6e4d4cf 100644 --- a/src/testRunner/unittests/services/preProcessFile.ts +++ b/src/testRunner/unittests/services/preProcessFile.ts @@ -176,6 +176,177 @@ describe("unittests:: services:: PreProcessFile:", () => { }); }); + it("Correctly ignore commented imports following template expression", () => { + /* eslint-disable no-template-curly-in-string */ + test("/**" + "\n" + + " * Before" + "\n" + + " * ```" + "\n" + + " * import * as a from \"a\";" + "\n" + + " * ```" + "\n" + + " */" + "\n" + + "type Foo = `${string}`;" + "\n" + + "/**" + "\n" + + " * After" + "\n" + + " * ```" + "\n" + + " * import { B } from \"b\";" + "\n" + + " * import * as c from \"c\";" + "\n" + + " * ```" + "\n" + + " */", + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [], + ambientExternalModules: undefined, + isLibFile: false + }); + /* eslint-enable no-template-curly-in-string */ + }); + + it("Correctly returns imports after a template expression", () => { + /* eslint-disable no-template-curly-in-string */ + test("`${foo}`; import \"./foo\";", + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "./foo", pos: 17, end: 22 } + ], + ambientExternalModules: undefined, + isLibFile: false + }); + /* eslint-enable no-template-curly-in-string */ + }); + + it("Correctly returns dynamic imports from template expression", () => { + /* eslint-disable no-template-curly-in-string */ + test("`${(
Text `` ${} text {} " + "\n" + + "${import(\"a\")} {import(\"b\")} " + "\n" + + "${/* A comment */} ${/* import(\"ignored\") */}
)}`", + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "a", pos: 39, end: 40 }, + { fileName: "b", pos: 53, end: 54 } + ], + ambientExternalModules: undefined, + isLibFile: false + }); + /* eslint-enable no-template-curly-in-string */ + }); + + it("Correctly returns dynamic imports from nested template expression", () => { + /* eslint-disable no-template-curly-in-string */ + test("`${foo(`${bar(`${import(\"a\")} ${import(\"b\")}`, `${baz(`${import(\"c\") ${import(\"d\")}`)}`)}`)}`", + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "a", pos: 24, end: 25 }, + { fileName: "b", pos: 39, end: 40 }, + { fileName: "c", pos: 64, end: 65 }, + { fileName: "d", pos: 78, end: 79 }, + ], + ambientExternalModules: undefined, + isLibFile: false + }); + /* eslint-enable no-template-curly-in-string */ + }); + + it("Correctly returns dynamic imports from tagged template expression", () => { + /* eslint-disable no-template-curly-in-string */ + test("foo`${ fn({ a: 100 }, import(\"a\"), `${import(\"b\")}`, import(\"c\"), `${import(\"d\")} foo`, import(\"e\")) }`", + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "a", pos: 29, end: 30 }, + { fileName: "b", pos: 45, end: 46 }, + { fileName: "c", pos: 60, end: 61 }, + { fileName: "d", pos: 76, end: 77 }, + { fileName: "e", pos: 95, end: 96 }, + ], + ambientExternalModules: undefined, + isLibFile: false + }); + /* eslint-enable no-template-curly-in-string */ + }); + + it("Correctly returns dynamic imports from template expression and imports following it", () => { + /* eslint-disable no-template-curly-in-string */ + test("const x = `hello ${await import(\"a\").default}`;" + "\n\n" + + "import { y } from \"b\";", + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "a", pos: 32, end: 33 }, + { fileName: "b", pos: 67, end: 68 }, + ], + ambientExternalModules: undefined, + isLibFile: false + }); + /* eslint-enable no-template-curly-in-string */ + }); + + it("Correctly returns dynamic imports from template expressions and other imports", () => { + /* eslint-disable no-template-curly-in-string */ + test("const x = `x ${await import(\"a\").default}`;" + "\n\n" + + "import { y } from \"b\";" + "\n" + + "const y = `y ${import(\"c\")}`;" + "\n\n" + + "import { d } from \"d\";", + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "a", pos: 28, end: 29 }, + { fileName: "b", pos: 63, end: 64 }, + { fileName: "c", pos: 90, end: 91 }, + { fileName: "d", pos: 117, end: 118 }, + ], + ambientExternalModules: undefined, + isLibFile: false + }); + /* eslint-enable no-template-curly-in-string */ + }); + + it("Correctly returns empty importedFiles with incorrect template expression", () => { + /* eslint-disable no-template-curly-in-string */ + test("const foo = `${", + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [], + ambientExternalModules: undefined, + isLibFile: false + }); + /* eslint-enable no-template-curly-in-string */ + }); + it("Correctly return ES6 exports", () => { test("export * from \"m1\";" + "\n" + "export {a} from \"m2\";" + "\n" + diff --git a/tests/baselines/reference/esNextWeakRefs_IterableWeakMap.symbols b/tests/baselines/reference/esNextWeakRefs_IterableWeakMap.symbols index cf1ed59e66d6e..be0559bfe5251 100644 --- a/tests/baselines/reference/esNextWeakRefs_IterableWeakMap.symbols +++ b/tests/baselines/reference/esNextWeakRefs_IterableWeakMap.symbols @@ -297,7 +297,7 @@ export class IterableWeakMap implements WeakMap { Object.defineProperties(IterableWeakMap.prototype, { >Object.defineProperties : Symbol(ObjectConstructor.defineProperties, Decl(lib.es5.d.ts, --, --)) ->Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2022.object.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) >defineProperties : Symbol(ObjectConstructor.defineProperties, Decl(lib.es5.d.ts, --, --)) >IterableWeakMap.prototype : Symbol(IterableWeakMap.prototype) >IterableWeakMap : Symbol(IterableWeakMap, Decl(esNextWeakRefs_IterableWeakMap.ts, 6, 2)) @@ -322,7 +322,7 @@ Object.defineProperties(IterableWeakMap.prototype, { >value : Symbol(value, Decl(esNextWeakRefs_IterableWeakMap.ts, 89, 23)) >Object.getOwnPropertyDescriptor( IterableWeakMap.prototype, "entries", )!.value : Symbol(PropertyDescriptor.value, Decl(lib.es5.d.ts, --, --)) >Object.getOwnPropertyDescriptor : Symbol(ObjectConstructor.getOwnPropertyDescriptor, Decl(lib.es5.d.ts, --, --)) ->Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2022.object.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) >getOwnPropertyDescriptor : Symbol(ObjectConstructor.getOwnPropertyDescriptor, Decl(lib.es5.d.ts, --, --)) IterableWeakMap.prototype, diff --git a/tests/baselines/reference/inferenceOptionalPropertiesToIndexSignatures.symbols b/tests/baselines/reference/inferenceOptionalPropertiesToIndexSignatures.symbols index 72d4478539d77..9874e516a2b75 100644 --- a/tests/baselines/reference/inferenceOptionalPropertiesToIndexSignatures.symbols +++ b/tests/baselines/reference/inferenceOptionalPropertiesToIndexSignatures.symbols @@ -72,7 +72,7 @@ const query = Object.entries(obj).map( >Object.entries(obj).map( ([k, v]) => `${k}=${encodeURIComponent(v)}`).join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --)) >Object.entries(obj).map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) >Object.entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) ->Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2022.object.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) >entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) >obj : Symbol(obj, Decl(inferenceOptionalPropertiesToIndexSignatures.ts, 16, 5)) >map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) diff --git a/tests/baselines/reference/parser0_004152.errors.txt b/tests/baselines/reference/parser0_004152.errors.txt index a1790a5f7305c..e0fc3f48e0843 100644 --- a/tests/baselines/reference/parser0_004152.errors.txt +++ b/tests/baselines/reference/parser0_004152.errors.txt @@ -1,6 +1,6 @@ tests/cases/conformance/parser/ecmascript5/Fuzz/parser0_004152.ts(2,28): error TS2304: Cannot find name 'DisplayPosition'. tests/cases/conformance/parser/ecmascript5/Fuzz/parser0_004152.ts(2,45): error TS1137: Expression or comma expected. -tests/cases/conformance/parser/ecmascript5/Fuzz/parser0_004152.ts(2,46): error TS1068: Unexpected token. A constructor, method, accessor, or property was expected. +tests/cases/conformance/parser/ecmascript5/Fuzz/parser0_004152.ts(2,46): error TS1005: ';' expected. tests/cases/conformance/parser/ecmascript5/Fuzz/parser0_004152.ts(2,49): error TS1005: ';' expected. tests/cases/conformance/parser/ecmascript5/Fuzz/parser0_004152.ts(2,51): error TS2300: Duplicate identifier '3'. tests/cases/conformance/parser/ecmascript5/Fuzz/parser0_004152.ts(2,52): error TS1005: ';' expected. @@ -41,7 +41,7 @@ tests/cases/conformance/parser/ecmascript5/Fuzz/parser0_004152.ts(3,25): error T ~ !!! error TS1137: Expression or comma expected. ~ -!!! error TS1068: Unexpected token. A constructor, method, accessor, or property was expected. +!!! error TS1005: ';' expected. ~ !!! error TS1005: ';' expected. ~ diff --git a/tests/baselines/reference/unionTypeInference.symbols b/tests/baselines/reference/unionTypeInference.symbols index a4a24b15ebfcc..11fdc52396485 100644 --- a/tests/baselines/reference/unionTypeInference.symbols +++ b/tests/baselines/reference/unionTypeInference.symbols @@ -230,7 +230,7 @@ async function fun(deepPromised: DeepPromised) { for (const value of Object.values(deepPromisedWithIndexer)) { >value : Symbol(value, Decl(unionTypeInference.ts, 62, 14)) >Object.values : Symbol(ObjectConstructor.values, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) ->Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2022.object.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) >values : Symbol(ObjectConstructor.values, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) >deepPromisedWithIndexer : Symbol(deepPromisedWithIndexer, Decl(unionTypeInference.ts, 61, 9)) diff --git a/tests/cases/fourslash/formatOnTypeOpenCurlyWithBraceCompletion.ts b/tests/cases/fourslash/formatOnTypeOpenCurlyWithBraceCompletion.ts new file mode 100644 index 0000000000000..b303b1ea62d6d --- /dev/null +++ b/tests/cases/fourslash/formatOnTypeOpenCurlyWithBraceCompletion.ts @@ -0,0 +1,12 @@ +/// + +//// if (foo) { +//// if (bar) {/**/} +//// } + +goTo.marker(""); +format.onType("", "{"); +verify.currentFileContentIs( +`if (foo) { + if (bar) { } +}`); diff --git a/tests/cases/fourslash/parserCorruptionAfterMapInClass.ts b/tests/cases/fourslash/parserCorruptionAfterMapInClass.ts new file mode 100644 index 0000000000000..65bc6c5b1ad70 --- /dev/null +++ b/tests/cases/fourslash/parserCorruptionAfterMapInClass.ts @@ -0,0 +1,17 @@ +/// + +// @target: esnext +// @lib: es2015 +// @strict: true + +//// class C { +//// map = new Set/*$*/ +//// +//// foo() { +//// +//// } +//// } + +goTo.marker('$'); +edit.insert('()'); +verify.getSyntacticDiagnostics([]);