From 64bbf5ee125b44a55cbe8efda60182ec20d815be Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Fri, 17 Aug 2018 22:04:15 -0600 Subject: [PATCH 1/3] Skip asterisks after newline when parsing JSDoc types --- src/compiler/parser.ts | 2 + src/compiler/scanner.ts | 15 ++ src/compiler/utilities.ts | 19 +- .../reference/typedefTagWrapping.errors.txt | 136 ++++++++++++++ .../reference/typedefTagWrapping.symbols | 166 ++++++++++++++++- .../reference/typedefTagWrapping.types | 170 +++++++++++++++++- .../conformance/jsdoc/typedefTagWrapping.ts | 122 ++++++++++++- .../fourslash/jsDocFunctionSignatures12.ts | 24 ++- 8 files changed, 642 insertions(+), 12 deletions(-) create mode 100644 tests/baselines/reference/typedefTagWrapping.errors.txt diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index b40648033de37..d1102eb78ac77 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2377,8 +2377,10 @@ namespace ts { } function parseJSDocType(): TypeNode { + scanner.setInJSDocType(true); const dotdotdot = parseOptionalToken(SyntaxKind.DotDotDotToken); let type = parseTypeOrTypePredicate(); + scanner.setInJSDocType(false); if (dotdotdot) { const variadic = createNode(SyntaxKind.JSDocVariadicType, dotdotdot.pos) as JSDocVariadicType; variadic.type = type; diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 61ce8330bff77..809ccadbc6e64 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -42,6 +42,8 @@ namespace ts { setScriptTarget(scriptTarget: ScriptTarget): void; setLanguageVariant(variant: LanguageVariant): void; setTextPos(textPos: number): void; + /* @internal */ + setInJSDocType(inType: boolean): void; // Invokes the provided callback then unconditionally restores the scanner to the state it // was in immediately prior to invoking the callback. The result of invoking the callback // is returned from this function. @@ -824,6 +826,8 @@ namespace ts { let tokenValue!: string; let tokenFlags: TokenFlags; + let inJSDocType = 0; + setText(text, start, length); return { @@ -854,6 +858,7 @@ namespace ts { setLanguageVariant, setOnError, setTextPos, + setInJSDocType, tryScan, lookAhead, scanRange, @@ -1350,6 +1355,7 @@ namespace ts { function scan(): SyntaxKind { startPos = pos; tokenFlags = 0; + let asteriskSeen = false; while (true) { tokenPos = pos; if (pos >= end) { @@ -1447,6 +1453,11 @@ namespace ts { return pos += 2, token = SyntaxKind.AsteriskAsteriskToken; } pos++; + if (inJSDocType && !asteriskSeen && (tokenFlags & TokenFlags.PrecedingLineBreak)) { + // decoration at the start of a JSDoc comment line + asteriskSeen = true; + continue; + } return token = SyntaxKind.AsteriskToken; case CharacterCodes.plus: if (text.charCodeAt(pos + 1) === CharacterCodes.plus) { @@ -2078,5 +2089,9 @@ namespace ts { tokenValue = undefined!; tokenFlags = 0; } + + function setInJSDocType(inType: boolean) { + inJSDocType += inType ? 1 : -1; + } } } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 7c5f2108c1e84..b07e9b8cbd198 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -490,12 +490,29 @@ namespace ts { return getTextOfNodeFromSourceText(sourceFile.text, node, includeTrivia); } + function isJSDocTypeExpressionOrChild(node: Node): boolean { + if (node.kind === SyntaxKind.JSDocTypeExpression) { + return true; + } + if (node.parent) { + return isJSDocTypeExpressionOrChild(node.parent); + } + return false; + } + export function getTextOfNodeFromSourceText(sourceText: string, node: Node, includeTrivia = false): string { if (nodeIsMissing(node)) { return ""; } - return sourceText.substring(includeTrivia ? node.pos : skipTrivia(sourceText, node.pos), node.end); + let text = sourceText.substring(includeTrivia ? node.pos : skipTrivia(sourceText, node.pos), node.end); + + if (isJSDocTypeExpressionOrChild(node)) { + // strip space + asterisk at line start + text = text.replace(/(^|\r?\n|\r)\s*\*\s*/g, "$1"); + } + + return text; } export function getTextOfNode(node: Node, includeTrivia = false): string { diff --git a/tests/baselines/reference/typedefTagWrapping.errors.txt b/tests/baselines/reference/typedefTagWrapping.errors.txt new file mode 100644 index 0000000000000..f480c1391e80a --- /dev/null +++ b/tests/baselines/reference/typedefTagWrapping.errors.txt @@ -0,0 +1,136 @@ +tests/cases/conformance/jsdoc/mod7.js(5,7): error TS1110: Type expected. +tests/cases/conformance/jsdoc/mod7.js(8,4): error TS1110: Type expected. + + +==== tests/cases/conformance/jsdoc/mod1.js (0 errors) ==== + /** + * @typedef {function(string): boolean} + * Type1 + */ + + /** + * Tries to use a type whose name is on a different + * line than the typedef tag. + * @param {Type1} func The function to call. + * @param {string} arg The argument to call it with. + * @returns {boolean} The return. + */ + function callIt(func, arg) { + return func(arg); + } + +==== tests/cases/conformance/jsdoc/mod2.js (0 errors) ==== + /** + * @typedef {{ + * num: number, + * str: string, + * boo: boolean + * }} Type2 + */ + + /** + * Makes use of a type with a multiline type expression. + * @param {Type2} obj The object. + * @returns {string|number} The return. + */ + function check(obj) { + return obj.boo ? obj.num : obj.str; + } + +==== tests/cases/conformance/jsdoc/mod3.js (0 errors) ==== + /** + * A function whose signature is very long. + * + * @typedef {function(boolean, string, number): + * (string|number)} StringOrNumber1 + */ + + /** + * Makes use of a function type with a long signature. + * @param {StringOrNumber1} func The function. + * @param {boolean} bool The condition. + * @param {string} str The string. + * @param {number} num The number. + * @returns {string|number} The return. + */ + function use1(func, bool, str, num) { + return func(bool, str, num) + } + +==== tests/cases/conformance/jsdoc/mod4.js (0 errors) ==== + /** + * A function whose signature is very long. + * + * @typedef {function(boolean, string, + * number): + * (string|number)} StringOrNumber2 + */ + + /** + * Makes use of a function type with a long signature. + * @param {StringOrNumber2} func The function. + * @param {boolean} bool The condition. + * @param {string} str The string. + * @param {number} num The number. + * @returns {string|number} The return. + */ + function use2(func, bool, str, num) { + return func(bool, str, num) + } + +==== tests/cases/conformance/jsdoc/mod5.js (0 errors) ==== + /** + * @typedef {{ + * num: + * number, + * str: + * string, + * boo: + * boolean + * }} Type5 + */ + + /** + * Makes use of a type with a multiline type expression. + * @param {Type5} obj The object. + * @returns {string|number} The return. + */ + function check5(obj) { + return obj.boo ? obj.num : obj.str; + } + +==== tests/cases/conformance/jsdoc/mod6.js (0 errors) ==== + /** + * @typedef {{ + * foo: + * *, + * bar: + * * + * }} Type6 + */ + + /** + * Makes use of a type with a multiline type expression. + * @param {Type6} obj The object. + * @returns {*} The return. + */ + function check6(obj) { + return obj.foo; + } + + +==== tests/cases/conformance/jsdoc/mod7.js (2 errors) ==== + /** + Multiline type expressions in comments without leading * are not supported. + @typedef {{ + foo: + *, + ~ +!!! error TS1110: Type expected. + bar: + * + }} Type7 + ~ +!!! error TS1110: Type expected. + */ + \ No newline at end of file diff --git a/tests/baselines/reference/typedefTagWrapping.symbols b/tests/baselines/reference/typedefTagWrapping.symbols index ec93da5a45b4c..ea0bb73a849ff 100644 --- a/tests/baselines/reference/typedefTagWrapping.symbols +++ b/tests/baselines/reference/typedefTagWrapping.symbols @@ -1,13 +1,13 @@ === tests/cases/conformance/jsdoc/mod1.js === /** * @typedef {function(string): boolean} - * MyType + * Type1 */ /** * Tries to use a type whose name is on a different * line than the typedef tag. - * @param {MyType} func The function to call. + * @param {Type1} func The function to call. * @param {string} arg The argument to call it with. * @returns {boolean} The return. */ @@ -21,3 +21,165 @@ function callIt(func, arg) { >arg : Symbol(arg, Decl(mod1.js, 12, 21)) } +=== tests/cases/conformance/jsdoc/mod2.js === +/** + * @typedef {{ + * num: number, + * str: string, + * boo: boolean + * }} Type2 + */ + +/** + * Makes use of a type with a multiline type expression. + * @param {Type2} obj The object. + * @returns {string|number} The return. + */ +function check(obj) { +>check : Symbol(check, Decl(mod2.js, 0, 0)) +>obj : Symbol(obj, Decl(mod2.js, 13, 15)) + + return obj.boo ? obj.num : obj.str; +>obj.boo : Symbol(boo, Decl(mod2.js, 3, 17)) +>obj : Symbol(obj, Decl(mod2.js, 13, 15)) +>boo : Symbol(boo, Decl(mod2.js, 3, 17)) +>obj.num : Symbol(num, Decl(mod2.js, 1, 14)) +>obj : Symbol(obj, Decl(mod2.js, 13, 15)) +>num : Symbol(num, Decl(mod2.js, 1, 14)) +>obj.str : Symbol(str, Decl(mod2.js, 2, 17)) +>obj : Symbol(obj, Decl(mod2.js, 13, 15)) +>str : Symbol(str, Decl(mod2.js, 2, 17)) +} + +=== tests/cases/conformance/jsdoc/mod3.js === +/** + * A function whose signature is very long. + * + * @typedef {function(boolean, string, number): + * (string|number)} StringOrNumber1 + */ + +/** + * Makes use of a function type with a long signature. + * @param {StringOrNumber1} func The function. + * @param {boolean} bool The condition. + * @param {string} str The string. + * @param {number} num The number. + * @returns {string|number} The return. + */ +function use1(func, bool, str, num) { +>use1 : Symbol(use1, Decl(mod3.js, 0, 0)) +>func : Symbol(func, Decl(mod3.js, 15, 14)) +>bool : Symbol(bool, Decl(mod3.js, 15, 19)) +>str : Symbol(str, Decl(mod3.js, 15, 25)) +>num : Symbol(num, Decl(mod3.js, 15, 30)) + + return func(bool, str, num) +>func : Symbol(func, Decl(mod3.js, 15, 14)) +>bool : Symbol(bool, Decl(mod3.js, 15, 19)) +>str : Symbol(str, Decl(mod3.js, 15, 25)) +>num : Symbol(num, Decl(mod3.js, 15, 30)) +} + +=== tests/cases/conformance/jsdoc/mod4.js === +/** + * A function whose signature is very long. + * + * @typedef {function(boolean, string, + * number): + * (string|number)} StringOrNumber2 + */ + +/** + * Makes use of a function type with a long signature. + * @param {StringOrNumber2} func The function. + * @param {boolean} bool The condition. + * @param {string} str The string. + * @param {number} num The number. + * @returns {string|number} The return. + */ +function use2(func, bool, str, num) { +>use2 : Symbol(use2, Decl(mod4.js, 0, 0)) +>func : Symbol(func, Decl(mod4.js, 16, 14)) +>bool : Symbol(bool, Decl(mod4.js, 16, 19)) +>str : Symbol(str, Decl(mod4.js, 16, 25)) +>num : Symbol(num, Decl(mod4.js, 16, 30)) + + return func(bool, str, num) +>func : Symbol(func, Decl(mod4.js, 16, 14)) +>bool : Symbol(bool, Decl(mod4.js, 16, 19)) +>str : Symbol(str, Decl(mod4.js, 16, 25)) +>num : Symbol(num, Decl(mod4.js, 16, 30)) +} + +=== tests/cases/conformance/jsdoc/mod5.js === +/** + * @typedef {{ + * num: + * number, + * str: + * string, + * boo: + * boolean + * }} Type5 + */ + +/** + * Makes use of a type with a multiline type expression. + * @param {Type5} obj The object. + * @returns {string|number} The return. + */ +function check5(obj) { +>check5 : Symbol(check5, Decl(mod5.js, 0, 0)) +>obj : Symbol(obj, Decl(mod5.js, 16, 16)) + + return obj.boo ? obj.num : obj.str; +>obj.boo : Symbol(boo, Decl(mod5.js, 5, 12)) +>obj : Symbol(obj, Decl(mod5.js, 16, 16)) +>boo : Symbol(boo, Decl(mod5.js, 5, 12)) +>obj.num : Symbol(num, Decl(mod5.js, 1, 14)) +>obj : Symbol(obj, Decl(mod5.js, 16, 16)) +>num : Symbol(num, Decl(mod5.js, 1, 14)) +>obj.str : Symbol(str, Decl(mod5.js, 3, 12)) +>obj : Symbol(obj, Decl(mod5.js, 16, 16)) +>str : Symbol(str, Decl(mod5.js, 3, 12)) +} + +=== tests/cases/conformance/jsdoc/mod6.js === +/** + * @typedef {{ + * foo: + * *, + * bar: + * * + * }} Type6 + */ + +/** + * Makes use of a type with a multiline type expression. + * @param {Type6} obj The object. + * @returns {*} The return. + */ +function check6(obj) { +>check6 : Symbol(check6, Decl(mod6.js, 0, 0)) +>obj : Symbol(obj, Decl(mod6.js, 14, 16)) + + return obj.foo; +>obj.foo : Symbol(foo, Decl(mod6.js, 1, 14)) +>obj : Symbol(obj, Decl(mod6.js, 14, 16)) +>foo : Symbol(foo, Decl(mod6.js, 1, 14)) +} + + +=== tests/cases/conformance/jsdoc/mod7.js === +/** +No type information for this code. Multiline type expressions in comments without leading * are not supported. +No type information for this code. @typedef {{ +No type information for this code. foo: +No type information for this code. *, +No type information for this code. bar: +No type information for this code. * +No type information for this code. }} Type7 +No type information for this code. */ +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/typedefTagWrapping.types b/tests/baselines/reference/typedefTagWrapping.types index 8c92717d1a1ab..8b49439d7dbc6 100644 --- a/tests/baselines/reference/typedefTagWrapping.types +++ b/tests/baselines/reference/typedefTagWrapping.types @@ -1,13 +1,13 @@ === tests/cases/conformance/jsdoc/mod1.js === /** * @typedef {function(string): boolean} - * MyType + * Type1 */ /** * Tries to use a type whose name is on a different * line than the typedef tag. - * @param {MyType} func The function to call. + * @param {Type1} func The function to call. * @param {string} arg The argument to call it with. * @returns {boolean} The return. */ @@ -22,3 +22,169 @@ function callIt(func, arg) { >arg : string } +=== tests/cases/conformance/jsdoc/mod2.js === +/** + * @typedef {{ + * num: number, + * str: string, + * boo: boolean + * }} Type2 + */ + +/** + * Makes use of a type with a multiline type expression. + * @param {Type2} obj The object. + * @returns {string|number} The return. + */ +function check(obj) { +>check : (obj: { num: number; str: string; boo: boolean; }) => string | number +>obj : { num: number; str: string; boo: boolean; } + + return obj.boo ? obj.num : obj.str; +>obj.boo ? obj.num : obj.str : string | number +>obj.boo : boolean +>obj : { num: number; str: string; boo: boolean; } +>boo : boolean +>obj.num : number +>obj : { num: number; str: string; boo: boolean; } +>num : number +>obj.str : string +>obj : { num: number; str: string; boo: boolean; } +>str : string +} + +=== tests/cases/conformance/jsdoc/mod3.js === +/** + * A function whose signature is very long. + * + * @typedef {function(boolean, string, number): + * (string|number)} StringOrNumber1 + */ + +/** + * Makes use of a function type with a long signature. + * @param {StringOrNumber1} func The function. + * @param {boolean} bool The condition. + * @param {string} str The string. + * @param {number} num The number. + * @returns {string|number} The return. + */ +function use1(func, bool, str, num) { +>use1 : (func: (arg0: boolean, arg1: string, arg2: number) => string | number, bool: boolean, str: string, num: number) => string | number +>func : (arg0: boolean, arg1: string, arg2: number) => string | number +>bool : boolean +>str : string +>num : number + + return func(bool, str, num) +>func(bool, str, num) : string | number +>func : (arg0: boolean, arg1: string, arg2: number) => string | number +>bool : boolean +>str : string +>num : number +} + +=== tests/cases/conformance/jsdoc/mod4.js === +/** + * A function whose signature is very long. + * + * @typedef {function(boolean, string, + * number): + * (string|number)} StringOrNumber2 + */ + +/** + * Makes use of a function type with a long signature. + * @param {StringOrNumber2} func The function. + * @param {boolean} bool The condition. + * @param {string} str The string. + * @param {number} num The number. + * @returns {string|number} The return. + */ +function use2(func, bool, str, num) { +>use2 : (func: (arg0: boolean, arg1: string, arg2: number) => string | number, bool: boolean, str: string, num: number) => string | number +>func : (arg0: boolean, arg1: string, arg2: number) => string | number +>bool : boolean +>str : string +>num : number + + return func(bool, str, num) +>func(bool, str, num) : string | number +>func : (arg0: boolean, arg1: string, arg2: number) => string | number +>bool : boolean +>str : string +>num : number +} + +=== tests/cases/conformance/jsdoc/mod5.js === +/** + * @typedef {{ + * num: + * number, + * str: + * string, + * boo: + * boolean + * }} Type5 + */ + +/** + * Makes use of a type with a multiline type expression. + * @param {Type5} obj The object. + * @returns {string|number} The return. + */ +function check5(obj) { +>check5 : (obj: { num: number; str: string; boo: boolean; }) => string | number +>obj : { num: number; str: string; boo: boolean; } + + return obj.boo ? obj.num : obj.str; +>obj.boo ? obj.num : obj.str : string | number +>obj.boo : boolean +>obj : { num: number; str: string; boo: boolean; } +>boo : boolean +>obj.num : number +>obj : { num: number; str: string; boo: boolean; } +>num : number +>obj.str : string +>obj : { num: number; str: string; boo: boolean; } +>str : string +} + +=== tests/cases/conformance/jsdoc/mod6.js === +/** + * @typedef {{ + * foo: + * *, + * bar: + * * + * }} Type6 + */ + +/** + * Makes use of a type with a multiline type expression. + * @param {Type6} obj The object. + * @returns {*} The return. + */ +function check6(obj) { +>check6 : (obj: { foo: any; bar: any; }) => any +>obj : { foo: any; bar: any; } + + return obj.foo; +>obj.foo : any +>obj : { foo: any; bar: any; } +>foo : any +} + + +=== tests/cases/conformance/jsdoc/mod7.js === +/** +No type information for this code. Multiline type expressions in comments without leading * are not supported. +No type information for this code. @typedef {{ +No type information for this code. foo: +No type information for this code. *, +No type information for this code. bar: +No type information for this code. * +No type information for this code. }} Type7 +No type information for this code. */ +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/cases/conformance/jsdoc/typedefTagWrapping.ts b/tests/cases/conformance/jsdoc/typedefTagWrapping.ts index 53cff6d02c0ae..19f4f1289a21d 100644 --- a/tests/cases/conformance/jsdoc/typedefTagWrapping.ts +++ b/tests/cases/conformance/jsdoc/typedefTagWrapping.ts @@ -1,20 +1,138 @@ // @noEmit: true // @allowJs: true // @checkJs: true + // @Filename: mod1.js /** * @typedef {function(string): boolean} - * MyType + * Type1 */ /** * Tries to use a type whose name is on a different * line than the typedef tag. - * @param {MyType} func The function to call. + * @param {Type1} func The function to call. * @param {string} arg The argument to call it with. * @returns {boolean} The return. */ function callIt(func, arg) { return func(arg); } + +// @Filename: mod2.js + +/** + * @typedef {{ + * num: number, + * str: string, + * boo: boolean + * }} Type2 + */ + +/** + * Makes use of a type with a multiline type expression. + * @param {Type2} obj The object. + * @returns {string|number} The return. + */ +function check(obj) { + return obj.boo ? obj.num : obj.str; +} + +// @Filename: mod3.js + +/** + * A function whose signature is very long. + * + * @typedef {function(boolean, string, number): + * (string|number)} StringOrNumber1 + */ + +/** + * Makes use of a function type with a long signature. + * @param {StringOrNumber1} func The function. + * @param {boolean} bool The condition. + * @param {string} str The string. + * @param {number} num The number. + * @returns {string|number} The return. + */ +function use1(func, bool, str, num) { + return func(bool, str, num) +} + +// @Filename: mod4.js + +/** + * A function whose signature is very long. + * + * @typedef {function(boolean, string, + * number): + * (string|number)} StringOrNumber2 + */ + +/** + * Makes use of a function type with a long signature. + * @param {StringOrNumber2} func The function. + * @param {boolean} bool The condition. + * @param {string} str The string. + * @param {number} num The number. + * @returns {string|number} The return. + */ +function use2(func, bool, str, num) { + return func(bool, str, num) +} + +// @Filename: mod5.js + +/** + * @typedef {{ + * num: + * number, + * str: + * string, + * boo: + * boolean + * }} Type5 + */ + +/** + * Makes use of a type with a multiline type expression. + * @param {Type5} obj The object. + * @returns {string|number} The return. + */ +function check5(obj) { + return obj.boo ? obj.num : obj.str; +} + +// @Filename: mod6.js + +/** + * @typedef {{ + * foo: + * *, + * bar: + * * + * }} Type6 + */ + +/** + * Makes use of a type with a multiline type expression. + * @param {Type6} obj The object. + * @returns {*} The return. + */ +function check6(obj) { + return obj.foo; +} + + +// @Filename: mod7.js + +/** + Multiline type expressions in comments without leading * are not supported. + @typedef {{ + foo: + *, + bar: + * + }} Type7 + */ diff --git a/tests/cases/fourslash/jsDocFunctionSignatures12.ts b/tests/cases/fourslash/jsDocFunctionSignatures12.ts index 29a8ac4caeb9c..a83b18782ca46 100644 --- a/tests/cases/fourslash/jsDocFunctionSignatures12.ts +++ b/tests/cases/fourslash/jsDocFunctionSignatures12.ts @@ -1,13 +1,27 @@ - /// + // @allowJs: true -// @Filename: Foo.js +// @Filename: jsDocFunctionSignatures.js + /////** -//// * @param {{ stringProp: string, -//// * numProp: number }} o +//// * @param {{ +//// * stringProp: string, +//// * numProp: number, +//// * boolProp: boolean, +//// * anyProp: *, +//// * anotherAnyProp: +//// * * +//// * }} o //// */ ////function f1(o) { //// o/**/; ////} + goTo.marker(); -verify.quickInfoIs("(parameter) o: any"); +verify.quickInfoIs(`(parameter) o: { + stringProp: string; + numProp: number; + boolProp: boolean; + anyProp: any; + anotherAnyProp: any; +}`); From 3b24fba217bd7b2af67cca9c95181d4f0e083511 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Tue, 4 Sep 2018 15:30:27 -0600 Subject: [PATCH 2/3] Single boolean expression --- src/compiler/utilities.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index b07e9b8cbd198..3d5893d0a03fc 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -491,13 +491,7 @@ namespace ts { } function isJSDocTypeExpressionOrChild(node: Node): boolean { - if (node.kind === SyntaxKind.JSDocTypeExpression) { - return true; - } - if (node.parent) { - return isJSDocTypeExpressionOrChild(node.parent); - } - return false; + return node.kind === SyntaxKind.JSDocTypeExpression || (node.parent && isJSDocTypeExpressionOrChild(node.parent)); } export function getTextOfNodeFromSourceText(sourceText: string, node: Node, includeTrivia = false): string { From aca9919950c8242bda60e10a53f6b1032db41f30 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Tue, 4 Sep 2018 15:47:19 -0600 Subject: [PATCH 3/3] Test for parsing and printing multiline function signatures with * --- tests/cases/fourslash/jsDocFunctionSignatures12.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/cases/fourslash/jsDocFunctionSignatures12.ts b/tests/cases/fourslash/jsDocFunctionSignatures12.ts index a83b18782ca46..5976d01a3d6cf 100644 --- a/tests/cases/fourslash/jsDocFunctionSignatures12.ts +++ b/tests/cases/fourslash/jsDocFunctionSignatures12.ts @@ -10,6 +10,10 @@ //// * boolProp: boolean, //// * anyProp: *, //// * anotherAnyProp: +//// * *, +//// * functionProp: +//// * function(string, +//// * *): //// * * //// * }} o //// */ @@ -24,4 +28,5 @@ verify.quickInfoIs(`(parameter) o: { boolProp: boolean; anyProp: any; anotherAnyProp: any; + functionProp: (arg0: string, arg1: any) => any; }`);