Files
test-repo/src/language-graphql/printer-graphql.js
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

573 lines
14 KiB
JavaScript
Raw Normal View History

import {
join,
hardline,
line,
softline,
group,
indent,
ifBreak,
} from "../document/builders.js";
import { isNextLineEmpty, isNonEmptyArray } from "../common/util.js";
2022-08-17 09:47:08 +08:00
import createGetVisitorKeys from "../utils/create-get-visitor-keys.js";
import UnexpectedNodeError from "../utils/unexpected-node-error.js";
import { insertPragma } from "./pragma.js";
import { locStart, locEnd } from "./loc.js";
2022-08-17 09:47:08 +08:00
import visitorKeys from "./visitor-keys.evaluate.js";
2017-06-05 15:34:08 -04:00
const getVisitorKeys = createGetVisitorKeys(visitorKeys, "kind");
function genericPrint(path, options, print) {
2021-03-11 04:14:08 +08:00
const node = path.getValue();
2021-03-11 04:14:08 +08:00
switch (node.kind) {
2017-06-05 15:34:08 -04:00
case "Document": {
const parts = [];
path.each((pathChild, index, definitions) => {
parts.push(print());
if (index !== definitions.length - 1) {
parts.push(hardline);
if (
isNextLineEmpty(options.originalText, pathChild.getValue(), locEnd)
) {
parts.push(hardline);
}
}
}, "definitions");
return [...parts, hardline];
2017-06-05 15:34:08 -04:00
}
case "OperationDefinition": {
2021-03-11 04:14:08 +08:00
const hasOperation = options.originalText[locStart(node)] !== "{";
const hasName = Boolean(node.name);
return [
2021-03-11 04:14:08 +08:00
hasOperation ? node.operation : "",
hasOperation && hasName ? [" ", print("name")] : "",
hasOperation && !hasName && isNonEmptyArray(node.variableDefinitions)
? " "
: "",
2021-03-11 04:14:08 +08:00
isNonEmptyArray(node.variableDefinitions)
? group([
"(",
indent([
softline,
join(
[ifBreak("", ", "), softline],
path.map(print, "variableDefinitions")
),
]),
softline,
")",
])
2017-06-06 17:42:47 -07:00
: "",
printDirectives(path, print, node),
2021-03-11 04:14:08 +08:00
node.selectionSet ? (!hasOperation && !hasName ? "" : " ") : "",
print("selectionSet"),
];
2017-06-05 15:34:08 -04:00
}
2017-06-06 12:35:40 -07:00
case "FragmentDefinition": {
return [
2017-06-06 12:35:40 -07:00
"fragment ",
print("name"),
2021-03-11 04:14:08 +08:00
isNonEmptyArray(node.variableDefinitions)
? group([
"(",
indent([
softline,
join(
[ifBreak("", ", "), softline],
path.map(print, "variableDefinitions")
),
]),
softline,
")",
])
: "",
2017-06-06 12:35:40 -07:00
" on ",
print("typeCondition"),
printDirectives(path, print, node),
2017-06-06 12:35:40 -07:00
" ",
print("selectionSet"),
];
2017-06-06 12:35:40 -07:00
}
2017-06-05 15:34:08 -04:00
case "SelectionSet": {
return [
2017-06-05 15:34:08 -04:00
"{",
indent([
hardline,
join(hardline, printSequence(path, options, print, "selections")),
]),
2017-06-05 15:34:08 -04:00
hardline,
"}",
];
2017-06-05 15:34:08 -04:00
}
case "Field": {
return group([
node.alias ? [print("alias"), ": "] : "",
print("name"),
2021-03-11 04:14:08 +08:00
node.arguments.length > 0
? group([
"(",
indent([
softline,
join(
[ifBreak("", ", "), softline],
printSequence(path, options, print, "arguments")
),
]),
softline,
")",
])
: "",
printDirectives(path, print, node),
2021-03-11 04:14:08 +08:00
node.selectionSet ? " " : "",
print("selectionSet"),
]);
2017-06-05 15:34:08 -04:00
}
case "Name": {
2021-03-11 04:14:08 +08:00
return node.value;
2017-06-05 15:34:08 -04:00
}
case "StringValue": {
2021-03-11 04:14:08 +08:00
if (node.block) {
const lines = node.value.replace(/"""/g, "\\$&").split("\n");
if (lines.length === 1) {
lines[0] = lines[0].trim();
}
if (lines.every((line) => line === "")) {
lines.length = 0;
}
return join(hardline, ['"""', ...lines, '"""']);
2017-12-31 16:45:06 +01:00
}
return [
'"',
2021-03-11 04:14:08 +08:00
node.value.replace(/["\\]/g, "\\$&").replace(/\n/g, "\\n"),
'"',
];
2017-06-05 15:34:08 -04:00
}
case "IntValue":
case "FloatValue":
case "EnumValue": {
2021-03-11 04:14:08 +08:00
return node.value;
}
case "BooleanValue": {
2021-03-11 04:14:08 +08:00
return node.value ? "true" : "false";
}
2017-06-06 18:06:15 -07:00
case "NullValue": {
return "null";
}
case "Variable": {
return ["$", print("name")];
2017-06-05 23:45:15 -07:00
}
case "ListValue": {
return group([
"[",
indent([
2017-06-05 23:45:15 -07:00
softline,
join([ifBreak("", ", "), softline], path.map(print, "values")),
]),
softline,
"]",
]);
}
case "ObjectValue": {
return group([
"{",
2021-03-11 04:14:08 +08:00
options.bracketSpacing && node.fields.length > 0 ? " " : "",
indent([
softline,
join([ifBreak("", ", "), softline], path.map(print, "fields")),
]),
softline,
2021-03-11 04:14:08 +08:00
ifBreak(
"",
options.bracketSpacing && node.fields.length > 0 ? " " : ""
),
"}",
]);
}
case "ObjectField":
2017-06-05 15:34:08 -04:00
case "Argument": {
return [print("name"), ": ", print("value")];
2017-06-05 15:34:08 -04:00
}
2017-06-06 17:42:47 -07:00
case "Directive": {
return [
2017-06-06 17:42:47 -07:00
"@",
print("name"),
2021-03-11 04:14:08 +08:00
node.arguments.length > 0
? group([
"(",
indent([
2017-06-06 17:42:47 -07:00
softline,
join(
[ifBreak("", ", "), softline],
printSequence(path, options, print, "arguments")
),
]),
softline,
")",
])
2017-06-06 17:42:47 -07:00
: "",
];
2017-06-06 17:42:47 -07:00
}
case "NamedType": {
2021-03-22 22:57:03 +08:00
return print("name");
}
case "VariableDefinition": {
return [
print("variable"),
": ",
print("type"),
node.defaultValue ? [" = ", print("defaultValue")] : "",
printDirectives(path, print, node),
];
}
2017-12-31 16:45:06 +01:00
case "ObjectTypeExtension":
2022-08-30 22:42:58 +08:00
case "ObjectTypeDefinition":
case "InputObjectTypeExtension":
case "InputObjectTypeDefinition":
case "InterfaceTypeExtension":
case "InterfaceTypeDefinition": {
const { kind } = node;
const parts = [];
if (kind.endsWith("TypeDefinition")) {
if (node.description) {
parts.push(print("description"), hardline);
}
} else {
parts.push("extend ");
}
if (kind.startsWith("ObjectType")) {
parts.push("type");
} else if (kind.startsWith("InputObjectType")) {
parts.push("input");
} else {
parts.push("interface");
}
parts.push(" ", print("name"));
if (!kind.startsWith("InputObjectType") && node.interfaces.length > 0) {
parts.push(" implements ", ...printInterfaces(path, options, print));
}
parts.push(printDirectives(path, print, node));
if (node.fields.length > 0) {
parts.push([
" {",
indent([
hardline,
join(hardline, printSequence(path, options, print, "fields")),
]),
hardline,
"}",
]);
}
return parts;
}
case "FieldDefinition": {
return [
print("description"),
2021-03-11 04:14:08 +08:00
node.description ? hardline : "",
print("name"),
2021-03-11 04:14:08 +08:00
node.arguments.length > 0
? group([
"(",
indent([
softline,
join(
[ifBreak("", ", "), softline],
printSequence(path, options, print, "arguments")
),
]),
softline,
")",
])
: "",
": ",
print("type"),
printDirectives(path, print, node),
];
}
case "DirectiveDefinition": {
return [
print("description"),
2021-03-11 04:14:08 +08:00
node.description ? hardline : "",
"directive ",
"@",
print("name"),
2021-03-11 04:14:08 +08:00
node.arguments.length > 0
? group([
"(",
indent([
softline,
join(
[ifBreak("", ", "), softline],
printSequence(path, options, print, "arguments")
),
]),
softline,
")",
])
: "",
2021-03-11 04:14:08 +08:00
node.repeatable ? " repeatable" : "",
2021-01-11 10:19:13 +08:00
" on ",
join(" | ", path.map(print, "locations")),
];
}
2017-12-31 16:45:06 +01:00
case "EnumTypeExtension":
2017-06-27 19:20:53 -07:00
case "EnumTypeDefinition": {
return [
2022-08-30 22:42:58 +08:00
...(node.description ? [print("description"), hardline] : []),
2021-03-11 04:14:08 +08:00
node.kind === "EnumTypeExtension" ? "extend " : "",
2017-06-27 19:20:53 -07:00
"enum ",
print("name"),
printDirectives(path, print, node),
2021-03-11 04:14:08 +08:00
node.values.length > 0
? [
2017-12-31 16:45:06 +01:00
" {",
indent([
hardline,
join(hardline, printSequence(path, options, print, "values")),
]),
2017-12-31 16:45:06 +01:00
hardline,
"}",
]
2017-12-31 16:45:06 +01:00
: "",
];
2017-06-27 19:20:53 -07:00
}
case "EnumValueDefinition": {
return [
print("description"),
2021-03-11 04:14:08 +08:00
node.description ? hardline : "",
print("name"),
printDirectives(path, print, node),
];
2017-06-27 19:20:53 -07:00
}
case "InputValueDefinition": {
return [
print("description"),
2021-03-11 04:14:08 +08:00
node.description ? (node.description.block ? hardline : line) : "",
print("name"),
": ",
print("type"),
node.defaultValue ? [" = ", print("defaultValue")] : "",
printDirectives(path, print, node),
];
}
case "SchemaExtension": {
return [
"extend schema",
printDirectives(path, print, node),
...(node.operationTypes.length > 0
? [
" {",
indent([
hardline,
join(
hardline,
printSequence(path, options, print, "operationTypes")
),
]),
hardline,
"}",
]
: []),
];
}
case "SchemaDefinition": {
return [
print("description"),
node.description ? hardline : "",
"schema",
printDirectives(path, print, node),
" {",
2021-03-11 04:14:08 +08:00
node.operationTypes.length > 0
? indent([
hardline,
join(
hardline,
printSequence(path, options, print, "operationTypes")
),
])
2017-06-27 20:15:55 -07:00
: "",
hardline,
"}",
];
2017-06-27 20:15:55 -07:00
}
case "OperationTypeDefinition": {
return [node.operation, ": ", print("type")];
2017-06-27 20:15:55 -07:00
}
2017-06-06 12:35:40 -07:00
case "FragmentSpread": {
return ["...", print("name"), printDirectives(path, print, node)];
2017-06-06 12:35:40 -07:00
}
case "InlineFragment": {
return [
2017-06-06 12:35:40 -07:00
"...",
node.typeCondition ? [" on ", print("typeCondition")] : "",
printDirectives(path, print, node),
2017-06-06 12:35:40 -07:00
" ",
print("selectionSet"),
];
2017-06-06 12:35:40 -07:00
}
2017-12-31 16:45:06 +01:00
case "UnionTypeExtension":
case "UnionTypeDefinition": {
return group([
2022-08-30 22:42:58 +08:00
...(node.description ? [print("description"), hardline] : []),
group([
2021-03-11 04:14:08 +08:00
node.kind === "UnionTypeExtension" ? "extend " : "",
"union ",
print("name"),
printDirectives(path, print, node),
2021-03-11 04:14:08 +08:00
node.types.length > 0
? [
" =",
ifBreak("", " "),
indent([
ifBreak([line, " "]),
join([line, "| "], path.map(print, "types")),
]),
]
: "",
]),
]);
}
2017-12-31 16:45:06 +01:00
case "ScalarTypeExtension":
2017-06-27 19:34:25 -07:00
case "ScalarTypeDefinition": {
return [
2022-08-30 22:42:58 +08:00
...(node.description ? [print("description"), hardline] : []),
2021-03-11 04:14:08 +08:00
node.kind === "ScalarTypeExtension" ? "extend " : "",
2017-06-27 19:34:25 -07:00
"scalar ",
print("name"),
printDirectives(path, print, node),
];
2017-06-27 19:34:25 -07:00
}
2017-06-08 12:20:41 -04:00
case "NonNullType": {
return [print("type"), "!"];
2017-06-08 12:20:41 -04:00
}
2017-06-08 12:34:35 -04:00
case "ListType": {
return ["[", print("type"), "]"];
2017-06-08 12:34:35 -04:00
}
2017-06-05 15:34:08 -04:00
default:
2017-09-03 22:40:44 +02:00
/* istanbul ignore next */
throw new UnexpectedNodeError(node, "Graphql", "kind");
2017-06-05 15:34:08 -04:00
}
}
function printDirectives(path, print, node) {
2021-03-11 04:14:08 +08:00
if (node.directives.length === 0) {
2017-06-06 17:42:47 -07:00
return "";
}
const printed = join(line, path.map(print, "directives"));
2021-03-11 04:14:08 +08:00
if (
node.kind === "FragmentDefinition" ||
node.kind === "OperationDefinition"
) {
return group([line, printed]);
}
return [" ", group(indent([softline, printed]))];
2017-06-06 17:42:47 -07:00
}
2022-03-31 21:04:12 +08:00
function printSequence(path, options, print, property) {
return path.map((path, index, sequence) => {
const printed = print();
if (
2022-03-31 21:04:12 +08:00
index < sequence.length - 1 &&
isNextLineEmpty(options.originalText, path.getValue(), locEnd)
) {
return [printed, hardline];
}
return printed;
2022-03-31 21:04:12 +08:00
}, property);
}
2017-12-27 00:04:09 +11:00
function canAttachComment(node) {
return node.kind !== "Comment";
2017-12-27 00:04:09 +11:00
}
function printComment(commentPath) {
const comment = commentPath.getValue();
if (comment.kind === "Comment") {
return "#" + comment.value.trimEnd();
2017-12-27 00:04:09 +11:00
}
2020-08-21 09:43:24 +08:00
/* istanbul ignore next */
throw new Error("Not a comment: " + JSON.stringify(comment));
2017-12-27 00:04:09 +11:00
}
function printInterfaces(path, options, print) {
const node = path.getValue();
const parts = [];
const { interfaces } = node;
const printed = path.map(print, "interfaces");
for (let index = 0; index < interfaces.length; index++) {
const interfaceNode = interfaces[index];
parts.push(printed[index]);
const nextInterfaceNode = interfaces[index + 1];
if (nextInterfaceNode) {
const textBetween = options.originalText.slice(
interfaceNode.loc.end,
nextInterfaceNode.loc.start
);
const hasComment = textBetween.includes("#");
2022-05-08 20:20:34 +08:00
parts.push(" &", hasComment ? line : " ");
}
}
return parts;
}
function clean(node, newNode /* , parent */) {
// We print single line `""" string """` as multiple line string,
// and the parser ignores space in multiple line string
if (node.kind === "StringValue" && node.block && !node.value.includes("\n")) {
newNode.value = newNode.value.trim();
}
}
clean.ignoredProperties = new Set(["loc", "comments"]);
function hasPrettierIgnore(path) {
const node = path.getValue();
2022-04-24 10:28:20 +08:00
return node?.comments?.some(
(comment) => comment.value.trim() === "prettier-ignore"
);
}
const printer = {
2017-12-26 12:23:50 +11:00
print: genericPrint,
massageAstNode: clean,
hasPrettierIgnore,
2018-06-17 14:04:48 +08:00
insertPragma,
2017-12-27 00:04:09 +11:00
printComment,
canAttachComment,
getVisitorKeys,
2017-12-26 12:23:50 +11:00
};
export default printer;