Mirror: The spec-compliant minimum of client-side GraphQL.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: Optimize performance to match a baseline graphql.js target (#5)

* Optimize parser performance to meet graphql.js perf target

* Optimize printer performance

* Add changeset

* Apply lints

* Fix unused branch of GraphQLError

authored by

Phil Pluckthun and committed by
GitHub
fb366340 3ca9519c

+137 -116
+5
.changeset/stupid-clouds-switch.md
··· 1 + --- 2 + '@0no-co/graphql.web': patch 3 + --- 4 + 5 + Optimize performance of `print` and `parse` with minor adjustments.
+1 -1
src/error.ts
··· 38 38 } 39 39 } 40 40 41 - this.extensions = extensions || {}; 41 + this.extensions = _extensions || {}; 42 42 } 43 43 44 44 toJSON(): any {
+15 -6
src/parser.ts
··· 47 47 return out; 48 48 } 49 49 50 - const ignoredRe = /(?:[\s,]*|#[^\n\r]*)*/y; 50 + // Note: This is equivalent to: /(?:[\s,]*|#[^\n\r]*)*/y 51 51 function ignored() { 52 - ignoredRe.lastIndex = idx; 53 - ignoredRe.test(input); 54 - idx = ignoredRe.lastIndex; 52 + for ( 53 + let char = input.charCodeAt(idx++) | 0; 54 + char === 9 /*'\t'*/ || 55 + char === 10 /*'\n'*/ || 56 + char === 13 /*'\r'*/ || 57 + char === 32 /*' '*/ || 58 + char === 35 /*'#'*/ || 59 + char === 44 /*','*/ || 60 + char === 65279 /*'\ufeff'*/; 61 + char = input.charCodeAt(idx++) | 0 62 + ) { 63 + if (char === 35 /*'#'*/) while ((char = input.charCodeAt(idx++)) !== 10 && char !== 13); 64 + } 65 + idx--; 55 66 } 56 67 57 68 const nameRe = /[_\w][_\d\w]*/y; ··· 221 232 } 222 233 223 234 function field(): ast.FieldNode | undefined { 224 - ignored(); 225 235 let _name = name(); 226 236 if (_name) { 227 237 ignored(); ··· 296 306 const fragmentSpreadRe = /\.\.\./y; 297 307 298 308 function fragmentSpread(): ast.FragmentSpreadNode | ast.InlineFragmentNode | undefined { 299 - ignored(); 300 309 if (advance(fragmentSpreadRe)) { 301 310 ignored(); 302 311 const _idx = idx;
+116 -109
src/printer.ts
··· 13 13 14 14 const MAX_LINE_LENGTH = 80; 15 15 16 - export function print(node: ASTNode): string { 17 - let out: string; 18 - switch (node.kind) { 19 - case 'OperationDefinition': 20 - if ( 21 - node.operation === 'query' && 22 - !node.name && 23 - !hasItems(node.variableDefinitions) && 24 - !hasItems(node.directives) 25 - ) { 26 - return print(node.selectionSet); 27 - } 28 - out = node.operation; 29 - if (node.name) out += ' ' + node.name.value; 30 - if (hasItems(node.variableDefinitions)) { 31 - if (!node.name) out += ' '; 32 - out += '(' + node.variableDefinitions.map(print).join(', ') + ')'; 33 - } 34 - if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' '); 35 - return out + ' ' + print(node.selectionSet); 36 - 37 - case 'VariableDefinition': 38 - out = print(node.variable) + ': ' + print(node.type); 39 - if (node.defaultValue) out += ' = ' + print(node.defaultValue); 40 - if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' '); 41 - return out; 42 - 43 - case 'Field': 44 - out = (node.alias ? print(node.alias) + ': ' : '') + node.name.value; 45 - if (hasItems(node.arguments)) { 46 - const args = node.arguments.map(print); 47 - const argsLine = out + '(' + args.join(', ') + ')'; 48 - out = 49 - argsLine.length > MAX_LINE_LENGTH 50 - ? out + '(\n ' + args.join('\n').replace(/\n/g, '\n ') + '\n)' 51 - : argsLine; 52 - } 53 - if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' '); 54 - return node.selectionSet ? out + ' ' + print(node.selectionSet) : out; 55 - 56 - case 'StringValue': 57 - return node.block ? printBlockString(node.value) : printString(node.value); 58 - 59 - case 'BooleanValue': 60 - return '' + node.value; 61 - 62 - case 'NullValue': 63 - return 'null'; 64 - 65 - case 'IntValue': 66 - case 'FloatValue': 67 - case 'EnumValue': 68 - case 'Name': 69 - return node.value; 70 - 71 - case 'ListValue': 72 - return '[' + node.values.map(print).join(', ') + ']'; 73 - 74 - case 'ObjectValue': 75 - return '{' + node.fields.map(print).join(', ') + '}'; 76 - 77 - case 'ObjectField': 78 - return node.name.value + ': ' + print(node.value); 79 - 80 - case 'Variable': 81 - return '$' + node.name.value; 82 - 83 - case 'Document': 84 - return hasItems(node.definitions) ? node.definitions.map(print).join('\n\n') : ''; 85 - 86 - case 'SelectionSet': 87 - return '{\n ' + node.selections.map(print).join('\n').replace(/\n/g, '\n ') + '\n}'; 88 - 89 - case 'Argument': 90 - return node.name.value + ': ' + print(node.value); 91 - 92 - case 'FragmentSpread': 93 - out = '...' + node.name.value; 94 - if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' '); 95 - return out; 96 - 97 - case 'InlineFragment': 98 - out = '...'; 99 - if (node.typeCondition) out += ' on ' + node.typeCondition.name.value; 100 - if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' '); 101 - return out + ' ' + print(node.selectionSet); 102 - 103 - case 'FragmentDefinition': 104 - out = 'fragment ' + node.name.value; 105 - out += ' on ' + node.typeCondition.name.value; 106 - if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' '); 107 - return out + ' ' + print(node.selectionSet); 108 - 109 - case 'Directive': 110 - out = '@' + node.name.value; 111 - if (hasItems(node.arguments)) out += '(' + node.arguments.map(print).join(', ') + ')'; 112 - return out; 113 - 114 - case 'NamedType': 115 - return node.name.value; 116 - 117 - case 'ListType': 118 - return '[' + print(node.type) + ']'; 119 - 120 - case 'NonNullType': 121 - return print(node.type) + '!'; 16 + const nodes: { 17 + [NodeT in ASTNode as NodeT['kind']]?: (node: NodeT) => string; 18 + } = { 19 + OperationDefinition(node) { 20 + if ( 21 + node.operation === 'query' && 22 + !node.name && 23 + !hasItems(node.variableDefinitions) && 24 + !hasItems(node.directives) 25 + ) { 26 + return nodes.SelectionSet!(node.selectionSet); 27 + } 28 + let out: string = node.operation; 29 + if (node.name) out += ' ' + node.name.value; 30 + if (hasItems(node.variableDefinitions)) { 31 + if (!node.name) out += ' '; 32 + out += '(' + node.variableDefinitions.map(nodes.VariableDefinition!).join(', ') + ')'; 33 + } 34 + if (hasItems(node.directives)) out += ' ' + node.directives.map(nodes.Directive!).join(' '); 35 + return out + ' ' + nodes.SelectionSet!(node.selectionSet); 36 + }, 37 + VariableDefinition(node) { 38 + let out = nodes.Variable!(node.variable) + ': ' + print(node.type); 39 + if (node.defaultValue) out += ' = ' + print(node.defaultValue); 40 + if (hasItems(node.directives)) out += ' ' + node.directives.map(nodes.Directive!).join(' '); 41 + return out; 42 + }, 43 + Field(node) { 44 + let out = (node.alias ? node.alias.value + ': ' : '') + node.name.value; 45 + if (hasItems(node.arguments)) { 46 + const args = node.arguments.map(nodes.Argument!); 47 + const argsLine = out + '(' + args.join(', ') + ')'; 48 + out = 49 + argsLine.length > MAX_LINE_LENGTH 50 + ? out + '(\n ' + args.join('\n').replace(/\n/g, '\n ') + '\n)' 51 + : argsLine; 52 + } 53 + if (hasItems(node.directives)) out += ' ' + node.directives.map(nodes.Directive!).join(' '); 54 + return node.selectionSet ? out + ' ' + nodes.SelectionSet!(node.selectionSet) : out; 55 + }, 56 + StringValue(node) { 57 + return node.block ? printBlockString(node.value) : printString(node.value); 58 + }, 59 + BooleanValue(node) { 60 + return '' + node.value; 61 + }, 62 + NullValue(_node) { 63 + return 'null'; 64 + }, 65 + IntValue(node) { 66 + return node.value; 67 + }, 68 + FloatValue(node) { 69 + return node.value; 70 + }, 71 + EnumValue(node) { 72 + return node.value; 73 + }, 74 + Name(node) { 75 + return node.value; 76 + }, 77 + Variable(node) { 78 + return '$' + node.name.value; 79 + }, 80 + ListValue(node) { 81 + return '[' + node.values.map(print).join(', ') + ']'; 82 + }, 83 + ObjectValue(node) { 84 + return '{' + node.fields.map(nodes.ObjectField!).join(', ') + '}'; 85 + }, 86 + ObjectField(node) { 87 + return node.name.value + ': ' + print(node.value); 88 + }, 89 + Document(node) { 90 + return hasItems(node.definitions) ? node.definitions.map(print).join('\n\n') : ''; 91 + }, 92 + SelectionSet(node) { 93 + return '{\n ' + node.selections.map(print).join('\n').replace(/\n/g, '\n ') + '\n}'; 94 + }, 95 + Argument(node) { 96 + return node.name.value + ': ' + print(node.value); 97 + }, 98 + FragmentSpread(node) { 99 + let out = '...' + node.name.value; 100 + if (hasItems(node.directives)) out += ' ' + node.directives.map(nodes.Directive!).join(' '); 101 + return out; 102 + }, 103 + InlineFragment(node) { 104 + let out = '...'; 105 + if (node.typeCondition) out += ' on ' + node.typeCondition.name.value; 106 + if (hasItems(node.directives)) out += ' ' + node.directives.map(nodes.Directive!).join(' '); 107 + return out + ' ' + print(node.selectionSet); 108 + }, 109 + FragmentDefinition(node) { 110 + let out = 'fragment ' + node.name.value; 111 + out += ' on ' + node.typeCondition.name.value; 112 + if (hasItems(node.directives)) out += ' ' + node.directives.map(nodes.Directive!).join(' '); 113 + return out + ' ' + print(node.selectionSet); 114 + }, 115 + Directive(node) { 116 + let out = '@' + node.name.value; 117 + if (hasItems(node.arguments)) out += '(' + node.arguments.map(nodes.Argument!).join(', ') + ')'; 118 + return out; 119 + }, 120 + NamedType(node) { 121 + return node.name.value; 122 + }, 123 + ListType(node) { 124 + return '[' + print(node.type) + ']'; 125 + }, 126 + NonNullType(node) { 127 + return print(node.type) + '!'; 128 + }, 129 + }; 122 130 123 - default: 124 - return ''; 125 - } 131 + export function print(node: ASTNode): string { 132 + return nodes[node.kind] ? nodes[node.kind]!(node as any) : ''; 126 133 }