From 8e86b24036eb5c13c72d78d8cb5fca620c002709 Mon Sep 17 00:00:00 2001 From: Alex T Date: Fri, 25 Sep 2020 22:36:04 +0300 Subject: [PATCH] feat(40233): add JS Doc types to smart selection (#40338) --- src/services/smartSelection.ts | 32 +++++++---- .../smartSelection_JSDocTags1.baseline | 30 ++++++++++ .../smartSelection_JSDocTags10.baseline | 29 ++++++++++ .../smartSelection_JSDocTags2.baseline | 21 +++++++ .../smartSelection_JSDocTags3.baseline | 21 +++++++ .../smartSelection_JSDocTags4.baseline | 34 ++++++++++++ .../smartSelection_JSDocTags5.baseline | 34 ++++++++++++ .../smartSelection_JSDocTags6.baseline | 31 +++++++++++ .../smartSelection_JSDocTags7.baseline | 26 +++++++++ .../smartSelection_JSDocTags8.baseline | 55 +++++++++++++++++++ .../smartSelection_JSDocTags9.baseline | 21 +++++++ .../fourslash/smartSelection_JSDocTags1.ts | 8 +++ .../fourslash/smartSelection_JSDocTags10.ts | 11 ++++ .../fourslash/smartSelection_JSDocTags2.ts | 8 +++ .../fourslash/smartSelection_JSDocTags3.ts | 8 +++ .../fourslash/smartSelection_JSDocTags4.ts | 13 +++++ .../fourslash/smartSelection_JSDocTags5.ts | 13 +++++ .../fourslash/smartSelection_JSDocTags6.ts | 12 ++++ .../fourslash/smartSelection_JSDocTags7.ts | 10 ++++ .../fourslash/smartSelection_JSDocTags8.ts | 10 ++++ .../fourslash/smartSelection_JSDocTags9.ts | 9 +++ 21 files changed, 426 insertions(+), 10 deletions(-) create mode 100644 tests/baselines/reference/smartSelection_JSDocTags1.baseline create mode 100644 tests/baselines/reference/smartSelection_JSDocTags10.baseline create mode 100644 tests/baselines/reference/smartSelection_JSDocTags2.baseline create mode 100644 tests/baselines/reference/smartSelection_JSDocTags3.baseline create mode 100644 tests/baselines/reference/smartSelection_JSDocTags4.baseline create mode 100644 tests/baselines/reference/smartSelection_JSDocTags5.baseline create mode 100644 tests/baselines/reference/smartSelection_JSDocTags6.baseline create mode 100644 tests/baselines/reference/smartSelection_JSDocTags7.baseline create mode 100644 tests/baselines/reference/smartSelection_JSDocTags8.baseline create mode 100644 tests/baselines/reference/smartSelection_JSDocTags9.baseline create mode 100644 tests/cases/fourslash/smartSelection_JSDocTags1.ts create mode 100644 tests/cases/fourslash/smartSelection_JSDocTags10.ts create mode 100644 tests/cases/fourslash/smartSelection_JSDocTags2.ts create mode 100644 tests/cases/fourslash/smartSelection_JSDocTags3.ts create mode 100644 tests/cases/fourslash/smartSelection_JSDocTags4.ts create mode 100644 tests/cases/fourslash/smartSelection_JSDocTags5.ts create mode 100644 tests/cases/fourslash/smartSelection_JSDocTags6.ts create mode 100644 tests/cases/fourslash/smartSelection_JSDocTags7.ts create mode 100644 tests/cases/fourslash/smartSelection_JSDocTags8.ts create mode 100644 tests/cases/fourslash/smartSelection_JSDocTags9.ts diff --git a/src/services/smartSelection.ts b/src/services/smartSelection.ts index 3263e7ed4fd..3fcab166959 100644 --- a/src/services/smartSelection.ts +++ b/src/services/smartSelection.ts @@ -13,7 +13,7 @@ namespace ts.SmartSelectionRange { const prevNode: Node | undefined = children[i - 1]; const node: Node = children[i]; const nextNode: Node | undefined = children[i + 1]; - if (node.getStart(sourceFile) > pos) { + if (getTokenPosOfNode(node, sourceFile, /*includeJsDoc*/ true) > pos) { break outer; } @@ -23,14 +23,14 @@ namespace ts.SmartSelectionRange { // of things that should be considered independently. // 3. A VariableStatement’s children are just a VaraiableDeclarationList and a semicolon. // 4. A lone VariableDeclaration in a VaraibleDeclaration feels redundant with the VariableStatement. - // // Dive in without pushing a selection range. if (isBlock(node) || isTemplateSpan(node) || isTemplateHead(node) || isTemplateTail(node) || prevNode && isTemplateHead(prevNode) || isVariableDeclarationList(node) && isVariableStatement(parentNode) || isSyntaxList(node) && isVariableDeclarationList(parentNode) - || isVariableDeclaration(node) && isSyntaxList(parentNode) && children.length === 1) { + || isVariableDeclaration(node) && isSyntaxList(parentNode) && children.length === 1 + || isJSDocTypeExpression(node) || isJSDocSignature(node) || isJSDocTypeLiteral(node)) { parentNode = node; break; } @@ -44,16 +44,15 @@ namespace ts.SmartSelectionRange { // Blocks with braces, brackets, parens, or JSX tags on separate lines should be // selected from open to close, including whitespace but not including the braces/etc. themselves. - const isBetweenMultiLineBookends = isSyntaxList(node) - && isListOpener(prevNode) - && isListCloser(nextNode) + const isBetweenMultiLineBookends = isSyntaxList(node) && isListOpener(prevNode) && isListCloser(nextNode) && !positionsAreOnSameLine(prevNode.getStart(), nextNode.getStart(), sourceFile); - const jsDocCommentStart = hasJSDocNodes(node) && node.jsDoc![0].getStart(); const start = isBetweenMultiLineBookends ? prevNode.getEnd() : node.getStart(); - const end = isBetweenMultiLineBookends ? nextNode.getStart() : node.getEnd(); - if (isNumber(jsDocCommentStart)) { - pushSelectionRange(jsDocCommentStart, end); + const end = isBetweenMultiLineBookends ? nextNode.getStart() : getEndPos(sourceFile, node); + + if (hasJSDocNodes(node) && node.jsDoc?.length) { + pushSelectionRange(first(node.jsDoc).getStart(), end); } + pushSelectionRange(start, end); // String literals should have a stop both inside and outside their quotes. @@ -270,4 +269,17 @@ namespace ts.SmartSelectionRange { || kind === SyntaxKind.CloseParenToken || kind === SyntaxKind.JsxClosingElement; } + + function getEndPos(sourceFile: SourceFile, node: Node): number { + switch (node.kind) { + case SyntaxKind.JSDocParameterTag: + case SyntaxKind.JSDocCallbackTag: + case SyntaxKind.JSDocPropertyTag: + case SyntaxKind.JSDocTypedefTag: + case SyntaxKind.JSDocThisTag: + return sourceFile.getLineEndOfPosition(node.getStart()); + default: + return node.getEnd(); + } + } } diff --git a/tests/baselines/reference/smartSelection_JSDocTags1.baseline b/tests/baselines/reference/smartSelection_JSDocTags1.baseline new file mode 100644 index 00000000000..0e390bc2fef --- /dev/null +++ b/tests/baselines/reference/smartSelection_JSDocTags1.baseline @@ -0,0 +1,30 @@ +/** + * @returns {Array<{ value: /**/string }>} + */ +function foo() { return [] } + + + string + + + value: string + + + { value: string } + + + Array<{ value: string }> + + + @returns {Array<{ value: string }>} + + +/** + * @returns {Array<{ value: string }>} + */ + + +/** + * @returns {Array<{ value: string }>} + */ +function foo() { return [] } \ No newline at end of file diff --git a/tests/baselines/reference/smartSelection_JSDocTags10.baseline b/tests/baselines/reference/smartSelection_JSDocTags10.baseline new file mode 100644 index 00000000000..195a0bd6eb3 --- /dev/null +++ b/tests/baselines/reference/smartSelection_JSDocTags10.baseline @@ -0,0 +1,29 @@ +/** + * @template T + * @extends {/**/Set} + */ +class A extends B { +} + + + Set + + + Set + + + @extends {Set} + + +/** + * @template T + * @extends {Set} + */ + + +/** + * @template T + * @extends {Set} + */ +class A extends B { +} \ No newline at end of file diff --git a/tests/baselines/reference/smartSelection_JSDocTags2.baseline b/tests/baselines/reference/smartSelection_JSDocTags2.baseline new file mode 100644 index 00000000000..8177bd36144 --- /dev/null +++ b/tests/baselines/reference/smartSelection_JSDocTags2.baseline @@ -0,0 +1,21 @@ +/** + * @type {/**/string} + */ +const foo; + + + string + + + @type {string} + + +/** + * @type {string} + */ + + +/** + * @type {string} + */ +const foo; \ No newline at end of file diff --git a/tests/baselines/reference/smartSelection_JSDocTags3.baseline b/tests/baselines/reference/smartSelection_JSDocTags3.baseline new file mode 100644 index 00000000000..d4c29c10733 --- /dev/null +++ b/tests/baselines/reference/smartSelection_JSDocTags3.baseline @@ -0,0 +1,21 @@ +/** + * @param {/**/string} x + */ +function foo(x) {} + + + string + + + @param {string} x + + +/** + * @param {string} x + */ + + +/** + * @param {string} x + */ +function foo(x) {} \ No newline at end of file diff --git a/tests/baselines/reference/smartSelection_JSDocTags4.baseline b/tests/baselines/reference/smartSelection_JSDocTags4.baseline new file mode 100644 index 00000000000..7a82e42bd48 --- /dev/null +++ b/tests/baselines/reference/smartSelection_JSDocTags4.baseline @@ -0,0 +1,34 @@ +/** + * @typedef {object} Foo + * @property {string} a + * @property {number} b + * @property {/**/number} c + */ + +/** @type {Foo} */ +const foo; + + + number + + + @property {number} c + + +/** + * @typedef {object} Foo + * @property {string} a + * @property {number} b + * @property {number} c + */ + + +/** + * @typedef {object} Foo + * @property {string} a + * @property {number} b + * @property {number} c + */ + +/** @type {Foo} */ +const foo; \ No newline at end of file diff --git a/tests/baselines/reference/smartSelection_JSDocTags5.baseline b/tests/baselines/reference/smartSelection_JSDocTags5.baseline new file mode 100644 index 00000000000..2d1913987d2 --- /dev/null +++ b/tests/baselines/reference/smartSelection_JSDocTags5.baseline @@ -0,0 +1,34 @@ +/** + * @callback Foo + * @param {string} data + * @param {/**/number} [index] - comment + * @return {boolean} + */ + +/** @type {Foo} */ +const foo = s => !(s.length % 2); + + + number + + + @param {number} [index] - comment + + +/** + * @callback Foo + * @param {string} data + * @param {number} [index] - comment + * @return {boolean} + */ + + +/** + * @callback Foo + * @param {string} data + * @param {number} [index] - comment + * @return {boolean} + */ + +/** @type {Foo} */ +const foo = s => !(s.length % 2); \ No newline at end of file diff --git a/tests/baselines/reference/smartSelection_JSDocTags6.baseline b/tests/baselines/reference/smartSelection_JSDocTags6.baseline new file mode 100644 index 00000000000..5475ba42b45 --- /dev/null +++ b/tests/baselines/reference/smartSelection_JSDocTags6.baseline @@ -0,0 +1,31 @@ +/** + * @template T + * @param {/**/T} x + * @return {T} + */ +function foo(x) { + return x; +} + + + T + + + @param {T} x + + +/** + * @template T + * @param {T} x + * @return {T} + */ + + +/** + * @template T + * @param {T} x + * @return {T} + */ +function foo(x) { + return x; +} \ No newline at end of file diff --git a/tests/baselines/reference/smartSelection_JSDocTags7.baseline b/tests/baselines/reference/smartSelection_JSDocTags7.baseline new file mode 100644 index 00000000000..2e67e7f5d04 --- /dev/null +++ b/tests/baselines/reference/smartSelection_JSDocTags7.baseline @@ -0,0 +1,26 @@ +/** + * @constructor + * @param {/**/number} data + */ +function Foo(data) { +} + + + number + + + @param {number} data + + +/** + * @constructor + * @param {number} data + */ + + +/** + * @constructor + * @param {number} data + */ +function Foo(data) { +} \ No newline at end of file diff --git a/tests/baselines/reference/smartSelection_JSDocTags8.baseline b/tests/baselines/reference/smartSelection_JSDocTags8.baseline new file mode 100644 index 00000000000..4c50de4c099 --- /dev/null +++ b/tests/baselines/reference/smartSelection_JSDocTags8.baseline @@ -0,0 +1,55 @@ +/** + * @this {/**/Foo} + * @param {*} e + */ +function callback(e) { +} + + + Foo + + + @this {Foo} + + +/** + * @this {Foo} + * @param {*} e + */ + + +/** + * @this {Foo} + * @param {*} e + */ +function callback(e) { +} + +================================================================================ + +/** + * @this {Foo} + * @param {/**/*} e + */ +function callback(e) { +} + + + * + + + @param {*} e + + +/** + * @this {Foo} + * @param {*} e + */ + + +/** + * @this {Foo} + * @param {*} e + */ +function callback(e) { +} \ No newline at end of file diff --git a/tests/baselines/reference/smartSelection_JSDocTags9.baseline b/tests/baselines/reference/smartSelection_JSDocTags9.baseline new file mode 100644 index 00000000000..0d4bdc8eced --- /dev/null +++ b/tests/baselines/reference/smartSelection_JSDocTags9.baseline @@ -0,0 +1,21 @@ +/** @enum {/**/number} */ +const Foo = { + x: 0, + y: 1, +}; + + + number + + + @enum {number} + + +/** @enum {number} */ + + +/** @enum {number} */ +const Foo = { + x: 0, + y: 1, +}; \ No newline at end of file diff --git a/tests/cases/fourslash/smartSelection_JSDocTags1.ts b/tests/cases/fourslash/smartSelection_JSDocTags1.ts new file mode 100644 index 00000000000..56b8600470b --- /dev/null +++ b/tests/cases/fourslash/smartSelection_JSDocTags1.ts @@ -0,0 +1,8 @@ +/// + +/////** +//// * @returns {Array<{ value: /**/string }>} +//// */ +////function foo() { return [] } + +verify.baselineSmartSelection(); diff --git a/tests/cases/fourslash/smartSelection_JSDocTags10.ts b/tests/cases/fourslash/smartSelection_JSDocTags10.ts new file mode 100644 index 00000000000..d415e908089 --- /dev/null +++ b/tests/cases/fourslash/smartSelection_JSDocTags10.ts @@ -0,0 +1,11 @@ +/// + + +/////** +//// * @template T +//// * @extends {/**/Set} +//// */ +////class A extends B { +////} + +verify.baselineSmartSelection(); diff --git a/tests/cases/fourslash/smartSelection_JSDocTags2.ts b/tests/cases/fourslash/smartSelection_JSDocTags2.ts new file mode 100644 index 00000000000..4fbad7d983f --- /dev/null +++ b/tests/cases/fourslash/smartSelection_JSDocTags2.ts @@ -0,0 +1,8 @@ +/// + +/////** +//// * @type {/**/string} +//// */ +////const foo; + +verify.baselineSmartSelection(); diff --git a/tests/cases/fourslash/smartSelection_JSDocTags3.ts b/tests/cases/fourslash/smartSelection_JSDocTags3.ts new file mode 100644 index 00000000000..c619c16eed8 --- /dev/null +++ b/tests/cases/fourslash/smartSelection_JSDocTags3.ts @@ -0,0 +1,8 @@ +/// + +/////** +//// * @param {/**/string} x +//// */ +////function foo(x) {} + +verify.baselineSmartSelection(); diff --git a/tests/cases/fourslash/smartSelection_JSDocTags4.ts b/tests/cases/fourslash/smartSelection_JSDocTags4.ts new file mode 100644 index 00000000000..6fc47e1edfd --- /dev/null +++ b/tests/cases/fourslash/smartSelection_JSDocTags4.ts @@ -0,0 +1,13 @@ +/// + +/////** +//// * @typedef {object} Foo +//// * @property {string} a +//// * @property {number} b +//// * @property {/**/number} c +//// */ +//// +/////** @type {Foo} */ +////const foo; + +verify.baselineSmartSelection(); diff --git a/tests/cases/fourslash/smartSelection_JSDocTags5.ts b/tests/cases/fourslash/smartSelection_JSDocTags5.ts new file mode 100644 index 00000000000..7af815f587a --- /dev/null +++ b/tests/cases/fourslash/smartSelection_JSDocTags5.ts @@ -0,0 +1,13 @@ +/// + +/////** +//// * @callback Foo +//// * @param {string} data +//// * @param {/**/number} [index] - comment +//// * @return {boolean} +//// */ +//// +/////** @type {Foo} */ +////const foo = s => !(s.length % 2); + +verify.baselineSmartSelection(); diff --git a/tests/cases/fourslash/smartSelection_JSDocTags6.ts b/tests/cases/fourslash/smartSelection_JSDocTags6.ts new file mode 100644 index 00000000000..ccb9ca6237b --- /dev/null +++ b/tests/cases/fourslash/smartSelection_JSDocTags6.ts @@ -0,0 +1,12 @@ +/// + +/////** +//// * @template T +//// * @param {/**/T} x +//// * @return {T} +//// */ +////function foo(x) { +//// return x; +////} + +verify.baselineSmartSelection(); diff --git a/tests/cases/fourslash/smartSelection_JSDocTags7.ts b/tests/cases/fourslash/smartSelection_JSDocTags7.ts new file mode 100644 index 00000000000..f196400ff16 --- /dev/null +++ b/tests/cases/fourslash/smartSelection_JSDocTags7.ts @@ -0,0 +1,10 @@ +/// + +/////** +//// * @constructor +//// * @param {/**/number} data +//// */ +////function Foo(data) { +////} + +verify.baselineSmartSelection(); diff --git a/tests/cases/fourslash/smartSelection_JSDocTags8.ts b/tests/cases/fourslash/smartSelection_JSDocTags8.ts new file mode 100644 index 00000000000..0ba3b13b9ef --- /dev/null +++ b/tests/cases/fourslash/smartSelection_JSDocTags8.ts @@ -0,0 +1,10 @@ +/// + +/////** +//// * @this {/*1*/Foo} +//// * @param {/*2*/*} e +//// */ +////function callback(e) { +////} + +verify.baselineSmartSelection(); diff --git a/tests/cases/fourslash/smartSelection_JSDocTags9.ts b/tests/cases/fourslash/smartSelection_JSDocTags9.ts new file mode 100644 index 00000000000..a381d4341da --- /dev/null +++ b/tests/cases/fourslash/smartSelection_JSDocTags9.ts @@ -0,0 +1,9 @@ +/// + +/////** @enum {/**/number} */ +////const Foo = { +//// x: 0, +//// y: 1, +////}; + +verify.baselineSmartSelection();