diff --git a/changelog_unreleased/javascript/12070.md b/changelog_unreleased/javascript/12070.md new file mode 100644 index 000000000..66bf7183e --- /dev/null +++ b/changelog_unreleased/javascript/12070.md @@ -0,0 +1,17 @@ +#### Print comments for parenthesized TS keyword types with `babel-ts` parser (#12070 by @sosukesuzuki) + + +```ts +// Input +let foo: ( + // comment + never +); + +// Prettier stable +Error: Comment "comment" was not printed. Please report this error! + +// Prettier main +let foo: // comment +never; +``` diff --git a/src/language-html/ast.js b/src/language-html/ast.js index cf67d691a..913960a17 100644 --- a/src/language-html/ast.js +++ b/src/language-html/ast.js @@ -26,11 +26,13 @@ class Node { if (nodes !== this[key]) { this[key] = cloneAndUpdateNodes(nodes, this); if (key === "attrs") { - setNonEnumerableProperties(this, { - attrMap: Object.fromEntries( + setNonEnumerableProperty( + this, + "attrMap", + Object.fromEntries( this[key].map((attr) => [attr.fullName, attr.value]) - ), - }); + ) + ); } } } @@ -45,7 +47,8 @@ class Node { const mappedNodes = mapNodesIfChanged(nodes, (node) => node.map(fn)); if (newNode !== nodes) { if (!newNode) { - newNode = new Node(); + // @ts-expect-error + newNode = new Node({ parent: this.parent }); } newNode._setNodes(NODES_KEY, mappedNodes); } @@ -58,15 +61,6 @@ class Node { newNode[key] = this[key]; } } - // @ts-expect-error - const { index, siblings, prev, next, parent } = this; - setNonEnumerableProperties(newNode, { - index, - siblings, - prev, - next, - parent, - }); } return fn(newNode || this); @@ -85,10 +79,37 @@ class Node { } /** - * @param {Object} [overrides] + * @param {Node} [target] + * @param {Object} [node] */ - clone(overrides) { - return new Node(overrides ? { ...this, ...overrides } : this); + insertChildBefore(target, node) { + const newNode = new Node({ ...node, parent: this }); + + // @ts-expect-error + this.children.splice(this.children.indexOf(target), 0, newNode); + } + + /** + * @param {Node} [child] + */ + removeChild(child) { + // @ts-expect-error + this.children.splice(this.children.indexOf(child), 1); + } + + /** + * @param {Node} [target] + * @param {Object} [node] + */ + replaceChild(target, node) { + const newNode = new Node({ ...node, parent: this }); + + // @ts-expect-error + this.children[this.children.indexOf(target)] = newNode; + } + + clone() { + return new Node(this); } /** @@ -108,6 +129,24 @@ class Node { return isNonEmptyArray(this.children) ? getLast(this.children) : null; } + get prev() { + // @ts-expect-error + if (!this.parent) { + return null; + } + // @ts-expect-error + return this.parent.children[this.parent.children.indexOf(this) - 1]; + } + + get next() { + // @ts-expect-error + if (!this.parent) { + return null; + } + // @ts-expect-error + return this.parent.children[this.parent.children.indexOf(this) + 1]; + } + // for element and attribute get rawName() { // @ts-expect-error @@ -128,38 +167,18 @@ function mapNodesIfChanged(nodes, fn) { function cloneAndUpdateNodes(nodes, parent) { const siblings = nodes.map((node) => - node instanceof Node ? node.clone() : new Node(node) + node instanceof Node ? node.clone() : new Node({ ...node, parent }) ); - let prev = null; - let current = siblings[0]; - let next = siblings[1] || null; - - for (let index = 0; index < siblings.length; index++) { - setNonEnumerableProperties(current, { - index, - siblings, - prev, - next, - parent, - }); - prev = current; - current = next; - next = siblings[index + 2] || null; + for (const sibling of siblings) { + sibling.parent = parent; } return siblings; } -function setNonEnumerableProperties(obj, props) { - const descriptors = Object.fromEntries( - Object.entries(props).map(([key, value]) => [ - key, - { value, enumerable: false }, - ]) - ); - - Object.defineProperties(obj, descriptors); +function setNonEnumerableProperty(obj, key, value) { + Object.defineProperty(obj, key, { value, enumerable: false }); } module.exports = { diff --git a/src/language-html/clean.js b/src/language-html/clean.js index fbfc73f2e..2d316486d 100644 --- a/src/language-html/clean.js +++ b/src/language-html/clean.js @@ -8,6 +8,7 @@ const ignoredProperties = new Set([ "endSourceSpan", "nameSpan", "valueSpan", + "parent", ]); function clean(ast, newNode) { diff --git a/src/language-html/parser-html.js b/src/language-html/parser-html.js index 54bf9c2e3..dd5c1e968 100644 --- a/src/language-html/parser-html.js +++ b/src/language-html/parser-html.js @@ -334,13 +334,16 @@ function _parse(text, options, parserOptions, shouldParseFrontMatter = true) { parserOptions, false ); + // @ts-expect-error subAst.sourceSpan = new ParseSourceSpan( startSpan, + // @ts-expect-error getLast(subAst.children).sourceSpan.end ); + // @ts-expect-error const firstText = subAst.children[0]; if (firstText.length === offset) { - /* istanbul ignore next */ + /* istanbul ignore next */ // @ts-expect-error subAst.children.shift(); } else { firstText.sourceSpan = new ParseSourceSpan( @@ -352,19 +355,19 @@ function _parse(text, options, parserOptions, shouldParseFrontMatter = true) { return subAst; }; - return ast.map((node) => { + ast.walk((node) => { if (node.type === "comment") { const ieConditionalComment = parseIeConditionalComment( node, parseSubHtml ); if (ieConditionalComment) { - return ieConditionalComment; + node.parent.replaceChild(node, ieConditionalComment); } } - - return node; }); + + return ast; } /** diff --git a/src/language-html/print-preprocess.js b/src/language-html/print-preprocess.js index 969e75372..a9c01d006 100644 --- a/src/language-html/print-preprocess.js +++ b/src/language-html/print-preprocess.js @@ -3,7 +3,6 @@ const { ParseSourceSpan, } = require("angular-html-parser/lib/compiler/src/parse_util"); -const getLast = require("../utils/get-last.js"); const { htmlTrim, getLeadingAndTrailingHtmlWhitespace, @@ -31,11 +30,10 @@ const PREPROCESS_PIPELINE = [ ]; function preprocess(ast, options) { - const res = ast.map((node) => node); for (const fn of PREPROCESS_PIPELINE) { - fn(res, options); + fn(ast, options); } - return res; + return ast; } function removeIgnorableFirstLf(ast /*, options */) { @@ -47,12 +45,12 @@ function removeIgnorableFirstLf(ast /*, options */) { node.children[0].type === "text" && node.children[0].value[0] === "\n" ) { - const [text, ...rest] = node.children; - node.setChildren( - text.value.length === 1 - ? rest - : [text.clone({ value: text.value.slice(1) }), ...rest] - ); + const text = node.children[0]; + if (text.value.length === 1) { + node.removeChild(text); + } else { + text.value = text.value.slice(1); + } } }); } @@ -73,47 +71,32 @@ function mergeIfConditionalStartEndCommentIntoElementOpeningTag( node.firstChild.sourceSpan.start.offset === node.startSourceSpan.end.offset; ast.walk((node) => { if (node.children) { - const isTargetResults = node.children.map(isTarget); - if (isTargetResults.some(Boolean)) { - const newChildren = []; - - for (let i = 0; i < node.children.length; i++) { - const child = node.children[i]; - - if (isTargetResults[i + 1]) { - // ieConditionalStartComment - continue; - } - - if (isTargetResults[i]) { - const ieConditionalStartComment = child.prev; - const ieConditionalEndComment = child.firstChild; - - const startSourceSpan = new ParseSourceSpan( - ieConditionalStartComment.sourceSpan.start, - ieConditionalEndComment.sourceSpan.end - ); - const sourceSpan = new ParseSourceSpan( - startSourceSpan.start, - child.sourceSpan.end - ); - - newChildren.push( - child.clone({ - condition: ieConditionalStartComment.condition, - sourceSpan, - startSourceSpan, - children: child.children.slice(1), - }) - ); - - continue; - } - - newChildren.push(child); + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + if (!isTarget(child)) { + continue; } - node.setChildren(newChildren); + const ieConditionalStartComment = child.prev; + const ieConditionalEndComment = child.firstChild; + + // ieConditionalStartComment + node.removeChild(ieConditionalStartComment); + i--; // because a node was removed + + const startSourceSpan = new ParseSourceSpan( + ieConditionalStartComment.sourceSpan.start, + ieConditionalEndComment.sourceSpan.end + ); + const sourceSpan = new ParseSourceSpan( + startSourceSpan.start, + child.sourceSpan.end + ); + + child.condition = ieConditionalStartComment.condition; + child.sourceSpan = sourceSpan; + child.startSourceSpan = startSourceSpan; + child.removeChild(ieConditionalEndComment); } } }); @@ -122,42 +105,31 @@ function mergeIfConditionalStartEndCommentIntoElementOpeningTag( function mergeNodeIntoText(ast, shouldMerge, getValue) { ast.walk((node) => { if (node.children) { - const shouldMergeResults = node.children.map(shouldMerge); - if (shouldMergeResults.some(Boolean)) { - const newChildren = []; - for (let i = 0; i < node.children.length; i++) { - const child = node.children[i]; + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; - if (child.type !== "text" && !shouldMergeResults[i]) { - newChildren.push(child); - continue; - } - - const newChild = - child.type === "text" - ? child - : child.clone({ type: "text", value: getValue(child) }); - - if ( - newChildren.length === 0 || - getLast(newChildren).type !== "text" - ) { - newChildren.push(newChild); - continue; - } - - const lastChild = newChildren.pop(); - newChildren.push( - lastChild.clone({ - value: lastChild.value + newChild.value, - sourceSpan: new ParseSourceSpan( - lastChild.sourceSpan.start, - newChild.sourceSpan.end - ), - }) - ); + if (child.type !== "text" && !shouldMerge(child)) { + continue; } - node.setChildren(newChildren); + + if (child.type !== "text") { + child.type = "text"; + child.value = getValue(child); + } + + const prevChild = child.prev; + if (!prevChild || prevChild.type !== "text") { + continue; + } + + prevChild.value += child.value; + prevChild.sourceSpan = new ParseSourceSpan( + prevChild.sourceSpan.start, + child.sourceSpan.end + ); + + node.removeChild(child); + i--; // because a node was removed } } }); @@ -190,36 +162,29 @@ function mergeSimpleElementIntoText(ast /*, options */) { node.next.type === "text"; ast.walk((node) => { if (node.children) { - const isSimpleElementResults = node.children.map(isSimpleElement); - if (isSimpleElementResults.some(Boolean)) { - const newChildren = []; - for (let i = 0; i < node.children.length; i++) { - const child = node.children[i]; - if (isSimpleElementResults[i]) { - const lastChild = newChildren.pop(); - const nextChild = node.children[++i]; - const { isTrailingSpaceSensitive, hasTrailingSpaces } = nextChild; - newChildren.push( - lastChild.clone({ - value: - lastChild.value + - `<${child.rawName}>` + - child.firstChild.value + - `` + - nextChild.value, - sourceSpan: new ParseSourceSpan( - lastChild.sourceSpan.start, - nextChild.sourceSpan.end - ), - isTrailingSpaceSensitive, - hasTrailingSpaces, - }) - ); - } else { - newChildren.push(child); - } + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + if (!isSimpleElement(child)) { + continue; } - node.setChildren(newChildren); + + const prevChild = child.prev; + const nextChild = child.next; + prevChild.value += + `<${child.rawName}>` + + child.firstChild.value + + `` + + nextChild.value; + prevChild.sourceSpan = new ParseSourceSpan( + prevChild.sourceSpan.start, + nextChild.sourceSpan.end + ); + prevChild.isTrailingSpaceSensitive = nextChild.isTrailingSpaceSensitive; + prevChild.hasTrailingSpaces = nextChild.hasTrailingSpaces; + + node.removeChild(child); + i--; // because a node was removed + node.removeChild(nextChild); } } }); @@ -236,11 +201,8 @@ function extractInterpolation(ast, options) { return; } - const newChildren = []; - for (const child of node.children) { if (child.type !== "text") { - newChildren.push(child); continue; } @@ -257,7 +219,7 @@ function extractInterpolation(ast, options) { if (i % 2 === 0) { endSourceSpan = startSourceSpan.moveBy(value.length); if (value.length > 0) { - newChildren.push({ + node.insertChildBefore(child, { type: "text", value, sourceSpan: new ParseSourceSpan(startSourceSpan, endSourceSpan), @@ -267,7 +229,7 @@ function extractInterpolation(ast, options) { } endSourceSpan = startSourceSpan.moveBy(value.length + 4); // `{{` + `}}` - newChildren.push({ + node.insertChildBefore(child, { type: "interpolation", sourceSpan: new ParseSourceSpan(startSourceSpan, endSourceSpan), children: @@ -285,9 +247,9 @@ function extractInterpolation(ast, options) { ], }); } - } - node.setChildren(newChildren); + node.removeChild(child); + } }); } @@ -298,7 +260,6 @@ function extractInterpolation(ast, options) { * - add `isWhitespaceSensitive`, `isIndentationSensitive` field for text nodes * - remove insensitive whitespaces */ -const WHITESPACE_NODE = { type: "whitespace" }; function extractWhitespaces(ast /*, options*/) { ast.walk((node) => { if (!node.children) { @@ -319,94 +280,91 @@ function extractWhitespaces(ast /*, options*/) { const isWhitespaceSensitive = isWhitespaceSensitiveNode(node); const isIndentationSensitive = isIndentationSensitiveNode(node); - node.setChildren( - node.children - // extract whitespace nodes - .flatMap((child) => { - if (child.type !== "text" || isWhitespaceSensitive) { - return child; + if (!isWhitespaceSensitive) { + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + if (child.type !== "text") { + continue; + } + + const { leadingWhitespace, text, trailingWhitespace } = + getLeadingAndTrailingHtmlWhitespace(child.value); + + const prevChild = child.prev; + const nextChild = child.next; + + if (!text) { + node.removeChild(child); + i--; // because a node was removed + + if (leadingWhitespace || trailingWhitespace) { + if (prevChild) { + prevChild.hasTrailingSpaces = true; + } + if (nextChild) { + nextChild.hasLeadingSpaces = true; + } } - - const localChildren = []; - - const { leadingWhitespace, text, trailingWhitespace } = - getLeadingAndTrailingHtmlWhitespace(child.value); + } else { + child.value = text; + child.sourceSpan = new ParseSourceSpan( + child.sourceSpan.start.moveBy(leadingWhitespace.length), + child.sourceSpan.end.moveBy(-trailingWhitespace.length) + ); if (leadingWhitespace) { - localChildren.push(WHITESPACE_NODE); + if (prevChild) { + prevChild.hasTrailingSpaces = true; + } + child.hasLeadingSpaces = true; } - - if (text) { - localChildren.push({ - type: "text", - value: text, - sourceSpan: new ParseSourceSpan( - child.sourceSpan.start.moveBy(leadingWhitespace.length), - child.sourceSpan.end.moveBy(-trailingWhitespace.length) - ), - }); - } - if (trailingWhitespace) { - localChildren.push(WHITESPACE_NODE); + child.hasTrailingSpaces = true; + if (nextChild) { + nextChild.hasLeadingSpaces = true; + } } + } + } + } - return localChildren; - }) - // set hasLeadingSpaces/hasTrailingSpaces - .map((child, index, children) => { - if (child === WHITESPACE_NODE) { - return; - } - - return { - ...child, - hasLeadingSpaces: children[index - 1] === WHITESPACE_NODE, - hasTrailingSpaces: children[index + 1] === WHITESPACE_NODE, - }; - }) - // filter whitespace nodes - .filter(Boolean) - ); node.isWhitespaceSensitive = isWhitespaceSensitive; node.isIndentationSensitive = isIndentationSensitive; }); } function addIsSelfClosing(ast /*, options */) { - ast.walk((node) => - Object.assign(node, { - isSelfClosing: - !node.children || - (node.type === "element" && - (node.tagDefinition.isVoid || - // self-closing - node.startSourceSpan === node.endSourceSpan)), - }) - ); + ast.walk((node) => { + node.isSelfClosing = + !node.children || + (node.type === "element" && + (node.tagDefinition.isVoid || + // self-closing + node.startSourceSpan === node.endSourceSpan)); + }); } function addHasHtmComponentClosingTag(ast, options) { - ast.walk((node) => - node.type !== "element" - ? node - : Object.assign(node, { - hasHtmComponentClosingTag: - node.endSourceSpan && - /^<\s*\/\s*\/\s*>$/.test( - options.originalText.slice( - node.endSourceSpan.start.offset, - node.endSourceSpan.end.offset - ) - ), - }) - ); + ast.walk((node) => { + if (node.type !== "element") { + return; + } + + node.hasHtmComponentClosingTag = + node.endSourceSpan && + /^<\s*\/\s*\/\s*>$/.test( + options.originalText.slice( + node.endSourceSpan.start.offset, + node.endSourceSpan.end.offset + ) + ); + }); } function addCssDisplay(ast, options) { - ast.walk((node) => - Object.assign(node, { cssDisplay: getNodeCssStyleDisplay(node, options) }) - ); + ast.walk((node) => { + node.cssDisplay = getNodeCssStyleDisplay(node, options); + }); } /** @@ -416,39 +374,37 @@ function addCssDisplay(ast, options) { */ function addIsSpaceSensitive(ast, options) { ast.walk((node) => { - if (!node.children) { + const { children } = node; + if (!children) { return; } - - if (node.children.length === 0) { + if (children.length === 0) { node.isDanglingSpaceSensitive = isDanglingSpaceSensitiveNode(node); return; } - - node.setChildren( - node.children - .map((child) => ({ - ...child, - isLeadingSpaceSensitive: isLeadingSpaceSensitiveNode(child, options), - isTrailingSpaceSensitive: isTrailingSpaceSensitiveNode( - child, - options - ), - })) - .map((child, index, children) => ({ - ...child, - isLeadingSpaceSensitive: - index === 0 - ? child.isLeadingSpaceSensitive - : children[index - 1].isTrailingSpaceSensitive && - child.isLeadingSpaceSensitive, - isTrailingSpaceSensitive: - index === children.length - 1 - ? child.isTrailingSpaceSensitive - : children[index + 1].isLeadingSpaceSensitive && - child.isTrailingSpaceSensitive, - })) - ); + for (const child of children) { + child.isLeadingSpaceSensitive = isLeadingSpaceSensitiveNode( + child, + options + ); + child.isTrailingSpaceSensitive = isTrailingSpaceSensitiveNode( + child, + options + ); + } + for (let index = 0; index < children.length; index++) { + const child = children[index]; + child.isLeadingSpaceSensitive = + index === 0 + ? child.isLeadingSpaceSensitive + : child.prev.isTrailingSpaceSensitive && + child.isLeadingSpaceSensitive; + child.isTrailingSpaceSensitive = + index === children.length - 1 + ? child.isTrailingSpaceSensitive + : child.next.isLeadingSpaceSensitive && + child.isTrailingSpaceSensitive; + } }); } diff --git a/src/language-html/utils.js b/src/language-html/utils.js index 5d9e822d9..4696285d5 100644 --- a/src/language-html/utils.js +++ b/src/language-html/utils.js @@ -113,12 +113,11 @@ function hasPrettierIgnore(node) { return false; } - if (typeof node.index !== "number" || node.index === 0) { + if (!node.prev) { return false; } - const prevNode = node.parent.children[node.index - 1]; - return isPrettierIgnore(prevNode); + return isPrettierIgnore(node.prev); } function isPrettierIgnore(node) { diff --git a/src/language-js/parse/postprocess/index.js b/src/language-js/parse/postprocess/index.js index bf01da5eb..97c543a38 100644 --- a/src/language-js/parse/postprocess/index.js +++ b/src/language-js/parse/postprocess/index.js @@ -3,6 +3,7 @@ const { getLast } = require("../../../common/util.js"); const { locStart, locEnd } = require("../../loc.js"); const { isTypeCastComment } = require("../../comments.js"); +const { isTsKeywordType } = require("../../utils.js"); const visitNode = require("./visitNode.js"); const { throwErrorForInvalidNodes } = require("./typescript.js"); @@ -79,7 +80,14 @@ function postprocess(ast, options) { } // remove redundant TypeScript nodes case "TSParenthesizedType": { - node.typeAnnotation.range = [locStart(node), locEnd(node)]; + if ( + !( + isTsKeywordType(node.typeAnnotation) || + node.typeAnnotation.type === "TSThisType" + ) + ) { + node.typeAnnotation.range = [locStart(node), locEnd(node)]; + } return node.typeAnnotation; } case "TSTypeParameter": diff --git a/src/language-js/print/typescript.js b/src/language-js/print/typescript.js index 9d5547775..693ffcd8a 100644 --- a/src/language-js/print/typescript.js +++ b/src/language-js/print/typescript.js @@ -20,6 +20,7 @@ const { shouldPrintComma, isCallExpression, isMemberExpression, + isTsKeywordType, } = require("../utils.js"); const { locStart, locEnd } = require("../loc.js"); @@ -58,7 +59,7 @@ function printTypescript(path, options, print) { return; } - if (node.type.endsWith("Keyword")) { + if (isTsKeywordType(node)) { return node.type.slice(2, -7).toLowerCase(); } diff --git a/src/language-js/utils.js b/src/language-js/utils.js index 693e52b80..ccb5f4add 100644 --- a/src/language-js/utils.js +++ b/src/language-js/utils.js @@ -1322,6 +1322,10 @@ const markerForIfWithoutBlockAndSameLineComment = Symbol( "ifWithoutBlockAndSameLineComment" ); +function isTsKeywordType({ type }) { + return type.startsWith("TS") && type.endsWith("Keyword"); +} + module.exports = { getFunctionParameters, iterateFunctionParametersPath, @@ -1387,4 +1391,5 @@ module.exports = { getComments, CommentCheckFlags, markerForIfWithoutBlockAndSameLineComment, + isTsKeywordType, }; diff --git a/src/main/comments.js b/src/main/comments.js index 2562cf260..77d961586 100644 --- a/src/main/comments.js +++ b/src/main/comments.js @@ -55,7 +55,8 @@ function getSortedChildNodes(node, options, resultArray) { key !== "precedingNode" && key !== "followingNode" && key !== "tokens" && - key !== "comments" + key !== "comments" && + key !== "parent" ) .map(([, value]) => value)); diff --git a/tests/format/typescript/keyword-types/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/keyword-types/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000..8f2097f3b --- /dev/null +++ b/tests/format/typescript/keyword-types/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,125 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`conditional-types.ts format 1`] = ` +====================================options===================================== +parsers: ["typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +export type UnwrappedResultRow = { + [P in keyof T]: ( + T[P] extends Req ? ( + a + ) : ( + T[P] extends Opt ? ( + b + ) : ( + // TEST + never + ) + ) + ); +}; + +=====================================output===================================== +export type UnwrappedResultRow = { + [P in keyof T]: T[P] extends Req + ? a + : T[P] extends Opt + ? b + : // TEST + never; +}; + +================================================================================ +`; + +exports[`keyword-types-with-parens-comments.ts format 1`] = ` +====================================options===================================== +parsers: ["typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +let foo: ( + // comment + any +); +let foo: ( + // comment + null +); +let foo: ( + // comment + this +); +let foo: ( + // comment + number +); +let foo: ( + // comment + void +); +let foo: ( + // comment + boolean +); +let foo: ( + // comment + bigint +); +let foo: ( + // comment + symbol +); +let foo: ( + // comment + string +); +let foo: ( + // comment + never +); +let foo: ( + // comment + object +); +let foo: ( + // comment + undefined +); +let foo: ( + // comment + unknown +); + +=====================================output===================================== +let foo: // comment +any; +let foo: // comment +null; +let foo: // comment +this; +let foo: // comment +number; +let foo: // comment +void; +let foo: // comment +boolean; +let foo: // comment +bigint; +let foo: // comment +symbol; +let foo: // comment +string; +let foo: // comment +never; +let foo: // comment +object; +let foo: // comment +undefined; +let foo: // comment +unknown; + +================================================================================ +`; diff --git a/tests/format/typescript/keyword-types/conditional-types.ts b/tests/format/typescript/keyword-types/conditional-types.ts new file mode 100644 index 000000000..96aef0495 --- /dev/null +++ b/tests/format/typescript/keyword-types/conditional-types.ts @@ -0,0 +1,14 @@ +export type UnwrappedResultRow = { + [P in keyof T]: ( + T[P] extends Req ? ( + a + ) : ( + T[P] extends Opt ? ( + b + ) : ( + // TEST + never + ) + ) + ); +}; diff --git a/tests/format/typescript/keyword-types/jsfmt.spec.js b/tests/format/typescript/keyword-types/jsfmt.spec.js new file mode 100644 index 000000000..2ea3bb6eb --- /dev/null +++ b/tests/format/typescript/keyword-types/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname, ["typescript"]); diff --git a/tests/format/typescript/keyword-types/keyword-types-with-parens-comments.ts b/tests/format/typescript/keyword-types/keyword-types-with-parens-comments.ts new file mode 100644 index 000000000..9587c0dbb --- /dev/null +++ b/tests/format/typescript/keyword-types/keyword-types-with-parens-comments.ts @@ -0,0 +1,52 @@ +let foo: ( + // comment + any +); +let foo: ( + // comment + null +); +let foo: ( + // comment + this +); +let foo: ( + // comment + number +); +let foo: ( + // comment + void +); +let foo: ( + // comment + boolean +); +let foo: ( + // comment + bigint +); +let foo: ( + // comment + symbol +); +let foo: ( + // comment + string +); +let foo: ( + // comment + never +); +let foo: ( + // comment + object +); +let foo: ( + // comment + undefined +); +let foo: ( + // comment + unknown +);