From 7bd89cf87388d3da2a20359914384c61d9e62675 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 16 Nov 2017 13:16:10 -0800 Subject: [PATCH 1/2] Allow curly around `@type` jsdoc to be optional --- src/compiler/parser.ts | 18 +++++++++--------- src/compiler/scanner.ts | 11 +++++++++++ .../jsdocTypedefMissingType.errors.txt | 5 +---- .../reference/jsdocTypedefMissingType.types | 4 ++-- tests/baselines/reference/malformedTags.types | 2 +- .../user/chrome-devtools-frontend.log | 12 +----------- 6 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index db2c09e34b899..01ae8d9ad5590 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -6132,16 +6132,16 @@ namespace ts { } // Parses out a JSDoc type expression. - export function parseJSDocTypeExpression(): JSDocTypeExpression; - export function parseJSDocTypeExpression(requireBraces: true): JSDocTypeExpression | undefined; - export function parseJSDocTypeExpression(requireBraces?: boolean): JSDocTypeExpression | undefined { + export function parseJSDocTypeExpression(braceless?: boolean): JSDocTypeExpression { const result = createNode(SyntaxKind.JSDocTypeExpression, scanner.getTokenPos()); - if (!parseExpected(SyntaxKind.OpenBraceToken) && requireBraces) { - return undefined; + if (!braceless) { + parseExpected(SyntaxKind.OpenBraceToken); } result.type = doInsideOfContext(NodeFlags.JSDoc, parseType); - parseExpected(SyntaxKind.CloseBraceToken); + if (!braceless) { + parseExpected(SyntaxKind.CloseBraceToken); + } fixupParentReferences(result); return finishNode(result); @@ -6486,9 +6486,9 @@ namespace ts { tagsEnd = tag.end; } - function tryParseTypeExpression(): JSDocTypeExpression | undefined { + function tryParseTypeExpression(bracelessFallback?: boolean): JSDocTypeExpression | undefined { skipWhitespace(); - return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined; + return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : bracelessFallback && parseJSDocTypeExpression(/*braceless*/ true); } function parseBracketNameInPropertyAndParamTag(): { name: EntityName, isBracketed: boolean } { @@ -6597,7 +6597,7 @@ namespace ts { const result = createNode(SyntaxKind.JSDocTypeTag, atToken.pos); result.atToken = atToken; result.tagName = tagName; - result.typeExpression = parseJSDocTypeExpression(/*requireBraces*/ true); + result.typeExpression = tryParseTypeExpression(/*bracketlessFallback*/ true); return finishNode(result); } diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 8dc5a10c626f9..78df166633c49 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -1873,7 +1873,17 @@ namespace ts { return token = SyntaxKind.CommaToken; case CharacterCodes.dot: pos++; + if (text.substr(tokenPos, pos + 2) === "...") { + pos += 2; + return token = SyntaxKind.DotDotDotToken; + } return token = SyntaxKind.DotToken; + case CharacterCodes.exclamation: + pos++; + return token = SyntaxKind.ExclamationToken; + case CharacterCodes.question: + pos++; + return token = SyntaxKind.QuestionToken; } if (isIdentifierStart(ch, ScriptTarget.Latest)) { @@ -1881,6 +1891,7 @@ namespace ts { while (isIdentifierPart(text.charCodeAt(pos), ScriptTarget.Latest) && pos < end) { pos++; } + tokenValue = text.substring(tokenPos, pos); return token = SyntaxKind.Identifier; } else { diff --git a/tests/baselines/reference/jsdocTypedefMissingType.errors.txt b/tests/baselines/reference/jsdocTypedefMissingType.errors.txt index b5b29a47ed9f9..ef1141a8e8157 100644 --- a/tests/baselines/reference/jsdocTypedefMissingType.errors.txt +++ b/tests/baselines/reference/jsdocTypedefMissingType.errors.txt @@ -1,8 +1,7 @@ /a.js(2,14): error TS8021: JSDoc '@typedef' tag should either have a type annotation or be followed by '@property' or '@member' tags. -/a.js(12,11): error TS1005: '{' expected. -==== /a.js (2 errors) ==== +==== /a.js (1 errors) ==== // Bad: missing a type /** @typedef T */ ~ @@ -17,7 +16,5 @@ */ /** @type Person */ - ~~~~~~ -!!! error TS1005: '{' expected. const person = { name: "" }; \ No newline at end of file diff --git a/tests/baselines/reference/jsdocTypedefMissingType.types b/tests/baselines/reference/jsdocTypedefMissingType.types index 4a3f796ccb892..18cd68abfcb8b 100644 --- a/tests/baselines/reference/jsdocTypedefMissingType.types +++ b/tests/baselines/reference/jsdocTypedefMissingType.types @@ -14,8 +14,8 @@ const t = 0; /** @type Person */ const person = { name: "" }; ->person : { [x: string]: any; name: string; } ->{ name: "" } : { [x: string]: any; name: string; } +>person : { name: string; } +>{ name: "" } : { name: string; } >name : string >"" : "" diff --git a/tests/baselines/reference/malformedTags.types b/tests/baselines/reference/malformedTags.types index b4f7daecd8f62..c3af959586790 100644 --- a/tests/baselines/reference/malformedTags.types +++ b/tests/baselines/reference/malformedTags.types @@ -5,7 +5,7 @@ * @type Function */ var isArray = Array.isArray; ->isArray : (arg: any) => arg is any[] +>isArray : Function >Array.isArray : (arg: any) => arg is any[] >Array : ArrayConstructor >isArray : (arg: any) => arg is any[] diff --git a/tests/baselines/reference/user/chrome-devtools-frontend.log b/tests/baselines/reference/user/chrome-devtools-frontend.log index ffb5e7c0b6cbf..4af634e0cef85 100644 --- a/tests/baselines/reference/user/chrome-devtools-frontend.log +++ b/tests/baselines/reference/user/chrome-devtools-frontend.log @@ -1,8 +1,6 @@ Exit Code: 1 Standard output: node_modules/chrome-devtools-frontend/front_end/Runtime.js(398,24): error TS1138: Parameter declaration expected. -node_modules/chrome-devtools-frontend/front_end/Runtime.js(527,55): error TS1005: '{' expected. -node_modules/chrome-devtools-frontend/front_end/accessibility/AXBreadcrumbsPane.js(314,15): error TS1005: '{' expected. node_modules/chrome-devtools-frontend/front_end/animation/AnimationModel.js(810,65): error TS1003: Identifier expected. node_modules/chrome-devtools-frontend/front_end/audits/AuditRules.js(488,2): error TS1003: Identifier expected. node_modules/chrome-devtools-frontend/front_end/audits/AuditsPanel.js(513,28): error TS1005: '>' expected. @@ -48,10 +46,8 @@ node_modules/chrome-devtools-frontend/front_end/console/ConsoleView.js(1521,2): node_modules/chrome-devtools-frontend/front_end/console_test_runner/ConsoleTestRunner.js(10,73): error TS1003: Identifier expected. node_modules/chrome-devtools-frontend/front_end/cookie_table/CookiesTable.js(39,36): error TS1138: Parameter declaration expected. node_modules/chrome-devtools-frontend/front_end/coverage/CoverageDecorationManager.js(7,2): error TS1131: Property or signature expected. -node_modules/chrome-devtools-frontend/front_end/coverage/CoverageDecorationManager.js(258,34): error TS1005: '{' expected. node_modules/chrome-devtools-frontend/front_end/coverage/CoverageModel.js(5,72): error TS1003: Identifier expected. node_modules/chrome-devtools-frontend/front_end/coverage/CoverageModel.js(8,57): error TS1003: Identifier expected. -node_modules/chrome-devtools-frontend/front_end/coverage/CoverageView.js(231,59): error TS1005: '{' expected. node_modules/chrome-devtools-frontend/front_end/data_grid/DataGrid.js(1200,2): error TS1131: Property or signature expected. node_modules/chrome-devtools-frontend/front_end/devices/DevicesView.js(890,194): error TS1003: Identifier expected. node_modules/chrome-devtools-frontend/front_end/devices/DevicesView.js(893,105): error TS1003: Identifier expected. @@ -98,7 +94,6 @@ node_modules/chrome-devtools-frontend/front_end/formatter/FormatterWorkerPool.js node_modules/chrome-devtools-frontend/front_end/formatter/FormatterWorkerPool.js(322,2): error TS1003: Identifier expected. node_modules/chrome-devtools-frontend/front_end/formatter/FormatterWorkerPool.js(327,2): error TS1003: Identifier expected. node_modules/chrome-devtools-frontend/front_end/formatter_worker/FormatterWorker.js(32,30): error TS1138: Parameter declaration expected. -node_modules/chrome-devtools-frontend/front_end/formatter_worker/FormatterWorker.js(58,26): error TS1005: '{' expected. node_modules/chrome-devtools-frontend/front_end/formatter_worker/RelaxedJSONParser.js(180,2): error TS1003: Identifier expected. node_modules/chrome-devtools-frontend/front_end/heap_snapshot_worker/HeapSnapshot.js(1370,4): error TS1131: Property or signature expected. node_modules/chrome-devtools-frontend/front_end/heap_snapshot_worker/HeapSnapshot.js(2118,2): error TS1131: Property or signature expected. @@ -107,7 +102,6 @@ node_modules/chrome-devtools-frontend/front_end/help/Help.js(57,2): error TS1131 node_modules/chrome-devtools-frontend/front_end/host/InspectorFrontendHostAPI.js(16,4): error TS1003: Identifier expected. node_modules/chrome-devtools-frontend/front_end/host/InspectorFrontendHostAPI.js(23,4): error TS1003: Identifier expected. node_modules/chrome-devtools-frontend/front_end/inline_editor/BezierEditor.js(270,103): error TS1003: Identifier expected. -node_modules/chrome-devtools-frontend/front_end/layer_viewer/Layers3DView.js(68,15): error TS1005: '{' expected. node_modules/chrome-devtools-frontend/front_end/layer_viewer/Layers3DView.js(761,67): error TS1003: Identifier expected. node_modules/chrome-devtools-frontend/front_end/mobile_throttling/ThrottlingPresets.js(14,2): error TS1131: Property or signature expected. node_modules/chrome-devtools-frontend/front_end/mobile_throttling/ThrottlingPresets.js(56,2): error TS1131: Property or signature expected. @@ -129,8 +123,6 @@ node_modules/chrome-devtools-frontend/front_end/network_log/NetworkLog.js(470,13 node_modules/chrome-devtools-frontend/front_end/object_ui/CustomPreviewComponent.js(140,16): error TS1110: Type expected. node_modules/chrome-devtools-frontend/front_end/object_ui/CustomPreviewComponent.js(141,16): error TS1110: Type expected. node_modules/chrome-devtools-frontend/front_end/object_ui/JavaScriptAutocomplete.js(7,64): error TS1003: Identifier expected. -node_modules/chrome-devtools-frontend/front_end/perf_ui/FlameChart.js(907,17): error TS1005: '{' expected. -node_modules/chrome-devtools-frontend/front_end/perf_ui/FlameChart.js(1167,15): error TS1005: '{' expected. node_modules/chrome-devtools-frontend/front_end/perf_ui/FlameChart.js(1387,2): error TS1131: Property or signature expected. node_modules/chrome-devtools-frontend/front_end/perf_ui/FlameChart.js(1397,2): error TS1131: Property or signature expected. node_modules/chrome-devtools-frontend/front_end/perf_ui/TimelineGrid.js(266,89): error TS1003: Identifier expected. @@ -164,7 +156,7 @@ node_modules/chrome-devtools-frontend/front_end/sdk/LayerTreeBase.js(8,1): error node_modules/chrome-devtools-frontend/front_end/sdk/NetworkManager.js(182,71): error TS1003: Identifier expected. node_modules/chrome-devtools-frontend/front_end/sdk/NetworkManager.js(198,2): error TS1131: Property or signature expected. node_modules/chrome-devtools-frontend/front_end/sdk/NetworkManager.js(238,48): error TS1003: Identifier expected. -node_modules/chrome-devtools-frontend/front_end/sdk/NetworkManager.js(1197,86): error TS1003: Identifier expected. +node_modules/chrome-devtools-frontend/front_end/sdk/NetworkManager.js(1200,86): error TS1003: Identifier expected. node_modules/chrome-devtools-frontend/front_end/sdk/NetworkRequest.js(1117,47): error TS1003: Identifier expected. node_modules/chrome-devtools-frontend/front_end/sdk/NetworkRequest.js(1127,122): error TS1003: Identifier expected. node_modules/chrome-devtools-frontend/front_end/sdk/NetworkRequest.js(1130,82): error TS1003: Identifier expected. @@ -210,13 +202,11 @@ node_modules/chrome-devtools-frontend/front_end/text_utils/TextUtils.js(340,32): node_modules/chrome-devtools-frontend/front_end/timeline/PerformanceMonitor.js(394,2): error TS1131: Property or signature expected. node_modules/chrome-devtools-frontend/front_end/timeline/PerformanceMonitor.js(406,2): error TS1131: Property or signature expected. node_modules/chrome-devtools-frontend/front_end/timeline/TimelineController.js(283,2): error TS1131: Property or signature expected. -node_modules/chrome-devtools-frontend/front_end/timeline/TimelineDetailsView.js(34,15): error TS1005: '{' expected. node_modules/chrome-devtools-frontend/front_end/timeline/TimelineHistoryManager.js(255,86): error TS1003: Identifier expected. node_modules/chrome-devtools-frontend/front_end/timeline/TimelinePanel.js(1087,106): error TS1003: Identifier expected. node_modules/chrome-devtools-frontend/front_end/timeline/TimelineUIUtils.js(2113,2): error TS1131: Property or signature expected. node_modules/chrome-devtools-frontend/front_end/timeline_model/TimelineModel.js(1246,99): error TS1003: Identifier expected. node_modules/chrome-devtools-frontend/front_end/timeline_model/TimelineModel.js(1420,82): error TS1003: Identifier expected. -node_modules/chrome-devtools-frontend/front_end/timeline_model/TimelineModelFilter.js(43,22): error TS1005: '{' expected. node_modules/chrome-devtools-frontend/front_end/timeline_model/TracingLayerTree.js(17,1): error TS1003: Identifier expected. node_modules/chrome-devtools-frontend/front_end/timeline_model/TracingLayerTree.js(26,1): error TS1003: Identifier expected. node_modules/chrome-devtools-frontend/front_end/ui/Context.js(14,33): error TS1110: Type expected. From 460eb83fef675b8ab3beb4cfc00760a4500cdc93 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 17 Nov 2017 15:45:17 -0800 Subject: [PATCH 2/2] Incorporate restructuring from @andy-ms --- src/compiler/parser.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 01ae8d9ad5590..4e1d4ccd9b04e 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -6132,14 +6132,12 @@ namespace ts { } // Parses out a JSDoc type expression. - export function parseJSDocTypeExpression(braceless?: boolean): JSDocTypeExpression { + export function parseJSDocTypeExpression(mayOmitBraces?: boolean): JSDocTypeExpression { const result = createNode(SyntaxKind.JSDocTypeExpression, scanner.getTokenPos()); - if (!braceless) { - parseExpected(SyntaxKind.OpenBraceToken); - } + const hasBrace = (mayOmitBraces ? parseOptional : parseExpected)(SyntaxKind.OpenBraceToken); result.type = doInsideOfContext(NodeFlags.JSDoc, parseType); - if (!braceless) { + if (!mayOmitBraces || hasBrace) { parseExpected(SyntaxKind.CloseBraceToken); } @@ -6486,9 +6484,9 @@ namespace ts { tagsEnd = tag.end; } - function tryParseTypeExpression(bracelessFallback?: boolean): JSDocTypeExpression | undefined { + function tryParseTypeExpression(): JSDocTypeExpression | undefined { skipWhitespace(); - return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : bracelessFallback && parseJSDocTypeExpression(/*braceless*/ true); + return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined; } function parseBracketNameInPropertyAndParamTag(): { name: EntityName, isBracketed: boolean } { @@ -6597,7 +6595,7 @@ namespace ts { const result = createNode(SyntaxKind.JSDocTypeTag, atToken.pos); result.atToken = atToken; result.tagName = tagName; - result.typeExpression = tryParseTypeExpression(/*bracketlessFallback*/ true); + result.typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true); return finishNode(result); }