Support toplevel interpolations in graphql tags (#3370)
* Refactor multiparser * Add support for toplevel interpolations in graphql tags * Update snapshots * Fix JSX-in-markdown special-case
This commit is contained in:
1 parent
073c0b16d8
commit
d80728b5ff
5 files changed
+660
-143
No files matched your search
+189
-109
@@ -5,44 +5,41 @@ const docUtils = require("./doc-utils");
|
||||
const docBuilders = require("./doc-builders");
|
||||
const comments = require("./comments");
|
||||
const indent = docBuilders.indent;
|
||||
const join = docBuilders.join;
|
||||
const hardline = docBuilders.hardline;
|
||||
const softline = docBuilders.softline;
|
||||
const concat = docBuilders.concat;
|
||||
|
||||
function printSubtree(subtreeParser, path, print, options) {
|
||||
const next = Object.assign({}, { transformDoc: doc => doc }, subtreeParser);
|
||||
next.options = Object.assign({}, options, next.options, {
|
||||
parentParser: options.parser,
|
||||
originalText: next.text
|
||||
});
|
||||
if (next.options.parser === "json") {
|
||||
next.options.trailingComma = "none";
|
||||
}
|
||||
const ast = require("./parser").parse(next.text, next.options);
|
||||
const astComments = ast.comments;
|
||||
delete ast.comments;
|
||||
comments.attach(astComments, ast, next.text, next.options);
|
||||
const nextDoc = require("./printer").printAstToDoc(ast, next.options);
|
||||
return next.transformDoc(nextDoc, { path, print });
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {{ text, options?, transformDoc? } | void}
|
||||
*/
|
||||
function getSubtreeParser(path, options) {
|
||||
function printSubtree(path, print, options) {
|
||||
switch (options.parser) {
|
||||
case "parse5":
|
||||
return fromHtmlParser2(path, options);
|
||||
return fromHtmlParser2(path, print, options);
|
||||
case "babylon":
|
||||
case "flow":
|
||||
case "typescript":
|
||||
return fromBabylonFlowOrTypeScript(path, options);
|
||||
return fromBabylonFlowOrTypeScript(path, print, options);
|
||||
case "markdown":
|
||||
return fromMarkdown(path, options);
|
||||
return fromMarkdown(path, print, options);
|
||||
}
|
||||
}
|
||||
|
||||
function fromMarkdown(path, options) {
|
||||
function parseAndPrint(text, partialNextOptions, parentOptions) {
|
||||
const nextOptions = Object.assign({}, parentOptions, partialNextOptions, {
|
||||
parentParser: parentOptions.parser,
|
||||
trailingComma:
|
||||
partialNextOptions.parser === "json"
|
||||
? "none"
|
||||
: partialNextOptions.trailingComma,
|
||||
originalText: text
|
||||
});
|
||||
const ast = require("./parser").parse(text, nextOptions);
|
||||
const astComments = ast.comments;
|
||||
delete ast.comments;
|
||||
comments.attach(astComments, ast, text, nextOptions);
|
||||
return require("./printer").printAstToDoc(ast, nextOptions);
|
||||
}
|
||||
|
||||
function fromMarkdown(path, print, options) {
|
||||
const node = path.getValue();
|
||||
|
||||
if (node.type === "code") {
|
||||
@@ -52,11 +49,8 @@ function fromMarkdown(path, options) {
|
||||
const style = styleUnit.repeat(
|
||||
Math.max(3, util.getMaxContinuousCount(node.value, styleUnit) + 1)
|
||||
);
|
||||
return {
|
||||
options: { parser },
|
||||
transformDoc: doc => concat([style, node.lang, hardline, doc, style]),
|
||||
text: node.value
|
||||
};
|
||||
const doc = parseAndPrint(node.value, { parser }, options);
|
||||
return concat([style, node.lang, hardline, doc, style]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,8 +87,10 @@ function fromMarkdown(path, options) {
|
||||
}
|
||||
}
|
||||
|
||||
function fromBabylonFlowOrTypeScript(path) {
|
||||
function fromBabylonFlowOrTypeScript(path, print, options) {
|
||||
const node = path.getValue();
|
||||
const parent = path.getParentNode();
|
||||
const parentParent = path.getParentNode(1);
|
||||
|
||||
switch (node.type) {
|
||||
case "TemplateLiteral": {
|
||||
@@ -104,19 +100,10 @@ function fromBabylonFlowOrTypeScript(path) {
|
||||
// Get full template literal with expressions replaced by placeholders
|
||||
const rawQuasis = node.quasis.map(q => q.value.raw);
|
||||
const text = rawQuasis.join("@prettier-placeholder");
|
||||
return {
|
||||
options: { parser: "css" },
|
||||
transformDoc: transformCssDoc,
|
||||
text: text
|
||||
};
|
||||
const doc = parseAndPrint(text, { parser: "css" }, options);
|
||||
return transformCssDoc(doc, path, print);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case "TemplateElement": {
|
||||
const parent = path.getParentNode();
|
||||
const parentParent = path.getParentNode(1);
|
||||
|
||||
/*
|
||||
* react-relay and graphql-tag
|
||||
* graphql`...`
|
||||
@@ -124,31 +111,98 @@ function fromBabylonFlowOrTypeScript(path) {
|
||||
* gql`...`
|
||||
*/
|
||||
if (
|
||||
// We currently don't support expression inside GraphQL template literals
|
||||
parent.expressions.length === 0 &&
|
||||
parentParent &&
|
||||
((parentParent.type === "TaggedTemplateExpression" &&
|
||||
((parentParent.tag.type === "MemberExpression" &&
|
||||
parentParent.tag.object.name === "graphql" &&
|
||||
parentParent.tag.property.name === "experimental") ||
|
||||
(parentParent.tag.type === "Identifier" &&
|
||||
(parentParent.tag.name === "gql" ||
|
||||
parentParent.tag.name === "graphql")))) ||
|
||||
(parentParent.type === "CallExpression" &&
|
||||
parentParent.callee.type === "Identifier" &&
|
||||
parentParent.callee.name === "graphql"))
|
||||
parent &&
|
||||
((parent.type === "TaggedTemplateExpression" &&
|
||||
((parent.tag.type === "MemberExpression" &&
|
||||
parent.tag.object.name === "graphql" &&
|
||||
parent.tag.property.name === "experimental") ||
|
||||
(parent.tag.type === "Identifier" &&
|
||||
(parent.tag.name === "gql" || parent.tag.name === "graphql")))) ||
|
||||
(parent.type === "CallExpression" &&
|
||||
parent.callee.type === "Identifier" &&
|
||||
parent.callee.name === "graphql"))
|
||||
) {
|
||||
return {
|
||||
options: { parser: "graphql" },
|
||||
transformDoc: doc =>
|
||||
concat([
|
||||
indent(concat([softline, stripTrailingHardline(doc)])),
|
||||
softline
|
||||
]),
|
||||
text: parent.quasis[0].value.raw
|
||||
};
|
||||
const expressionDocs = node.expressions
|
||||
? path.map(print, "expressions")
|
||||
: [];
|
||||
|
||||
const numQuasis = node.quasis.length;
|
||||
|
||||
if (numQuasis === 1 && node.quasis[0].value.raw.trim() === "") {
|
||||
return "``";
|
||||
}
|
||||
|
||||
const parts = [];
|
||||
|
||||
for (let i = 0; i < numQuasis; i++) {
|
||||
const templateElement = node.quasis[i];
|
||||
const isFirst = i === 0;
|
||||
const isLast = i === numQuasis - 1;
|
||||
const text = templateElement.value.raw;
|
||||
const lines = text.split("\n");
|
||||
const numLines = lines.length;
|
||||
const expressionDoc = expressionDocs[i];
|
||||
|
||||
const startsWithBlankLine =
|
||||
numLines > 2 && lines[0].trim() === "" && lines[1].trim() === "";
|
||||
const endsWithBlankLine =
|
||||
numLines > 2 &&
|
||||
lines[numLines - 1].trim() === "" &&
|
||||
lines[numLines - 2].trim() === "";
|
||||
|
||||
const commentsAndWhitespaceOnly = lines.every(line =>
|
||||
/^\s*(?:#[^\r\n]*)?$/.test(line)
|
||||
);
|
||||
|
||||
// Bail out if an interpolation occurs within a comment.
|
||||
if (!isLast && /#[^\r\n]*$/.test(lines[numLines - 1])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let doc = null;
|
||||
|
||||
if (commentsAndWhitespaceOnly) {
|
||||
doc = printGraphqlComments(lines);
|
||||
} else {
|
||||
try {
|
||||
doc = stripTrailingHardline(
|
||||
parseAndPrint(text, { parser: "graphql" }, options)
|
||||
);
|
||||
} catch (_error) {
|
||||
// Bail if any part fails to parse.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (doc) {
|
||||
if (!isFirst && startsWithBlankLine) {
|
||||
parts.push("");
|
||||
}
|
||||
parts.push(doc);
|
||||
if (!isLast && endsWithBlankLine) {
|
||||
parts.push("");
|
||||
}
|
||||
} else if (!isFirst && !isLast && startsWithBlankLine) {
|
||||
parts.push("");
|
||||
}
|
||||
|
||||
if (expressionDoc) {
|
||||
parts.push(concat(["${", expressionDoc, "}"]));
|
||||
}
|
||||
}
|
||||
|
||||
return concat([
|
||||
"`",
|
||||
indent(concat([hardline, join(hardline, parts)])),
|
||||
hardline,
|
||||
"`"
|
||||
]);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "TemplateElement": {
|
||||
/**
|
||||
* md`...`
|
||||
* markdown`...`
|
||||
@@ -161,18 +215,21 @@ function fromBabylonFlowOrTypeScript(path) {
|
||||
(parentParent.tag.name === "md" ||
|
||||
parentParent.tag.name === "markdown")))
|
||||
) {
|
||||
return {
|
||||
options: { parser: "markdown", __inJsTemplate: true },
|
||||
transformDoc: doc =>
|
||||
concat([
|
||||
indent(
|
||||
concat([softline, stripTrailingHardline(escapeBackticks(doc))])
|
||||
),
|
||||
softline
|
||||
]),
|
||||
const doc = parseAndPrint(
|
||||
// leading whitespaces matter in markdown
|
||||
text: dedent(parent.quasis[0].value.cooked)
|
||||
};
|
||||
dedent(parent.quasis[0].value.cooked),
|
||||
{
|
||||
parser: "markdown",
|
||||
__inJsTemplate: true
|
||||
},
|
||||
options
|
||||
);
|
||||
return concat([
|
||||
indent(
|
||||
concat([softline, stripTrailingHardline(escapeBackticks(doc))])
|
||||
),
|
||||
softline
|
||||
]);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -180,6 +237,32 @@ function fromBabylonFlowOrTypeScript(path) {
|
||||
}
|
||||
}
|
||||
|
||||
function printGraphqlComments(lines) {
|
||||
const parts = [];
|
||||
let seenComment = false;
|
||||
|
||||
lines.map(textLine => textLine.trim()).forEach((textLine, i, array) => {
|
||||
// Lines are either whitespace only, or a comment (with poential whitespace
|
||||
// around it). Drop whitespace-only lines.
|
||||
if (textLine === "") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (array[i - 1] === "" && seenComment) {
|
||||
// If a non-first comment is preceded by a blank (whitespace only) line,
|
||||
// add in a blank line.
|
||||
parts.push(concat([hardline, textLine]));
|
||||
} else {
|
||||
parts.push(textLine);
|
||||
}
|
||||
|
||||
seenComment = true;
|
||||
});
|
||||
|
||||
// If `lines` was whitespace only, return `null`.
|
||||
return parts.length === 0 ? null : join(hardline, parts);
|
||||
}
|
||||
|
||||
function dedent(str) {
|
||||
const firstMatchedIndent = str.match(/\n^( *)/m);
|
||||
const spaces = firstMatchedIndent === null ? 0 : firstMatchedIndent[1].length;
|
||||
@@ -206,7 +289,7 @@ function escapeBackticks(doc) {
|
||||
});
|
||||
}
|
||||
|
||||
function fromHtmlParser2(path, options) {
|
||||
function fromHtmlParser2(path, print, options) {
|
||||
const node = path.getValue();
|
||||
|
||||
switch (node.type) {
|
||||
@@ -220,11 +303,8 @@ function fromHtmlParser2(path, options) {
|
||||
parent.attribs.type === "application/javascript")
|
||||
) {
|
||||
const parser = options.parser === "flow" ? "flow" : "babylon";
|
||||
return {
|
||||
options: { parser },
|
||||
transformDoc: doc => concat([hardline, doc]),
|
||||
text: getText(options, node)
|
||||
};
|
||||
const doc = parseAndPrint(getText(options, node), { parser }, options);
|
||||
return concat([hardline, doc]);
|
||||
}
|
||||
|
||||
// Inline TypeScript
|
||||
@@ -233,20 +313,22 @@ function fromHtmlParser2(path, options) {
|
||||
(parent.attribs.type === "application/x-typescript" ||
|
||||
parent.attribs.lang === "ts")
|
||||
) {
|
||||
return {
|
||||
options: { parser: "typescript" },
|
||||
transformDoc: doc => concat([hardline, doc]),
|
||||
text: getText(options, node)
|
||||
};
|
||||
const doc = parseAndPrint(
|
||||
getText(options, node),
|
||||
{ parser: "typescript" },
|
||||
options
|
||||
);
|
||||
return concat([hardline, doc]);
|
||||
}
|
||||
|
||||
// Inline Styles
|
||||
if (parent.type === "style") {
|
||||
return {
|
||||
options: { parser: "css" },
|
||||
transformDoc: doc => concat([hardline, stripTrailingHardline(doc)]),
|
||||
text: getText(options, node)
|
||||
};
|
||||
const doc = parseAndPrint(
|
||||
getText(options, node),
|
||||
{ parser: "css" },
|
||||
options
|
||||
);
|
||||
return concat([hardline, stripTrailingHardline(doc)]);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -261,32 +343,31 @@ function fromHtmlParser2(path, options) {
|
||||
* @click="someFunction()"
|
||||
*/
|
||||
if (/(^@)|(^v-)|:/.test(node.key) && !/^\w+$/.test(node.value)) {
|
||||
return {
|
||||
text: node.value,
|
||||
options: {
|
||||
const doc = parseAndPrint(
|
||||
node.value,
|
||||
{
|
||||
parser: parseJavaScriptExpression,
|
||||
// Use singleQuote since HTML attributes use double-quotes.
|
||||
// TODO(azz): We still need to do an entity escape on the attribute.
|
||||
singleQuote: true
|
||||
},
|
||||
transformDoc: doc => {
|
||||
return concat([
|
||||
node.key,
|
||||
'="',
|
||||
util.hasNewlineInRange(node.value, 0, node.value.length)
|
||||
? doc
|
||||
: docUtils.removeLines(doc),
|
||||
'"'
|
||||
]);
|
||||
}
|
||||
};
|
||||
options
|
||||
);
|
||||
return concat([
|
||||
node.key,
|
||||
'="',
|
||||
util.hasNewlineInRange(node.value, 0, node.value.length)
|
||||
? doc
|
||||
: docUtils.removeLines(doc),
|
||||
'"'
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function transformCssDoc(quasisDoc, parent) {
|
||||
const parentNode = parent.path.getValue();
|
||||
function transformCssDoc(quasisDoc, path, print) {
|
||||
const parentNode = path.getValue();
|
||||
|
||||
const isEmpty =
|
||||
parentNode.quasis.length === 1 && !parentNode.quasis[0].value.raw.trim();
|
||||
@@ -295,7 +376,7 @@ function transformCssDoc(quasisDoc, parent) {
|
||||
}
|
||||
|
||||
const expressionDocs = parentNode.expressions
|
||||
? parent.path.map(parent.print, "expressions")
|
||||
? path.map(print, "expressions")
|
||||
: [];
|
||||
const newDoc = replacePlaceholders(quasisDoc, expressionDocs);
|
||||
/* istanbul ignore if */
|
||||
@@ -458,6 +539,5 @@ function isStyledIdentifier(node) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getSubtreeParser,
|
||||
printSubtree
|
||||
};
|
||||
+11
-13
@@ -122,20 +122,18 @@ function genericPrint(path, options, printPath, args) {
|
||||
}
|
||||
|
||||
if (node) {
|
||||
// Potentially switch to a different parser
|
||||
const next = multiparser.getSubtreeParser(path, options);
|
||||
if (next) {
|
||||
try {
|
||||
return multiparser.printSubtree(next, path, printPath, options);
|
||||
} catch (error) {
|
||||
/* istanbul ignore if */
|
||||
if (process.env.PRETTIER_DEBUG) {
|
||||
const e = new Error(error);
|
||||
e.parser = next.options.parser;
|
||||
throw e;
|
||||
}
|
||||
// Continue with current parser
|
||||
try {
|
||||
// Potentially switch to a different parser
|
||||
const sub = multiparser.printSubtree(path, printPath, options);
|
||||
if (sub) {
|
||||
return sub;
|
||||
}
|
||||
} catch (error) {
|
||||
/* istanbul ignore if */
|
||||
if (process.env.PRETTIER_DEBUG) {
|
||||
throw error;
|
||||
}
|
||||
// Continue with current parser
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`expressions.js 1`] = `
|
||||
// We currently don't support expressions in GraphQL template literals so these templates
|
||||
// should not change.
|
||||
|
||||
graphql(schema, \`
|
||||
query allPartsByManufacturerName($name: String!) {
|
||||
allParts(filter:{manufacturer: {name: $name}}) {
|
||||
@@ -20,29 +17,28 @@ query allPartsByManufacturerName($name: String!) {
|
||||
\${fragments.all}
|
||||
\`)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// We currently don't support expressions in GraphQL template literals so these templates
|
||||
// should not change.
|
||||
|
||||
graphql(
|
||||
schema,
|
||||
\`
|
||||
query allPartsByManufacturerName($name: String!) {
|
||||
allParts(filter:{manufacturer: {name: $name}}) {
|
||||
... PartAll
|
||||
}}
|
||||
\${fragments.all}
|
||||
\`
|
||||
query allPartsByManufacturerName($name: String!) {
|
||||
allParts(filter: { manufacturer: { name: $name } }) {
|
||||
...PartAll
|
||||
}
|
||||
}
|
||||
\${fragments.all}
|
||||
\`
|
||||
);
|
||||
|
||||
const veryLongVariableNameToMakeTheLineBreak = graphql(
|
||||
schema,
|
||||
\`
|
||||
query allPartsByManufacturerName($name: String!) {
|
||||
allParts(filter:{manufacturer: {name: $name}}) {
|
||||
... PartAll
|
||||
}}
|
||||
\${fragments.all}
|
||||
\`
|
||||
query allPartsByManufacturerName($name: String!) {
|
||||
allParts(filter: { manufacturer: { name: $name } }) {
|
||||
...PartAll
|
||||
}
|
||||
}
|
||||
\${fragments.all}
|
||||
\`
|
||||
);
|
||||
|
||||
`;
|
||||
@@ -82,6 +78,153 @@ const query = gql\`
|
||||
}
|
||||
}
|
||||
\`;
|
||||
|
||||
|
||||
// With interpolations:
|
||||
|
||||
gql\`
|
||||
query User {
|
||||
user(id:5){
|
||||
...UserDetails
|
||||
...Friends
|
||||
}
|
||||
}
|
||||
|
||||
\${USER_DETAILS_FRAGMENT}\${FRIENDS_FRAGMENT}
|
||||
\`
|
||||
|
||||
|
||||
// Skip if non-toplevel interpolation:
|
||||
|
||||
gql\`
|
||||
query User {
|
||||
user(id:\${id}){ name }
|
||||
}
|
||||
\`
|
||||
|
||||
|
||||
// Skip if top-level interpolation within comment:
|
||||
|
||||
gql\`
|
||||
query User {
|
||||
user(id:5){ name }
|
||||
}
|
||||
#\${test}
|
||||
\`
|
||||
|
||||
|
||||
// Comment on last line:
|
||||
|
||||
gql\`
|
||||
query User {
|
||||
user(id:5){ name }
|
||||
}
|
||||
# comment\`
|
||||
// \` <-- editor syntax highlighting workaround
|
||||
|
||||
|
||||
// Preserve up to one blank line between things and enforce linebreak between
|
||||
// interpolations:
|
||||
|
||||
gql\`
|
||||
# comment
|
||||
\${one}\${two} \${three}
|
||||
\${four}
|
||||
|
||||
\${five}
|
||||
# comment
|
||||
\${six}
|
||||
|
||||
# comment
|
||||
\${seven}
|
||||
# comment
|
||||
|
||||
\${eight}
|
||||
|
||||
# comment with trailing whitespace
|
||||
|
||||
|
||||
# blank line above this comment
|
||||
|
||||
|
||||
\`
|
||||
|
||||
|
||||
// Interpolation directly before and after query:
|
||||
|
||||
gql\`\${one} query Test { test }\${two}\`
|
||||
|
||||
|
||||
// Only interpolation:
|
||||
|
||||
gql\`\${test}\`
|
||||
|
||||
|
||||
// Only comment:
|
||||
|
||||
gql\`# comment\`
|
||||
// \` <-- editor syntax highlighting workaround
|
||||
|
||||
|
||||
// Only whitespace:
|
||||
|
||||
gql\` \`
|
||||
|
||||
|
||||
// Empty:
|
||||
|
||||
gql\`\`
|
||||
|
||||
|
||||
// Comments after other things:
|
||||
// Currently, comments after interpolations are moved to the next line.
|
||||
// We might want to keep them on the next line in the future.
|
||||
|
||||
gql\`
|
||||
\${test} # comment
|
||||
|
||||
query Test { # comment
|
||||
test # comment
|
||||
} # comment
|
||||
\${test} # comment
|
||||
\${test} # comment
|
||||
|
||||
\${test} # comment
|
||||
|
||||
# comment
|
||||
\${test} # comment
|
||||
\`
|
||||
|
||||
|
||||
// Larger mixed test:
|
||||
|
||||
gql\`
|
||||
|
||||
|
||||
|
||||
query User {
|
||||
test
|
||||
}
|
||||
|
||||
|
||||
|
||||
\${USER_DETAILS_FRAGMENT}
|
||||
|
||||
# Comment
|
||||
# that continues on a new line
|
||||
|
||||
|
||||
# and has a blank line in the middle
|
||||
|
||||
\${FRIENDS_FRAGMENT}
|
||||
\${generateFragment({
|
||||
totally: "a good idea"
|
||||
})}
|
||||
|
||||
\${fragment}#comment
|
||||
|
||||
fragment another on User { name
|
||||
}\${ fragment }\`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
import gql from "graphql-tag";
|
||||
|
||||
@@ -95,6 +238,158 @@ const query = gql\`
|
||||
}
|
||||
\`;
|
||||
|
||||
// With interpolations:
|
||||
|
||||
gql\`
|
||||
query User {
|
||||
user(id: 5) {
|
||||
...UserDetails
|
||||
...Friends
|
||||
}
|
||||
}
|
||||
|
||||
\${USER_DETAILS_FRAGMENT}
|
||||
\${FRIENDS_FRAGMENT}
|
||||
\`;
|
||||
|
||||
// Skip if non-toplevel interpolation:
|
||||
|
||||
gql\`
|
||||
query User {
|
||||
user(id:\${id}){ name }
|
||||
}
|
||||
\`;
|
||||
|
||||
// Skip if top-level interpolation within comment:
|
||||
|
||||
gql\`
|
||||
query User {
|
||||
user(id:5){ name }
|
||||
}
|
||||
#\${test}
|
||||
\`;
|
||||
|
||||
// Comment on last line:
|
||||
|
||||
gql\`
|
||||
query User {
|
||||
user(id: 5) {
|
||||
name
|
||||
}
|
||||
}
|
||||
# comment
|
||||
\`;
|
||||
// \` <-- editor syntax highlighting workaround
|
||||
|
||||
// Preserve up to one blank line between things and enforce linebreak between
|
||||
// interpolations:
|
||||
|
||||
gql\`
|
||||
# comment
|
||||
\${one}
|
||||
\${two}
|
||||
\${three}
|
||||
\${four}
|
||||
|
||||
\${five}
|
||||
# comment
|
||||
\${six}
|
||||
|
||||
# comment
|
||||
\${seven}
|
||||
# comment
|
||||
|
||||
\${eight}
|
||||
|
||||
# comment with trailing whitespace
|
||||
|
||||
# blank line above this comment
|
||||
\`;
|
||||
|
||||
// Interpolation directly before and after query:
|
||||
|
||||
gql\`
|
||||
\${one}
|
||||
query Test {
|
||||
test
|
||||
}
|
||||
\${two}
|
||||
\`;
|
||||
|
||||
// Only interpolation:
|
||||
|
||||
gql\`
|
||||
\${test}
|
||||
\`;
|
||||
|
||||
// Only comment:
|
||||
|
||||
gql\`
|
||||
# comment
|
||||
\`;
|
||||
// \` <-- editor syntax highlighting workaround
|
||||
|
||||
// Only whitespace:
|
||||
|
||||
gql\`\`;
|
||||
|
||||
// Empty:
|
||||
|
||||
gql\`\`;
|
||||
|
||||
// Comments after other things:
|
||||
// Currently, comments after interpolations are moved to the next line.
|
||||
// We might want to keep them on the next line in the future.
|
||||
|
||||
gql\`
|
||||
\${test}
|
||||
# comment
|
||||
|
||||
query Test {
|
||||
# comment
|
||||
test # comment
|
||||
} # comment
|
||||
\${test}
|
||||
# comment
|
||||
\${test}
|
||||
# comment
|
||||
|
||||
\${test}
|
||||
# comment
|
||||
|
||||
# comment
|
||||
\${test}
|
||||
# comment
|
||||
\`;
|
||||
|
||||
// Larger mixed test:
|
||||
|
||||
gql\`
|
||||
query User {
|
||||
test
|
||||
}
|
||||
|
||||
\${USER_DETAILS_FRAGMENT}
|
||||
|
||||
# Comment
|
||||
# that continues on a new line
|
||||
|
||||
# and has a blank line in the middle
|
||||
|
||||
\${FRIENDS_FRAGMENT}
|
||||
\${generateFragment({
|
||||
totally: "a good idea"
|
||||
})}
|
||||
|
||||
\${fragment}
|
||||
#comment
|
||||
|
||||
fragment another on User {
|
||||
name
|
||||
}
|
||||
\${fragment}
|
||||
\`;
|
||||
|
||||
`;
|
||||
|
||||
exports[`react-relay.js 1`] = `
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// We currently don't support expressions in GraphQL template literals so these templates
|
||||
// should not change.
|
||||
|
||||
graphql(schema, `
|
||||
query allPartsByManufacturerName($name: String!) {
|
||||
allParts(filter:{manufacturer: {name: $name}}) {
|
||||
|
||||
@@ -9,3 +9,150 @@ const query = gql`
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
// With interpolations:
|
||||
|
||||
gql`
|
||||
query User {
|
||||
user(id:5){
|
||||
...UserDetails
|
||||
...Friends
|
||||
}
|
||||
}
|
||||
|
||||
${USER_DETAILS_FRAGMENT}${FRIENDS_FRAGMENT}
|
||||
`
|
||||
|
||||
|
||||
// Skip if non-toplevel interpolation:
|
||||
|
||||
gql`
|
||||
query User {
|
||||
user(id:${id}){ name }
|
||||
}
|
||||
`
|
||||
|
||||
|
||||
// Skip if top-level interpolation within comment:
|
||||
|
||||
gql`
|
||||
query User {
|
||||
user(id:5){ name }
|
||||
}
|
||||
#${test}
|
||||
`
|
||||
|
||||
|
||||
// Comment on last line:
|
||||
|
||||
gql`
|
||||
query User {
|
||||
user(id:5){ name }
|
||||
}
|
||||
# comment`
|
||||
// ` <-- editor syntax highlighting workaround
|
||||
|
||||
|
||||
// Preserve up to one blank line between things and enforce linebreak between
|
||||
// interpolations:
|
||||
|
||||
gql`
|
||||
# comment
|
||||
${one}${two} ${three}
|
||||
${four}
|
||||
|
||||
${five}
|
||||
# comment
|
||||
${six}
|
||||
|
||||
# comment
|
||||
${seven}
|
||||
# comment
|
||||
|
||||
${eight}
|
||||
|
||||
# comment with trailing whitespace
|
||||
|
||||
|
||||
# blank line above this comment
|
||||
|
||||
|
||||
`
|
||||
|
||||
|
||||
// Interpolation directly before and after query:
|
||||
|
||||
gql`${one} query Test { test }${two}`
|
||||
|
||||
|
||||
// Only interpolation:
|
||||
|
||||
gql`${test}`
|
||||
|
||||
|
||||
// Only comment:
|
||||
|
||||
gql`# comment`
|
||||
// ` <-- editor syntax highlighting workaround
|
||||
|
||||
|
||||
// Only whitespace:
|
||||
|
||||
gql` `
|
||||
|
||||
|
||||
// Empty:
|
||||
|
||||
gql``
|
||||
|
||||
|
||||
// Comments after other things:
|
||||
// Currently, comments after interpolations are moved to the next line.
|
||||
// We might want to keep them on the next line in the future.
|
||||
|
||||
gql`
|
||||
${test} # comment
|
||||
|
||||
query Test { # comment
|
||||
test # comment
|
||||
} # comment
|
||||
${test} # comment
|
||||
${test} # comment
|
||||
|
||||
${test} # comment
|
||||
|
||||
# comment
|
||||
${test} # comment
|
||||
`
|
||||
|
||||
|
||||
// Larger mixed test:
|
||||
|
||||
gql`
|
||||
|
||||
|
||||
|
||||
query User {
|
||||
test
|
||||
}
|
||||
|
||||
|
||||
|
||||
${USER_DETAILS_FRAGMENT}
|
||||
|
||||
# Comment
|
||||
# that continues on a new line
|
||||
|
||||
|
||||
# and has a blank line in the middle
|
||||
|
||||
${FRIENDS_FRAGMENT}
|
||||
${generateFragment({
|
||||
totally: "a good idea"
|
||||
})}
|
||||
|
||||
${fragment}#comment
|
||||
|
||||
fragment another on User { name
|
||||
}${ fragment }`
|
||||
Reference in new issue
Block a user