UNPKG

3.14 kBJavaScriptView Raw
1import { Source, isSource } from "../language/source.mjs";
2import { TokenKind } from "../language/tokenKind.mjs";
3import { Lexer, isPunctuatorTokenKind } from "../language/lexer.mjs";
4import { dedentBlockStringValue, getBlockStringIndentation } from "../language/blockString.mjs";
5/**
6 * Strips characters that are not significant to the validity or execution
7 * of a GraphQL document:
8 * - UnicodeBOM
9 * - WhiteSpace
10 * - LineTerminator
11 * - Comment
12 * - Comma
13 * - BlockString indentation
14 *
15 * Note: It is required to have a delimiter character between neighboring
16 * non-punctuator tokens and this function always uses single space as delimiter.
17 *
18 * It is guaranteed that both input and output documents if parsed would result
19 * in the exact same AST except for nodes location.
20 *
21 * Warning: It is guaranteed that this function will always produce stable results.
22 * However, it's not guaranteed that it will stay the same between different
23 * releases due to bugfixes or changes in the GraphQL specification.
24 *
25 * Query example:
26 *
27 * query SomeQuery($foo: String!, $bar: String) {
28 * someField(foo: $foo, bar: $bar) {
29 * a
30 * b {
31 * c
32 * d
33 * }
34 * }
35 * }
36 *
37 * Becomes:
38 *
39 * query SomeQuery($foo:String!$bar:String){someField(foo:$foo bar:$bar){a b{c d}}}
40 *
41 * SDL example:
42 *
43 * """
44 * Type description
45 * """
46 * type Foo {
47 * """
48 * Field description
49 * """
50 * bar: String
51 * }
52 *
53 * Becomes:
54 *
55 * """Type description""" type Foo{"""Field description""" bar:String}
56 */
57
58export function stripIgnoredCharacters(source) {
59 var sourceObj = isSource(source) ? source : new Source(source);
60 var body = sourceObj.body;
61 var lexer = new Lexer(sourceObj);
62 var strippedBody = '';
63 var wasLastAddedTokenNonPunctuator = false;
64
65 while (lexer.advance().kind !== TokenKind.EOF) {
66 var currentToken = lexer.token;
67 var tokenKind = currentToken.kind;
68 /**
69 * Every two non-punctuator tokens should have space between them.
70 * Also prevent case of non-punctuator token following by spread resulting
71 * in invalid token (e.g. `1...` is invalid Float token).
72 */
73
74 var isNonPunctuator = !isPunctuatorTokenKind(currentToken.kind);
75
76 if (wasLastAddedTokenNonPunctuator) {
77 if (isNonPunctuator || currentToken.kind === TokenKind.SPREAD) {
78 strippedBody += ' ';
79 }
80 }
81
82 var tokenBody = body.slice(currentToken.start, currentToken.end);
83
84 if (tokenKind === TokenKind.BLOCK_STRING) {
85 strippedBody += dedentBlockString(tokenBody);
86 } else {
87 strippedBody += tokenBody;
88 }
89
90 wasLastAddedTokenNonPunctuator = isNonPunctuator;
91 }
92
93 return strippedBody;
94}
95
96function dedentBlockString(blockStr) {
97 // skip leading and trailing triple quotations
98 var rawStr = blockStr.slice(3, -3);
99 var body = dedentBlockStringValue(rawStr);
100
101 if (getBlockStringIndentation(body) > 0) {
102 body = '\n' + body;
103 }
104
105 var lastChar = body[body.length - 1];
106 var hasTrailingQuote = lastChar === '"' && body.slice(-4) !== '\\"""';
107
108 if (hasTrailingQuote || lastChar === '\\') {
109 body += '\n';
110 }
111
112 return '"""' + body + '"""';
113}