prettier/src/language-graphql/printer-graphql.js

686 lines
17 KiB
JavaScript

"use strict";
const {
concat,
join,
hardline,
line,
softline,
group,
indent,
ifBreak
} = require("../doc").builders;
const { hasIgnoreComment } = require("../common/util");
const { isNextLineEmpty } = require("../common/util-shared");
const { insertPragma } = require("./pragma");
function genericPrint(path, options, print) {
const n = path.getValue();
if (!n) {
return "";
}
if (typeof n === "string") {
return n;
}
switch (n.kind) {
case "Document": {
const parts = [];
path.map((pathChild, index) => {
parts.push(concat([pathChild.call(print)]));
if (index !== n.definitions.length - 1) {
parts.push(hardline);
if (
isNextLineEmpty(options.originalText, pathChild.getValue(), options)
) {
parts.push(hardline);
}
}
}, "definitions");
return concat([concat(parts), hardline]);
}
case "OperationDefinition": {
const hasOperation = options.originalText[options.locStart(n)] !== "{";
const hasName = !!n.name;
return concat([
hasOperation ? n.operation : "",
hasOperation && hasName ? concat([" ", path.call(print, "name")]) : "",
n.variableDefinitions && n.variableDefinitions.length
? group(
concat([
"(",
indent(
concat([
softline,
join(
concat([ifBreak("", ", "), softline]),
path.map(print, "variableDefinitions")
)
])
),
softline,
")"
])
)
: "",
printDirectives(path, print, n),
n.selectionSet ? (!hasOperation && !hasName ? "" : " ") : "",
path.call(print, "selectionSet")
]);
}
case "FragmentDefinition": {
return concat([
"fragment ",
path.call(print, "name"),
n.variableDefinitions && n.variableDefinitions.length
? group(
concat([
"(",
indent(
concat([
softline,
join(
concat([ifBreak("", ", "), softline]),
path.map(print, "variableDefinitions")
)
])
),
softline,
")"
])
)
: "",
" on ",
path.call(print, "typeCondition"),
printDirectives(path, print, n),
" ",
path.call(print, "selectionSet")
]);
}
case "SelectionSet": {
return concat([
"{",
indent(
concat([
hardline,
join(
hardline,
path.call(
selectionsPath => printSequence(selectionsPath, options, print),
"selections"
)
)
])
),
hardline,
"}"
]);
}
case "Field": {
return group(
concat([
n.alias ? concat([path.call(print, "alias"), ": "]) : "",
path.call(print, "name"),
n.arguments.length > 0
? group(
concat([
"(",
indent(
concat([
softline,
join(
concat([ifBreak("", ", "), softline]),
path.call(
argsPath => printSequence(argsPath, options, print),
"arguments"
)
)
])
),
softline,
")"
])
)
: "",
printDirectives(path, print, n),
n.selectionSet ? " " : "",
path.call(print, "selectionSet")
])
);
}
case "Name": {
return n.value;
}
case "StringValue": {
if (n.block) {
return concat([
'"""',
hardline,
join(hardline, n.value.replace(/"""/g, "\\$&").split("\n")),
hardline,
'"""'
]);
}
return concat([
'"',
n.value.replace(/["\\]/g, "\\$&").replace(/\n/g, "\\n"),
'"'
]);
}
case "IntValue":
case "FloatValue":
case "EnumValue": {
return n.value;
}
case "BooleanValue": {
return n.value ? "true" : "false";
}
case "NullValue": {
return "null";
}
case "Variable": {
return concat(["$", path.call(print, "name")]);
}
case "ListValue": {
return group(
concat([
"[",
indent(
concat([
softline,
join(
concat([ifBreak("", ", "), softline]),
path.map(print, "values")
)
])
),
softline,
"]"
])
);
}
case "ObjectValue": {
return group(
concat([
"{",
options.bracketSpacing && n.fields.length > 0 ? " " : "",
indent(
concat([
softline,
join(
concat([ifBreak("", ", "), softline]),
path.map(print, "fields")
)
])
),
softline,
ifBreak("", options.bracketSpacing && n.fields.length > 0 ? " " : ""),
"}"
])
);
}
case "ObjectField":
case "Argument": {
return concat([
path.call(print, "name"),
": ",
path.call(print, "value")
]);
}
case "Directive": {
return concat([
"@",
path.call(print, "name"),
n.arguments.length > 0
? group(
concat([
"(",
indent(
concat([
softline,
join(
concat([ifBreak("", ", "), softline]),
path.call(
argsPath => printSequence(argsPath, options, print),
"arguments"
)
)
])
),
softline,
")"
])
)
: ""
]);
}
case "NamedType": {
return path.call(print, "name");
}
case "VariableDefinition": {
return concat([
path.call(print, "variable"),
": ",
path.call(print, "type"),
n.defaultValue ? concat([" = ", path.call(print, "defaultValue")]) : ""
]);
}
case "TypeExtensionDefinition": {
return concat(["extend ", path.call(print, "definition")]);
}
case "ObjectTypeExtension":
case "ObjectTypeDefinition": {
return concat([
path.call(print, "description"),
n.description ? hardline : "",
n.kind === "ObjectTypeExtension" ? "extend " : "",
"type ",
path.call(print, "name"),
n.interfaces.length > 0
? concat([
" implements ",
join(
determineInterfaceSeparator(
options.originalText.substr(
options.locStart(n),
options.locEnd(n)
)
),
path.map(print, "interfaces")
)
])
: "",
printDirectives(path, print, n),
n.fields.length > 0
? concat([
" {",
indent(
concat([
hardline,
join(
hardline,
path.call(
fieldsPath => printSequence(fieldsPath, options, print),
"fields"
)
)
])
),
hardline,
"}"
])
: ""
]);
}
case "FieldDefinition": {
return concat([
path.call(print, "description"),
n.description ? hardline : "",
path.call(print, "name"),
n.arguments.length > 0
? group(
concat([
"(",
indent(
concat([
softline,
join(
concat([ifBreak("", ", "), softline]),
path.call(
argsPath => printSequence(argsPath, options, print),
"arguments"
)
)
])
),
softline,
")"
])
)
: "",
": ",
path.call(print, "type"),
printDirectives(path, print, n)
]);
}
case "DirectiveDefinition": {
return concat([
path.call(print, "description"),
n.description ? hardline : "",
"directive ",
"@",
path.call(print, "name"),
n.arguments.length > 0
? group(
concat([
"(",
indent(
concat([
softline,
join(
concat([ifBreak("", ", "), softline]),
path.call(
argsPath => printSequence(argsPath, options, print),
"arguments"
)
)
])
),
softline,
")"
])
)
: "",
concat([" on ", join(" | ", path.map(print, "locations"))])
]);
}
case "EnumTypeExtension":
case "EnumTypeDefinition": {
return concat([
path.call(print, "description"),
n.description ? hardline : "",
n.kind === "EnumTypeExtension" ? "extend " : "",
"enum ",
path.call(print, "name"),
printDirectives(path, print, n),
n.values.length > 0
? concat([
" {",
indent(
concat([
hardline,
join(
hardline,
path.call(
valuesPath => printSequence(valuesPath, options, print),
"values"
)
)
])
),
hardline,
"}"
])
: ""
]);
}
case "EnumValueDefinition": {
return concat([
path.call(print, "description"),
n.description ? hardline : "",
path.call(print, "name"),
printDirectives(path, print, n)
]);
}
case "InputValueDefinition": {
return concat([
path.call(print, "description"),
n.description ? (n.description.block ? hardline : line) : "",
path.call(print, "name"),
": ",
path.call(print, "type"),
n.defaultValue ? concat([" = ", path.call(print, "defaultValue")]) : "",
printDirectives(path, print, n)
]);
}
case "InputObjectTypeExtension":
case "InputObjectTypeDefinition": {
return concat([
path.call(print, "description"),
n.description ? hardline : "",
n.kind === "InputObjectTypeExtension" ? "extend " : "",
"input ",
path.call(print, "name"),
printDirectives(path, print, n),
n.fields.length > 0
? concat([
" {",
indent(
concat([
hardline,
join(
hardline,
path.call(
fieldsPath => printSequence(fieldsPath, options, print),
"fields"
)
)
])
),
hardline,
"}"
])
: ""
]);
}
case "SchemaDefinition": {
return concat([
"schema",
printDirectives(path, print, n),
" {",
n.operationTypes.length > 0
? indent(
concat([
hardline,
join(
hardline,
path.call(
opsPath => printSequence(opsPath, options, print),
"operationTypes"
)
)
])
)
: "",
hardline,
"}"
]);
}
case "OperationTypeDefinition": {
return concat([
path.call(print, "operation"),
": ",
path.call(print, "type")
]);
}
case "InterfaceTypeExtension":
case "InterfaceTypeDefinition": {
return concat([
path.call(print, "description"),
n.description ? hardline : "",
n.kind === "InterfaceTypeExtension" ? "extend " : "",
"interface ",
path.call(print, "name"),
printDirectives(path, print, n),
n.fields.length > 0
? concat([
" {",
indent(
concat([
hardline,
join(
hardline,
path.call(
fieldsPath => printSequence(fieldsPath, options, print),
"fields"
)
)
])
),
hardline,
"}"
])
: ""
]);
}
case "FragmentSpread": {
return concat([
"...",
path.call(print, "name"),
printDirectives(path, print, n)
]);
}
case "InlineFragment": {
return concat([
"...",
n.typeCondition
? concat([" on ", path.call(print, "typeCondition")])
: "",
printDirectives(path, print, n),
" ",
path.call(print, "selectionSet")
]);
}
case "UnionTypeExtension":
case "UnionTypeDefinition": {
return group(
concat([
path.call(print, "description"),
n.description ? hardline : "",
group(
concat([
n.kind === "UnionTypeExtension" ? "extend " : "",
"union ",
path.call(print, "name"),
printDirectives(path, print, n),
n.types.length > 0
? concat([
" =",
ifBreak("", " "),
indent(
concat([
ifBreak(concat([line, " "])),
join(concat([line, "| "]), path.map(print, "types"))
])
)
])
: ""
])
)
])
);
}
case "ScalarTypeExtension":
case "ScalarTypeDefinition": {
return concat([
path.call(print, "description"),
n.description ? hardline : "",
n.kind === "ScalarTypeExtension" ? "extend " : "",
"scalar ",
path.call(print, "name"),
printDirectives(path, print, n)
]);
}
case "NonNullType": {
return concat([path.call(print, "type"), "!"]);
}
case "ListType": {
return concat(["[", path.call(print, "type"), "]"]);
}
default:
/* istanbul ignore next */
throw new Error("unknown graphql type: " + JSON.stringify(n.kind));
}
}
function printDirectives(path, print, n) {
if (n.directives.length === 0) {
return "";
}
return concat([
" ",
group(
indent(
concat([
softline,
join(
concat([ifBreak("", " "), softline]),
path.map(print, "directives")
)
])
)
)
]);
}
function printSequence(sequencePath, options, print) {
const count = sequencePath.getValue().length;
return sequencePath.map((path, i) => {
const printed = print(path);
if (
isNextLineEmpty(options.originalText, path.getValue(), options) &&
i < count - 1
) {
return concat([printed, hardline]);
}
return printed;
});
}
function canAttachComment(node) {
return node.kind && node.kind !== "Comment";
}
function printComment(commentPath) {
const comment = commentPath.getValue();
if (comment.kind === "Comment") {
return "#" + comment.value.trimRight();
}
throw new Error("Not a comment: " + JSON.stringify(comment));
}
function determineInterfaceSeparator(originalSource) {
const start = originalSource.indexOf("implements");
if (start === -1) {
throw new Error("Must implement interfaces: " + originalSource);
}
let end = originalSource.indexOf("{");
if (end === -1) {
end = originalSource.length;
}
return originalSource.substr(start, end).includes("&") ? " & " : ", ";
}
function clean(node, newNode /*, parent*/) {
delete newNode.loc;
delete newNode.comments;
}
module.exports = {
print: genericPrint,
massageAstNode: clean,
hasPrettierIgnore: hasIgnoreComment,
insertPragma,
printComment,
canAttachComment
};