123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- import { isWhiteSpace } from './characterClasses.mjs';
- /**
- * Produces the value of a block string from its parsed raw value, similar to
- * CoffeeScript's block string, Python's docstring trim or Ruby's strip_heredoc.
- *
- * This implements the GraphQL spec's BlockStringValue() static algorithm.
- *
- * @internal
- */
- export function dedentBlockStringLines(lines) {
- var _firstNonEmptyLine2;
- let commonIndent = Number.MAX_SAFE_INTEGER;
- let firstNonEmptyLine = null;
- let lastNonEmptyLine = -1;
- for (let i = 0; i < lines.length; ++i) {
- var _firstNonEmptyLine;
- const line = lines[i];
- const indent = leadingWhitespace(line);
- if (indent === line.length) {
- continue; // skip empty lines
- }
- firstNonEmptyLine =
- (_firstNonEmptyLine = firstNonEmptyLine) !== null &&
- _firstNonEmptyLine !== void 0
- ? _firstNonEmptyLine
- : i;
- lastNonEmptyLine = i;
- if (i !== 0 && indent < commonIndent) {
- commonIndent = indent;
- }
- }
- return lines // Remove common indentation from all lines but first.
- .map((line, i) => (i === 0 ? line : line.slice(commonIndent))) // Remove leading and trailing blank lines.
- .slice(
- (_firstNonEmptyLine2 = firstNonEmptyLine) !== null &&
- _firstNonEmptyLine2 !== void 0
- ? _firstNonEmptyLine2
- : 0,
- lastNonEmptyLine + 1,
- );
- }
- function leadingWhitespace(str) {
- let i = 0;
- while (i < str.length && isWhiteSpace(str.charCodeAt(i))) {
- ++i;
- }
- return i;
- }
- /**
- * @internal
- */
- export function isPrintableAsBlockString(value) {
- if (value === '') {
- return true; // empty string is printable
- }
- let isEmptyLine = true;
- let hasIndent = false;
- let hasCommonIndent = true;
- let seenNonEmptyLine = false;
- for (let i = 0; i < value.length; ++i) {
- switch (value.codePointAt(i)) {
- case 0x0000:
- case 0x0001:
- case 0x0002:
- case 0x0003:
- case 0x0004:
- case 0x0005:
- case 0x0006:
- case 0x0007:
- case 0x0008:
- case 0x000b:
- case 0x000c:
- case 0x000e:
- case 0x000f:
- return false;
- // Has non-printable characters
- case 0x000d:
- // \r
- return false;
- // Has \r or \r\n which will be replaced as \n
- case 10:
- // \n
- if (isEmptyLine && !seenNonEmptyLine) {
- return false; // Has leading new line
- }
- seenNonEmptyLine = true;
- isEmptyLine = true;
- hasIndent = false;
- break;
- case 9: // \t
- case 32:
- // <space>
- hasIndent || (hasIndent = isEmptyLine);
- break;
- default:
- hasCommonIndent && (hasCommonIndent = hasIndent);
- isEmptyLine = false;
- }
- }
- if (isEmptyLine) {
- return false; // Has trailing empty lines
- }
- if (hasCommonIndent && seenNonEmptyLine) {
- return false; // Has internal indent
- }
- return true;
- }
- /**
- * Print a block string in the indented block form by adding a leading and
- * trailing blank line. However, if a block string starts with whitespace and is
- * a single-line, adding a leading blank line would strip that whitespace.
- *
- * @internal
- */
- export function printBlockString(value, options) {
- const escapedValue = value.replace(/"""/g, '\\"""'); // Expand a block string's raw value into independent lines.
- const lines = escapedValue.split(/\r\n|[\n\r]/g);
- const isSingleLine = lines.length === 1; // If common indentation is found we can fix some of those cases by adding leading new line
- const forceLeadingNewLine =
- lines.length > 1 &&
- lines
- .slice(1)
- .every((line) => line.length === 0 || isWhiteSpace(line.charCodeAt(0))); // Trailing triple quotes just looks confusing but doesn't force trailing new line
- const hasTrailingTripleQuotes = escapedValue.endsWith('\\"""'); // Trailing quote (single or double) or slash forces trailing new line
- const hasTrailingQuote = value.endsWith('"') && !hasTrailingTripleQuotes;
- const hasTrailingSlash = value.endsWith('\\');
- const forceTrailingNewline = hasTrailingQuote || hasTrailingSlash;
- const printAsMultipleLines =
- !(options !== null && options !== void 0 && options.minimize) && // add leading and trailing new lines only if it improves readability
- (!isSingleLine ||
- value.length > 70 ||
- forceTrailingNewline ||
- forceLeadingNewLine ||
- hasTrailingTripleQuotes);
- let result = ''; // Format a multi-line block quote to account for leading space.
- const skipLeadingNewLine = isSingleLine && isWhiteSpace(value.charCodeAt(0));
- if ((printAsMultipleLines && !skipLeadingNewLine) || forceLeadingNewLine) {
- result += '\n';
- }
- result += escapedValue;
- if (printAsMultipleLines || forceTrailingNewline) {
- result += '\n';
- }
- return '"""' + result + '"""';
- }
|