From 0e1db9fbcafe84256eb108b8fea06f407303c138 Mon Sep 17 00:00:00 2001 From: fisker Date: Thu, 19 Nov 2020 09:17:30 +0800 Subject: [PATCH 1/6] Extract printClass and printTypeParameters --- src/language-js/print/class.js | 131 ++++++++++++++ src/language-js/print/type-parameters.js | 99 +++++++++++ src/language-js/printer-estree.js | 211 +---------------------- 3 files changed, 235 insertions(+), 206 deletions(-) create mode 100644 src/language-js/print/class.js create mode 100644 src/language-js/print/type-parameters.js diff --git a/src/language-js/print/class.js b/src/language-js/print/class.js new file mode 100644 index 000000000000..16e7fc3298be --- /dev/null +++ b/src/language-js/print/class.js @@ -0,0 +1,131 @@ +"use strict"; + +const { printComments, printDanglingComments } = require("../../main/comments"); +const { + builders: { concat, join, line, hardline, softline, group, indent, ifBreak }, +} = require("../../document"); +const { hasTrailingComment, hasTrailingLineComment } = require("../utils"); +const { getTypeParametersGroupId } = require("./type-parameters"); + +function printClass(path, options, print) { + const n = path.getValue(); + const parts = []; + + if (n.abstract) { + parts.push("abstract "); + } + + parts.push("class"); + + // Keep old behaviour of extends in same line + // If there is only on extends and there are not comments + const groupMode = + (n.id && hasTrailingComment(n.id)) || + (n.superClass && + n.superClass.comments && + n.superClass.comments.length !== 0) || + (n.extends && n.extends.length !== 0) || // DeclareClass + (n.mixins && n.mixins.length !== 0) || + (n.implements && n.implements.length !== 0); + + const partsGroup = []; + const extendsParts = []; + + if (n.id) { + partsGroup.push(" ", path.call(print, "id")); + } + + partsGroup.push(path.call(print, "typeParameters")); + + const hasMultipleHeritage = + ["superClass", "extends", "mixins", "implements"].filter((key) => !!n[key]) + .length > 1; + const shouldIndentOnlyHeritageClauses = + n.typeParameters && + !hasTrailingLineComment(n.typeParameters) && + !hasMultipleHeritage; + + function printList(listName) { + if (n[listName] && n[listName].length !== 0) { + const printedLeadingComments = printDanglingComments( + path, + options, + /* sameIndent */ true, + ({ marker }) => marker === listName + ); + extendsParts.push( + shouldIndentOnlyHeritageClauses + ? ifBreak(" ", line, { + groupId: getTypeParametersGroupId(n.typeParameters), + }) + : line, + printedLeadingComments, + printedLeadingComments && hardline, + listName, + group( + indent( + concat([line, join(concat([",", line]), path.map(print, listName))]) + ) + ) + ); + } + } + + if (n.superClass) { + const printSuperClass = (path) => { + const printed = path.call(print, "superClass"); + const parent = path.getParentNode(); + if (parent && parent.type === "AssignmentExpression") { + return concat([ + ifBreak("("), + indent(concat([softline, printed])), + softline, + ifBreak(")"), + ]); + } + return printed; + }; + const printed = concat([ + "extends ", + printSuperClass(path), + path.call(print, "superTypeParameters"), + ]); + const printedWithComments = path.call( + (superClass) => printComments(superClass, () => printed, options), + "superClass" + ); + if (groupMode) { + extendsParts.push(line, group(printedWithComments)); + } else { + extendsParts.push(" ", printedWithComments); + } + } else { + printList("extends"); + } + + printList("mixins"); + printList("implements"); + + if (groupMode) { + const printedExtends = concat(extendsParts); + if (shouldIndentOnlyHeritageClauses) { + parts.push( + group( + concat( + partsGroup.concat(ifBreak(indent(printedExtends), printedExtends)) + ) + ) + ); + } else { + parts.push(group(indent(concat(partsGroup.concat(printedExtends))))); + } + } else { + parts.push(...partsGroup, ...extendsParts); + } + + parts.push(" ", path.call(print, "body")); + + return parts; +} + +module.exports = { printClass }; diff --git a/src/language-js/print/type-parameters.js b/src/language-js/print/type-parameters.js new file mode 100644 index 000000000000..6c3b1fa4988d --- /dev/null +++ b/src/language-js/print/type-parameters.js @@ -0,0 +1,99 @@ +"use strict"; + +const { printDanglingComments } = require("../../main/comments"); +const { + builders: { concat, join, line, hardline, softline, group, indent, ifBreak }, +} = require("../../document"); +const { + hasDanglingComments, + isTestCall, + isBlockComment, + shouldPrintComma, +} = require("../utils"); +const { shouldHugType } = require("./type-annotation"); + +const typeParametersGroupIds = new WeakMap(); +function getTypeParametersGroupId(node) { + if (!typeParametersGroupIds.has(node)) { + typeParametersGroupIds.set(node, Symbol("typeParameters")); + } + return typeParametersGroupIds.get(node); +} + +function printTypeParameters(path, options, print, paramsKey) { + const n = path.getValue(); + + if (!n[paramsKey]) { + return ""; + } + + // for TypeParameterDeclaration typeParameters is a single node + if (!Array.isArray(n[paramsKey])) { + return path.call(print, paramsKey); + } + + const grandparent = path.getNode(2); + const isParameterInTestCall = grandparent != null && isTestCall(grandparent); + + const shouldInline = + isParameterInTestCall || + n[paramsKey].length === 0 || + (n[paramsKey].length === 1 && + (shouldHugType(n[paramsKey][0]) || + (n[paramsKey][0].type === "GenericTypeAnnotation" && + shouldHugType(n[paramsKey][0].id)) || + (n[paramsKey][0].type === "TSTypeReference" && + shouldHugType(n[paramsKey][0].typeName)) || + n[paramsKey][0].type === "NullableTypeAnnotation")); + + function printDanglingCommentsForInline(n) { + if (!hasDanglingComments(n)) { + return ""; + } + const hasOnlyBlockComments = n.comments.every((comment) => + isBlockComment(comment) + ); + const printed = printDanglingComments( + path, + options, + /* sameIndent */ hasOnlyBlockComments + ); + if (hasOnlyBlockComments) { + return printed; + } + return concat([printed, hardline]); + } + + if (shouldInline) { + return concat([ + "<", + join(", ", path.map(print, paramsKey)), + printDanglingCommentsForInline(n), + ">", + ]); + } + + return group( + concat([ + "<", + indent( + concat([ + softline, + join(concat([",", line]), path.map(print, paramsKey)), + ]) + ), + ifBreak( + options.parser !== "typescript" && + options.parser !== "babel-ts" && + shouldPrintComma(options, "all") + ? "," + : "" + ), + softline, + ">", + ]), + { id: getTypeParametersGroupId(n) } + ); +} + +module.exports = { printTypeParameters, getTypeParametersGroupId }; diff --git a/src/language-js/printer-estree.js b/src/language-js/printer-estree.js index 073cc6baddda..b4b39a286bb1 100644 --- a/src/language-js/printer-estree.js +++ b/src/language-js/printer-estree.js @@ -126,6 +126,11 @@ const { printTypeAnnotation, shouldHugType, } = require("./print/type-annotation"); +const { printClass } = require("./print/class"); +const { + printTypeParameters, + getTypeParametersGroupId, +} = require("./print/type-parameters"); const needsQuoteProps = new WeakMap(); @@ -3428,212 +3433,6 @@ function printTypeScriptModifiers(path, options, print) { return concat([join(" ", path.map(print, "modifiers")), " "]); } -const typeParametersGroupIds = new WeakMap(); -function getTypeParametersGroupId(node) { - if (!typeParametersGroupIds.has(node)) { - typeParametersGroupIds.set(node, Symbol("typeParameters")); - } - return typeParametersGroupIds.get(node); -} - -function printTypeParameters(path, options, print, paramsKey) { - const n = path.getValue(); - - if (!n[paramsKey]) { - return ""; - } - - // for TypeParameterDeclaration typeParameters is a single node - if (!Array.isArray(n[paramsKey])) { - return path.call(print, paramsKey); - } - - const grandparent = path.getNode(2); - const isParameterInTestCall = grandparent != null && isTestCall(grandparent); - - const shouldInline = - isParameterInTestCall || - n[paramsKey].length === 0 || - (n[paramsKey].length === 1 && - (shouldHugType(n[paramsKey][0]) || - (n[paramsKey][0].type === "GenericTypeAnnotation" && - shouldHugType(n[paramsKey][0].id)) || - (n[paramsKey][0].type === "TSTypeReference" && - shouldHugType(n[paramsKey][0].typeName)) || - n[paramsKey][0].type === "NullableTypeAnnotation")); - - function printDanglingCommentsForInline(n) { - if (!hasDanglingComments(n)) { - return ""; - } - const hasOnlyBlockComments = n.comments.every((comment) => - isBlockComment(comment) - ); - const printed = comments.printDanglingComments( - path, - options, - /* sameIndent */ hasOnlyBlockComments - ); - if (hasOnlyBlockComments) { - return printed; - } - return concat([printed, hardline]); - } - - if (shouldInline) { - return concat([ - "<", - join(", ", path.map(print, paramsKey)), - printDanglingCommentsForInline(n), - ">", - ]); - } - - return group( - concat([ - "<", - indent( - concat([ - softline, - join(concat([",", line]), path.map(print, paramsKey)), - ]) - ), - ifBreak( - options.parser !== "typescript" && - options.parser !== "babel-ts" && - shouldPrintComma(options, "all") - ? "," - : "" - ), - softline, - ">", - ]), - { id: getTypeParametersGroupId(n) } - ); -} - -function printClass(path, options, print) { - const n = path.getValue(); - const parts = []; - - if (n.abstract) { - parts.push("abstract "); - } - - parts.push("class"); - - // Keep old behaviour of extends in same line - // If there is only on extends and there are not comments - const groupMode = - (n.id && hasTrailingComment(n.id)) || - (n.superClass && - n.superClass.comments && - n.superClass.comments.length !== 0) || - (n.extends && n.extends.length !== 0) || // DeclareClass - (n.mixins && n.mixins.length !== 0) || - (n.implements && n.implements.length !== 0); - - const partsGroup = []; - const extendsParts = []; - - if (n.id) { - partsGroup.push(" ", path.call(print, "id")); - } - - partsGroup.push(path.call(print, "typeParameters")); - - const hasMultipleHeritage = - ["superClass", "extends", "mixins", "implements"].filter((key) => !!n[key]) - .length > 1; - const shouldIndentOnlyHeritageClauses = - n.typeParameters && - !hasTrailingLineComment(n.typeParameters) && - !hasMultipleHeritage; - - function printList(listName) { - if (n[listName] && n[listName].length !== 0) { - const printedLeadingComments = comments.printDanglingComments( - path, - options, - /* sameIndent */ true, - ({ marker }) => marker === listName - ); - extendsParts.push( - shouldIndentOnlyHeritageClauses - ? ifBreak(" ", line, { - groupId: getTypeParametersGroupId(n.typeParameters), - }) - : line, - printedLeadingComments, - printedLeadingComments && hardline, - listName, - group( - indent( - concat([line, join(concat([",", line]), path.map(print, listName))]) - ) - ) - ); - } - } - - if (n.superClass) { - const printSuperClass = (path) => { - const printed = path.call(print, "superClass"); - const parent = path.getParentNode(); - if (parent && parent.type === "AssignmentExpression") { - return concat([ - ifBreak("("), - indent(concat([softline, printed])), - softline, - ifBreak(")"), - ]); - } - return printed; - }; - const printed = concat([ - "extends ", - printSuperClass(path), - path.call(print, "superTypeParameters"), - ]); - const printedWithComments = path.call( - (superClass) => - comments.printComments(superClass, () => printed, options), - "superClass" - ); - if (groupMode) { - extendsParts.push(line, group(printedWithComments)); - } else { - extendsParts.push(" ", printedWithComments); - } - } else { - printList("extends"); - } - - printList("mixins"); - printList("implements"); - - if (groupMode) { - const printedExtends = concat(extendsParts); - if (shouldIndentOnlyHeritageClauses) { - parts.push( - group( - concat( - partsGroup.concat(ifBreak(indent(printedExtends), printedExtends)) - ) - ) - ); - } else { - parts.push(group(indent(concat(partsGroup.concat(printedExtends))))); - } - } else { - parts.push(...partsGroup, ...extendsParts); - } - - parts.push(" ", path.call(print, "body")); - - return parts; -} - function separatorNoWhitespace( isFacebookTranslationTag, child, From 2b7b22e440bb535615c7c2d929c02a191dfd8ee2 Mon Sep 17 00:00:00 2001 From: fisker Date: Thu, 19 Nov 2020 09:29:39 +0800 Subject: [PATCH 2/6] Move functions to outer --- src/language-js/print/class.js | 114 +++++++++++++---------- src/language-js/print/type-parameters.js | 39 ++++---- 2 files changed, 83 insertions(+), 70 deletions(-) diff --git a/src/language-js/print/class.js b/src/language-js/print/class.js index 16e7fc3298be..5bd1cb195915 100644 --- a/src/language-js/print/class.js +++ b/src/language-js/print/class.js @@ -37,54 +37,7 @@ function printClass(path, options, print) { partsGroup.push(path.call(print, "typeParameters")); - const hasMultipleHeritage = - ["superClass", "extends", "mixins", "implements"].filter((key) => !!n[key]) - .length > 1; - const shouldIndentOnlyHeritageClauses = - n.typeParameters && - !hasTrailingLineComment(n.typeParameters) && - !hasMultipleHeritage; - - function printList(listName) { - if (n[listName] && n[listName].length !== 0) { - const printedLeadingComments = printDanglingComments( - path, - options, - /* sameIndent */ true, - ({ marker }) => marker === listName - ); - extendsParts.push( - shouldIndentOnlyHeritageClauses - ? ifBreak(" ", line, { - groupId: getTypeParametersGroupId(n.typeParameters), - }) - : line, - printedLeadingComments, - printedLeadingComments && hardline, - listName, - group( - indent( - concat([line, join(concat([",", line]), path.map(print, listName))]) - ) - ) - ); - } - } - if (n.superClass) { - const printSuperClass = (path) => { - const printed = path.call(print, "superClass"); - const parent = path.getParentNode(); - if (parent && parent.type === "AssignmentExpression") { - return concat([ - ifBreak("("), - indent(concat([softline, printed])), - softline, - ifBreak(")"), - ]); - } - return printed; - }; const printed = concat([ "extends ", printSuperClass(path), @@ -100,15 +53,15 @@ function printClass(path, options, print) { extendsParts.push(" ", printedWithComments); } } else { - printList("extends"); + extendsParts(printList(path, options, print, "extends")); } - printList("mixins"); - printList("implements"); + extendsParts(printList(path, options, print, "mixins")); + extendsParts(printList(path, options, print, "implements")); if (groupMode) { const printedExtends = concat(extendsParts); - if (shouldIndentOnlyHeritageClauses) { + if (shouldIndentOnlyHeritageClauses(n)) { parts.push( group( concat( @@ -128,4 +81,63 @@ function printClass(path, options, print) { return parts; } +function hasMultipleHeritage(node) { + return ( + ["superClass", "extends", "mixins", "implements"].filter( + (key) => !!node[key] + ).length > 1 + ); +} + +function shouldIndentOnlyHeritageClauses(node) { + return ( + node.typeParameters && + !hasTrailingLineComment(node.typeParameters) && + !hasMultipleHeritage(node) + ); +} + +function printList(path, options, print, listName) { + const n = path.getValue(); + if (!n[listName] || n[listName].length === 0) { + return ""; + } + + const printedLeadingComments = printDanglingComments( + path, + options, + /* sameIndent */ true, + ({ marker }) => marker === listName + ); + return ( + shouldIndentOnlyHeritageClauses(n) + ? ifBreak(" ", line, { + groupId: getTypeParametersGroupId(n.typeParameters), + }) + : line, + printedLeadingComments, + printedLeadingComments && hardline, + listName, + group( + indent( + concat([line, join(concat([",", line]), path.map(print, listName))]) + ) + ) + ); +} + +function printSuperClass(path, options, print) { + const printed = path.call(print, "superClass"); + const parent = path.getParentNode(); + if (parent && parent.type === "AssignmentExpression") { + return concat([ + ifBreak("("), + indent(concat([softline, printed])), + softline, + ifBreak(")"), + ]); + } + return printed; +} + module.exports = { printClass }; diff --git a/src/language-js/print/type-parameters.js b/src/language-js/print/type-parameters.js index 6c3b1fa4988d..f4c53039f9bd 100644 --- a/src/language-js/print/type-parameters.js +++ b/src/language-js/print/type-parameters.js @@ -46,29 +46,11 @@ function printTypeParameters(path, options, print, paramsKey) { shouldHugType(n[paramsKey][0].typeName)) || n[paramsKey][0].type === "NullableTypeAnnotation")); - function printDanglingCommentsForInline(n) { - if (!hasDanglingComments(n)) { - return ""; - } - const hasOnlyBlockComments = n.comments.every((comment) => - isBlockComment(comment) - ); - const printed = printDanglingComments( - path, - options, - /* sameIndent */ hasOnlyBlockComments - ); - if (hasOnlyBlockComments) { - return printed; - } - return concat([printed, hardline]); - } - if (shouldInline) { return concat([ "<", join(", ", path.map(print, paramsKey)), - printDanglingCommentsForInline(n), + printDanglingCommentsForInline(path, options), ">", ]); } @@ -96,4 +78,23 @@ function printTypeParameters(path, options, print, paramsKey) { ); } +function printDanglingCommentsForInline(path, options) { + const n = path.getValue(); + if (!hasDanglingComments(n)) { + return ""; + } + const hasOnlyBlockComments = n.comments.every((comment) => + isBlockComment(comment) + ); + const printed = printDanglingComments( + path, + options, + /* sameIndent */ hasOnlyBlockComments + ); + if (hasOnlyBlockComments) { + return printed; + } + return concat([printed, hardline]); +} + module.exports = { printTypeParameters, getTypeParametersGroupId }; From 7fda6381e42dbcc945f22b212fe7010d73d480e8 Mon Sep 17 00:00:00 2001 From: fisker Date: Thu, 19 Nov 2020 09:40:53 +0800 Subject: [PATCH 3/6] Missing `.push` --- src/language-js/print/class.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/language-js/print/class.js b/src/language-js/print/class.js index 5bd1cb195915..268bb7296e0c 100644 --- a/src/language-js/print/class.js +++ b/src/language-js/print/class.js @@ -53,11 +53,11 @@ function printClass(path, options, print) { extendsParts.push(" ", printedWithComments); } } else { - extendsParts(printList(path, options, print, "extends")); + extendsParts.push(printList(path, options, print, "extends")); } - extendsParts(printList(path, options, print, "mixins")); - extendsParts(printList(path, options, print, "implements")); + extendsParts.push(printList(path, options, print, "mixins")); + extendsParts.push(printList(path, options, print, "implements")); if (groupMode) { const printedExtends = concat(extendsParts); From c60b4fcbfcfaabf225ba6bcce1272bc98ac9eb4e Mon Sep 17 00:00:00 2001 From: fisker Date: Thu, 19 Nov 2020 09:49:40 +0800 Subject: [PATCH 4/6] Refactor `printClass` to return Doc --- src/language-js/print/class.js | 2 +- src/language-js/printer-estree.js | 69 ++++++++++++++++++------------- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/src/language-js/print/class.js b/src/language-js/print/class.js index 268bb7296e0c..fadfbb98598f 100644 --- a/src/language-js/print/class.js +++ b/src/language-js/print/class.js @@ -78,7 +78,7 @@ function printClass(path, options, print) { parts.push(" ", path.call(print, "body")); - return parts; + return concat(parts); } function hasMultipleHeritage(node) { diff --git a/src/language-js/printer-estree.js b/src/language-js/printer-estree.js index b4b39a286bb1..530bc9bd6f85 100644 --- a/src/language-js/printer-estree.js +++ b/src/language-js/printer-estree.js @@ -1858,7 +1858,7 @@ function printPathNoParens(path, options, print, args) { if (n.declare) { parts.push("declare "); } - parts.push(concat(printClass(path, options, print))); + parts.push(printClass(path, options, print)); return concat(parts); case "TSInterfaceHeritage": case "TSExpressionWithTypeArguments": // Babel AST @@ -1960,29 +1960,41 @@ function printPathNoParens(path, options, print, args) { semi, ]); case "DeclareFunction": - return printFlowDeclaration(path, [ - "function ", - path.call(print, "id"), - n.predicate ? " " : "", - path.call(print, "predicate"), - semi, - ]); + return printFlowDeclaration( + path, + concat([ + "function ", + path.call(print, "id"), + n.predicate ? " " : "", + path.call(print, "predicate"), + semi, + ]) + ); case "DeclareModule": - return printFlowDeclaration(path, [ - "module ", - path.call(print, "id"), - " ", - path.call(print, "body"), - ]); + return printFlowDeclaration( + path, + concat([ + "module ", + path.call(print, "id"), + " ", + path.call(print, "body"), + ]) + ); case "DeclareModuleExports": - return printFlowDeclaration(path, [ - "module.exports", - ": ", - path.call(print, "typeAnnotation"), - semi, - ]); + return printFlowDeclaration( + path, + concat([ + "module.exports", + ": ", + path.call(print, "typeAnnotation"), + semi, + ]) + ); case "DeclareVariable": - return printFlowDeclaration(path, ["var ", path.call(print, "id"), semi]); + return printFlowDeclaration( + path, + concat(["var ", path.call(print, "id"), semi]) + ); case "DeclareOpaqueType": case "OpaqueType": { parts.push( @@ -2002,7 +2014,7 @@ function printPathNoParens(path, options, print, args) { parts.push(semi); if (n.type === "DeclareOpaqueType") { - return printFlowDeclaration(path, parts); + return printFlowDeclaration(path, concat(parts)); } return concat(parts); @@ -3410,19 +3422,18 @@ function printReturnType(path, print, options) { return concat(parts); } -function printFlowDeclaration(path, parts) { +function printFlowDeclaration(path, printed) { const parentExportDecl = getParentExportDeclaration(path); if (parentExportDecl) { assert.strictEqual(parentExportDecl.type, "DeclareExportDeclaration"); - } else { - // If the parent node has type DeclareExportDeclaration, then it - // will be responsible for printing the "declare" token. Otherwise - // it needs to be printed with this non-exported declaration node. - parts.unshift("declare "); + return printed; } - return concat(parts); + // If the parent node has type DeclareExportDeclaration, then it + // will be responsible for printing the "declare" token. Otherwise + // it needs to be printed with this non-exported declaration node. + return concat(["declare ", printed]); } function printTypeScriptModifiers(path, options, print) { From edc70a90db3b3dbfbf44f0c6ea54374e067f15d9 Mon Sep 17 00:00:00 2001 From: fisker Date: Thu, 19 Nov 2020 10:34:30 +0800 Subject: [PATCH 5/6] Missing arguments --- src/language-js/print/class.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/language-js/print/class.js b/src/language-js/print/class.js index fadfbb98598f..9f3eb33aa7fb 100644 --- a/src/language-js/print/class.js +++ b/src/language-js/print/class.js @@ -40,7 +40,7 @@ function printClass(path, options, print) { if (n.superClass) { const printed = concat([ "extends ", - printSuperClass(path), + printSuperClass(path, options, print), path.call(print, "superTypeParameters"), ]); const printedWithComments = path.call( From 8be71e940a5742d352dbdfce2f9f9b3b4828462d Mon Sep 17 00:00:00 2001 From: fisker Date: Thu, 19 Nov 2020 11:11:28 +0800 Subject: [PATCH 6/6] Fix `printList` --- src/language-js/print/class.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/language-js/print/class.js b/src/language-js/print/class.js index 9f3eb33aa7fb..f5b44069e9c8 100644 --- a/src/language-js/print/class.js +++ b/src/language-js/print/class.js @@ -109,7 +109,7 @@ function printList(path, options, print, listName) { /* sameIndent */ true, ({ marker }) => marker === listName ); - return ( + return concat([ shouldIndentOnlyHeritageClauses(n) ? ifBreak(" ", line, { groupId: getTypeParametersGroupId(n.typeParameters), @@ -122,8 +122,8 @@ function printList(path, options, print, listName) { indent( concat([line, join(concat([",", line]), path.map(print, listName))]) ) - ) - ); + ), + ]); } function printSuperClass(path, options, print) {