Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract printInterface and printCallExpression #9715

Merged
merged 7 commits into from Nov 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
103 changes: 103 additions & 0 deletions src/language-js/print/call-expression.js
@@ -0,0 +1,103 @@
"use strict";

const {
builders: { concat, join, group },
} = require("../../document");
const pathNeedsParens = require("../needs-parens");
const {
getCallArguments,
hasFlowAnnotationComment,
isCallOrOptionalCallExpression,
isMemberish,
isTemplateOnItsOwnLine,
isTestCall,
iterateCallArgumentsPath,
} = require("../utils");
const printMemberChain = require("./member-chain");
const printCallArguments = require("./call-arguments");
const { printOptionalToken, printFunctionTypeParameters } = require("./misc");

function printCallExpression(path, options, print) {
const n = path.getValue();
const isNew = n.type === "NewExpression";
const isDynamicImport = n.type === "ImportExpression";

const optional = printOptionalToken(path);
const args = getCallArguments(n);
if (
// Dangling comments not handled, all these special cases should has argument #9668
args.length > 0 &&
// We want to keep CommonJS- and AMD-style require calls, and AMD-style
// define calls, as a unit.
// e.g. `define(["some/lib", (lib) => {`
((!isDynamicImport &&
!isNew &&
n.callee.type === "Identifier" &&
(n.callee.name === "require" || n.callee.name === "define")) ||
// Template literals as single arguments
(args.length === 1 &&
isTemplateOnItsOwnLine(args[0], options.originalText)) ||
// Keep test declarations on a single line
// e.g. `it('long name', () => {`
(!isNew && isTestCall(n, path.getParentNode())))
) {
const printed = [];
iterateCallArgumentsPath(path, (argPath) => {
printed.push(print(argPath));
});
return concat([
isNew ? "new " : "",
path.call(print, "callee"),
optional,
printFunctionTypeParameters(path, options, print),
concat(["(", join(", ", printed), ")"]),
]);
}

// Inline Flow annotation comments following Identifiers in Call nodes need to
// stay with the Identifier. For example:
//
// foo /*:: <SomeGeneric> */(bar);
//
// Here, we ensure that such comments stay between the Identifier and the Callee.
const isIdentifierWithFlowAnnotation =
(options.parser === "babel" || options.parser === "babel-flow") &&
n.callee &&
n.callee.type === "Identifier" &&
hasFlowAnnotationComment(n.callee.trailingComments);
if (isIdentifierWithFlowAnnotation) {
n.callee.trailingComments[0].printed = true;
}

// We detect calls on member lookups and possibly print them in a
// special chain format. See `printMemberChain` for more info.
if (
!isDynamicImport &&
!isNew &&
isMemberish(n.callee) &&
!path.call((path) => pathNeedsParens(path, options), "callee")
) {
return printMemberChain(path, options, print);
}

const contents = concat([
isNew ? "new " : "",
isDynamicImport ? "import" : path.call(print, "callee"),
optional,
isIdentifierWithFlowAnnotation
? `/*:: ${n.callee.trailingComments[0].value.slice(2).trim()} */`
: "",
printFunctionTypeParameters(path, options, print),
printCallArguments(path, options, print),
]);

// We group here when the callee is itself a call expression.
// See `isLongCurriedCallExpression` for more info.
if (isDynamicImport || isCallOrOptionalCallExpression(n.callee)) {
return group(contents);
}

return contents;
}

module.exports = { printCallExpression };
83 changes: 83 additions & 0 deletions src/language-js/print/interface.js
@@ -0,0 +1,83 @@
"use strict";

const {
builders: { concat, join, line, group, indent, ifBreak },
} = require("../../document");
const {
hasTrailingComment,
hasTrailingLineComment,
identity,
} = require("../utils");
const { getTypeParametersGroupId } = require("./type-parameters");
const { printTypeScriptModifiers } = require("./misc");

function printInterface(path, options, print) {
const n = path.getValue();
const parts = [];
if (n.type === "DeclareInterface" || n.declare) {
parts.push("declare ");
}

if (n.type === "TSInterfaceDeclaration") {
parts.push(
n.abstract ? "abstract " : "",
printTypeScriptModifiers(path, options, print)
);
}

parts.push("interface");

const partsGroup = [];
const extendsParts = [];

if (n.type !== "InterfaceTypeAnnotation") {
partsGroup.push(
" ",
path.call(print, "id"),
path.call(print, "typeParameters")
);
}

const shouldIndentOnlyHeritageClauses =
n.typeParameters && !hasTrailingLineComment(n.typeParameters);

if (n.extends && n.extends.length !== 0) {
extendsParts.push(
shouldIndentOnlyHeritageClauses
? ifBreak(" ", line, {
groupId: getTypeParametersGroupId(n.typeParameters),
})
: line,
"extends ",
(n.extends.length === 1 ? identity : indent)(
join(concat([",", line]), path.map(print, "extends"))
)
);
}

if (
(n.id && hasTrailingComment(n.id)) ||
(n.extends && n.extends.length !== 0)
) {
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 group(concat(parts));
}

module.exports = { printInterface };
16 changes: 13 additions & 3 deletions src/language-js/print/misc.js
@@ -1,11 +1,12 @@
"use strict";

const { isNumericLiteral } = require("../utils");

const {
builders: { concat, softline, group, indent, join, line, hardline },
} = require("../../document");
const { hasNewlineBetweenOrAfterDecorators } = require("../utils");
const {
hasNewlineBetweenOrAfterDecorators,
isNumericLiteral,
} = require("../utils");

function printOptionalToken(path) {
const node = path.getValue();
Expand Down Expand Up @@ -59,6 +60,14 @@ function printBindExpressionCallee(path, options, print) {
return concat(["::", path.call(print, "callee")]);
}

function printTypeScriptModifiers(path, options, print) {
const n = path.getValue();
if (!n.modifiers || !n.modifiers.length) {
return "";
}
return concat([join(" ", path.map(print, "modifiers")), " "]);
}

function printDecorators(path, options, print) {
const node = path.getValue();
return group(
Expand All @@ -74,5 +83,6 @@ module.exports = {
printFunctionTypeParameters,
printMemberLookup,
printBindExpressionCallee,
printTypeScriptModifiers,
printDecorators,
};