Skip to content

Commit ce38bb4

Browse files
committed
Unify 'print' and 'printSchema' output for block strings
1 parent 60a2bf8 commit ce38bb4

File tree

4 files changed

+44
-61
lines changed

4 files changed

+44
-61
lines changed

src/language/__tests__/schema-printer-test.js

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -54,18 +54,12 @@ describe('Printer: SDL document', () => {
5454
type Foo implements Bar & Baz {
5555
"Description of the \`one\` field."
5656
one: Type
57-
"""
58-
This is a description of the \`two\` field.
59-
"""
57+
"""This is a description of the \`two\` field."""
6058
two(
61-
"""
62-
This is a description of the \`argument\` argument.
63-
"""
59+
"""This is a description of the \`argument\` argument."""
6460
argument: InputType!
6561
): Type
66-
"""
67-
This is a description of the \`three\` field.
68-
"""
62+
"""This is a description of the \`three\` field."""
6963
three(argument: InputType, other: String): Int
7064
four(argument: String = "string"): String
7165
five(argument: [String] = ["string", "string"]): String
@@ -121,13 +115,9 @@ describe('Printer: SDL document', () => {
121115
extend scalar CustomScalar @onScalar
122116
123117
enum Site {
124-
"""
125-
This is a description of the \`DESKTOP\` value
126-
"""
118+
"""This is a description of the \`DESKTOP\` value"""
127119
DESKTOP
128-
"""
129-
This is a description of the \`MOBILE\` value
130-
"""
120+
"""This is a description of the \`MOBILE\` value"""
131121
MOBILE
132122
"This is a description of the \`WEB\` value"
133123
WEB
@@ -163,9 +153,7 @@ describe('Printer: SDL document', () => {
163153
164154
extend input InputType @onInputObject
165155
166-
"""
167-
This is a description of the \`@skip\` directive
168-
"""
156+
"""This is a description of the \`@skip\` directive"""
169157
directive @skip(if: Boolean! @onArgumentDefinition) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
170158
171159
directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT

src/language/blockStringValue.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,32 @@ function leadingWhitespace(str) {
6262
function isBlank(str) {
6363
return leadingWhitespace(str) === str.length;
6464
}
65+
66+
/**
67+
* Print a block string in the indented block form by adding a leading and
68+
* trailing blank line. However, if a block string starts with whitespace and is
69+
* a single-line, adding a leading blank line would strip that whitespace.
70+
*/
71+
export function printBlockString(
72+
value: string,
73+
indentation?: string = '',
74+
preferMultipleLines?: ?boolean = false,
75+
): string {
76+
const isSingleLine = value.indexOf('\n') === -1;
77+
const hasLeadingSpace = value[0] === ' ' || value[0] === '\t';
78+
const hasTrailingQuote = value[value.length - 1] === '"';
79+
const printAsMultipleLines =
80+
!isSingleLine || hasTrailingQuote || preferMultipleLines;
81+
82+
let result = '';
83+
// Format a multi-line block quote to account for leading space.
84+
if (printAsMultipleLines && !(isSingleLine && hasLeadingSpace)) {
85+
result += '\n' + indentation;
86+
}
87+
result += indentation ? value.replace(/\n/g, '\n' + indentation) : value;
88+
if (printAsMultipleLines) {
89+
result += '\n';
90+
}
91+
92+
return '"""' + result.replace(/"""/g, '\\"""') + '"""';
93+
}

src/language/printer.js

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import type { ASTNode } from './ast';
1111
import { visit } from './visitor';
12+
import { printBlockString } from './blockStringValue';
1213

1314
/**
1415
* Converts an AST into a string, using one set of reasonable
@@ -90,7 +91,7 @@ const printDocASTReducer: any = {
9091
FloatValue: ({ value }) => value,
9192
StringValue: ({ value, block: isBlockString }, key) =>
9293
isBlockString
93-
? printBlockString(value, key === 'description')
94+
? printBlockString(value, key === 'description' ? '' : ' ')
9495
: JSON.stringify(value),
9596
BooleanValue: ({ value }) => (value ? 'true' : 'false'),
9697
NullValue: () => 'null',
@@ -273,15 +274,3 @@ function isMultiline(string) {
273274
function hasMultilineItems(maybeArray) {
274275
return maybeArray && maybeArray.some(isMultiline);
275276
}
276-
277-
/**
278-
* Print a block string in the indented block form by adding a leading and
279-
* trailing blank line. However, if a block string starts with whitespace and is
280-
* a single-line, adding a leading blank line would strip that whitespace.
281-
*/
282-
function printBlockString(value, isDescription) {
283-
const escaped = value.replace(/"""/g, '\\"""');
284-
return isMultiline(value) || (value[0] !== ' ' && value[0] !== '\t')
285-
? `"""\n${isDescription ? escaped : indent(escaped)}\n"""`
286-
: `"""${escaped.replace(/"$/, '"\n')}"""`;
287-
}

src/utilities/schemaPrinter.js

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import objectValues from '../polyfills/objectValues';
1212
import inspect from '../jsutils/inspect';
1313
import { astFromValue } from '../utilities/astFromValue';
1414
import { print } from '../language/printer';
15+
import { printBlockString } from '../language/blockStringValue';
1516
import type { GraphQLSchema } from '../type/schema';
1617
import {
1718
isScalarType,
@@ -329,37 +330,13 @@ function printDescription(
329330
return printDescriptionWithComments(lines, indentation, firstInBlock);
330331
}
331332
332-
let description =
333-
indentation && !firstInBlock
334-
? '\n' + indentation + '"""'
335-
: indentation + '"""';
336-
337-
// In some circumstances, a single line can be used for the description.
338-
if (
339-
lines.length === 1 &&
340-
lines[0].length < 70 &&
341-
lines[0][lines[0].length - 1] !== '"'
342-
) {
343-
return description + escapeQuote(lines[0]) + '"""\n';
344-
}
345-
346-
// Format a multi-line block quote to account for leading space.
347-
const hasLeadingSpace = lines[0][0] === ' ' || lines[0][0] === '\t';
348-
if (!hasLeadingSpace) {
349-
description += '\n';
350-
}
351-
for (let i = 0; i < lines.length; i++) {
352-
if (i !== 0 || !hasLeadingSpace) {
353-
description += indentation;
354-
}
355-
description += escapeQuote(lines[i]) + '\n';
356-
}
357-
description += indentation + '"""\n';
358-
return description;
359-
}
333+
const text = lines.join('\n');
334+
const preferMultipleLines = text.length > 70;
335+
const blockString = printBlockString(text, '', preferMultipleLines);
336+
const prefix =
337+
indentation && !firstInBlock ? '\n' + indentation : indentation;
360338
361-
function escapeQuote(line) {
362-
return line.replace(/"""/g, '\\"""');
339+
return prefix + blockString.replace(/\n/g, '\n' + indentation) + '\n';
363340
}
364341
365342
function printDescriptionWithComments(lines, indentation, firstInBlock) {

0 commit comments

Comments
 (0)