UNPKG

2.79 kBJavaScriptView Raw
1import { printBlockString } from '../language/blockString.mjs';
2import { isPunctuatorTokenKind, Lexer } from '../language/lexer.mjs';
3import { isSource, Source } from '../language/source.mjs';
4import { TokenKind } from '../language/tokenKind.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 * ```graphql
28 * query SomeQuery($foo: String!, $bar: String) {
29 * someField(foo: $foo, bar: $bar) {
30 * a
31 * b {
32 * c
33 * d
34 * }
35 * }
36 * }
37 * ```
38 *
39 * Becomes:
40 *
41 * ```graphql
42 * query SomeQuery($foo:String!$bar:String){someField(foo:$foo bar:$bar){a b{c d}}}
43 * ```
44 *
45 * SDL example:
46 *
47 * ```graphql
48 * """
49 * Type description
50 * """
51 * type Foo {
52 * """
53 * Field description
54 * """
55 * bar: String
56 * }
57 * ```
58 *
59 * Becomes:
60 *
61 * ```graphql
62 * """Type description""" type Foo{"""Field description""" bar:String}
63 * ```
64 */
65
66export function stripIgnoredCharacters(source) {
67 const sourceObj = isSource(source) ? source : new Source(source);
68 const body = sourceObj.body;
69 const lexer = new Lexer(sourceObj);
70 let strippedBody = '';
71 let wasLastAddedTokenNonPunctuator = false;
72
73 while (lexer.advance().kind !== TokenKind.EOF) {
74 const currentToken = lexer.token;
75 const tokenKind = currentToken.kind;
76 /**
77 * Every two non-punctuator tokens should have space between them.
78 * Also prevent case of non-punctuator token following by spread resulting
79 * in invalid token (e.g. `1...` is invalid Float token).
80 */
81
82 const isNonPunctuator = !isPunctuatorTokenKind(currentToken.kind);
83
84 if (wasLastAddedTokenNonPunctuator) {
85 if (isNonPunctuator || currentToken.kind === TokenKind.SPREAD) {
86 strippedBody += ' ';
87 }
88 }
89
90 const tokenBody = body.slice(currentToken.start, currentToken.end);
91
92 if (tokenKind === TokenKind.BLOCK_STRING) {
93 strippedBody += printBlockString(currentToken.value, {
94 minimize: true,
95 });
96 } else {
97 strippedBody += tokenBody;
98 }
99
100 wasLastAddedTokenNonPunctuator = isNonPunctuator;
101 }
102
103 return strippedBody;
104}