···
-
const nameRe = /[_A-Za-z]\w*/y;
-
// NOTE: This should be compressed by our build step
-
// This merges all possible value parsing into one regular expression
-
const valueRe = new RegExp(
-
// `null`, `true`, and `false` literals (BooleanValue & NullValue)
-
// Variables starting with `$` then having a name (VariableNode)
-
// Numbers, starting with int then optionally following with a float part (IntValue and FloatValue)
-
'(-?\\d+)((?:\\.\\d+)?[eE][+-]?\\d+|\\.\\d+)?|' +
-
// Block strings starting with `"""` until the next unescaped `"""` (StringValue)
-
'("""(?:"""|(?:[\\s\\S]*?[^\\\\])"""))|' +
-
// Strings starting with `"` must be on one line (StringValue)
-
'("(?:"|[^\\r\\n]*?[^\\\\]"))|' + // string
-
// Enums are simply names except for our literals (EnumValue)
-
// NOTE: Each of the groups above end up in the RegExpExecArray at the specified indices (starting with 1)
-
const enum ValueGroup {
-
type ValueExec = RegExpExecArray & {
-
[Prop in ValueGroup]: string | undefined;
-
const complexStringRe = /\\/;
function value(constant: true): ast.ConstValueNode;
function value(constant: boolean): ast.ValueNode;
function value(constant: boolean): ast.ValueNode {
let match: string | undefined;
-
let exec: ValueExec | null;
-
valueRe.lastIndex = idx;
-
if (input.charCodeAt(idx) === 91 /*'['*/) {
-
// Lists are checked ahead of time with `[` chars
-
const values: ast.ValueNode[] = [];
-
while (input.charCodeAt(idx) !== 93 /*']'*/) values.push(value(constant));
-
kind: 'ListValue' as Kind.LIST,
-
} else if (input.charCodeAt(idx) === 123 /*'{'*/) {
-
// Objects are checked ahead of time with `{` chars
-
const fields: ast.ObjectFieldNode[] = [];
-
while (input.charCodeAt(idx) !== 125 /*'}'*/) {
-
if ((match = advance(nameRe)) == null) throw error('ObjectField');
-
if (input.charCodeAt(idx++) !== 58 /*':'*/) throw error('ObjectField');
-
kind: 'ObjectField' as Kind.OBJECT_FIELD,
-
name: { kind: 'Name' as Kind.NAME, value: match },
-
value: value(constant),
-
kind: 'ObjectValue' as Kind.OBJECT,
-
} else if ((exec = valueRe.exec(input) as ValueExec) != null) {
-
// Starting from here, the merged `valueRe` is used
-
idx = valueRe.lastIndex;
-
if ((match = exec[ValueGroup.Const]) != null) {
-
return match === 'null'
-
? { kind: 'NullValue' as Kind.NULL }
-
kind: 'BooleanValue' as Kind.BOOLEAN,
-
value: match === 'true',
-
} else if ((match = exec[ValueGroup.Var]) != null) {
-
throw error('Variable');
-
kind: 'Variable' as Kind.VARIABLE,
-
kind: 'Name' as Kind.NAME,
-
} else if ((match = exec[ValueGroup.Int]) != null) {
-
let floatPart: string | undefined;
-
if ((floatPart = exec[ValueGroup.Float]) != null) {
kind: 'FloatValue' as Kind.FLOAT,
-
value: match + floatPart,
kind: 'IntValue' as Kind.INT,
-
} else if ((match = exec[ValueGroup.BlockString]) != null) {
-
kind: 'StringValue' as Kind.STRING,
-
value: blockString(match.slice(3, -3)),
-
} else if ((match = exec[ValueGroup.String]) != null) {
-
kind: 'StringValue' as Kind.STRING,
-
// When strings don't contain escape codes, a simple slice will be enough, otherwise
-
// `JSON.parse` matches GraphQL's string parsing perfectly
-
value: complexStringRe.test(match) ? (JSON.parse(match) as string) : match.slice(1, -1),
-
} else if ((match = exec[ValueGroup.Enum]) != null) {
-
kind: 'EnumValue' as Kind.ENUM,
function arguments_(constant: boolean): ast.ArgumentNode[] | undefined {
···
const args: ast.ArgumentNode[] = [];
-
let _name: string | undefined;
-
if ((_name = advance(nameRe)) == null) throw error('Argument');
if (input.charCodeAt(idx++) !== 58 /*':'*/) throw error('Argument');
kind: 'Argument' as Kind.ARGUMENT,
-
name: { kind: 'Name' as Kind.NAME, value: _name },
} while (input.charCodeAt(idx) !== 41 /*')'*/);
···
function directives(constant: boolean): ast.DirectiveNode[] | undefined {
if (input.charCodeAt(idx) === 64 /*'@'*/) {
const directives: ast.DirectiveNode[] = [];
-
let _name: string | undefined;
-
if ((_name = advance(nameRe)) == null) throw error('Directive');
kind: 'Directive' as Kind.DIRECTIVE,
-
name: { kind: 'Name' as Kind.NAME, value: _name },
arguments: arguments_(constant),
} while (input.charCodeAt(idx) === 64 /*'@'*/);
···
function type(): ast.TypeNode {
-
let match: string | undefined;
while (input.charCodeAt(idx) === 91 /*'['*/) {
-
if ((match = advance(nameRe)) == null) throw error('NamedType');
let type: ast.TypeNode = {
kind: 'NamedType' as Kind.NAMED_TYPE,
-
name: { kind: 'Name' as Kind.NAME, value: match },
if (input.charCodeAt(idx) === 33 /*'!'*/) {
···
-
// NOTE: This should be compressed by our build step
-
// This merges the two possible selection parsing branches into one regular expression
-
const selectionRe = new RegExp(
-
// fragment spreads (FragmentSpread or InlineFragment nodes)
-
// field aliases or names (FieldNode)
-
// NOTE: Each of the groups above end up in the RegExpExecArray at the indices 1&2
-
const enum SelectionGroup {
-
type SelectionExec = RegExpExecArray & {
-
[Prop in SelectionGroup]: string | undefined;
function selectionSet(): ast.SelectionSetNode {
const selections: ast.SelectionNode[] = [];
-
let match: string | undefined;
-
let exec: SelectionExec | null;
-
selectionRe.lastIndex = idx;
-
if ((exec = selectionRe.exec(input) as SelectionExec) != null) {
-
idx = selectionRe.lastIndex;
-
if (exec[SelectionGroup.Spread] != null) {
-
let match = advance(nameRe);
-
if (match != null && match !== 'on') {
-
// A simple `...Name` spread with optional directives
-
kind: 'FragmentSpread' as Kind.FRAGMENT_SPREAD,
-
name: { kind: 'Name' as Kind.NAME, value: match },
directives: directives(false),
-
// An inline `... on Name` spread; if this doesn't match, the type condition has been omitted
-
if ((match = advance(nameRe)) == null) throw error('NamedType');
-
const _directives = directives(false);
-
if (input.charCodeAt(idx++) !== 123 /*'{'*/) throw error('InlineFragment');
kind: 'InlineFragment' as Kind.INLINE_FRAGMENT,
-
kind: 'NamedType' as Kind.NAMED_TYPE,
-
name: { kind: 'Name' as Kind.NAME, value: match },
-
directives: _directives,
selectionSet: selectionSet(),
-
} else if ((match = exec[SelectionGroup.Name]) != null) {
-
let _alias: string | undefined;
-
// Parse the optional alias, by reassigning and then getting the name
-
if (input.charCodeAt(idx) === 58 /*':'*/) {
-
if ((match = advance(nameRe)) == null) throw error('Field');
-
const _arguments = arguments_(false);
-
const _directives = directives(false);
-
let _selectionSet: ast.SelectionSetNode | undefined;
-
if (input.charCodeAt(idx) === 123 /*'{'*/) {
-
_selectionSet = selectionSet();
-
kind: 'Field' as Kind.FIELD,
-
alias: _alias ? { kind: 'Name' as Kind.NAME, value: _alias } : undefined,
-
name: { kind: 'Name' as Kind.NAME, value: match },
-
directives: _directives,
-
selectionSet: _selectionSet,
-
throw error('SelectionSet');
} while (input.charCodeAt(idx) !== 125 /*'}'*/);
···
const vars: ast.VariableDefinitionNode[] = [];
-
let _name: string | undefined;
if (input.charCodeAt(idx++) !== 36 /*'$'*/) throw error('Variable');
-
if ((_name = advance(nameRe)) == null) throw error('Variable');
if (input.charCodeAt(idx++) !== 58 /*':'*/) throw error('VariableDefinition');
···
kind: 'VariableDefinition' as Kind.VARIABLE_DEFINITION,
kind: 'Variable' as Kind.VARIABLE,
-
name: { kind: 'Name' as Kind.NAME, value: _name },
defaultValue: _defaultValue,
···
function fragmentDefinition(): ast.FragmentDefinitionNode {
-
let _name: string | undefined;
-
let _condition: string | undefined;
-
if ((_name = advance(nameRe)) == null) throw error('FragmentDefinition');
-
if (advance(nameRe) !== 'on') throw error('FragmentDefinition');
-
if ((_condition = advance(nameRe)) == null) throw error('FragmentDefinition');
-
const _directives = directives(false);
-
if (input.charCodeAt(idx++) !== 123 /*'{'*/) throw error('FragmentDefinition');
kind: 'FragmentDefinition' as Kind.FRAGMENT_DEFINITION,
-
name: { kind: 'Name' as Kind.NAME, value: _name },
kind: 'NamedType' as Kind.NAMED_TYPE,
-
name: { kind: 'Name' as Kind.NAME, value: _condition },
-
directives: _directives,
-
selectionSet: selectionSet(),
-
const definitionRe = /(?:query|mutation|subscription|fragment)/y;
-
function operationDefinition(
-
operation: OperationTypeNode | undefined
-
): ast.OperationDefinitionNode | undefined {
-
let _name: string | undefined;
-
let _variableDefinitions: ast.VariableDefinitionNode[] | undefined;
-
let _directives: ast.DirectiveNode[] | undefined;
-
_name = advance(nameRe);
-
_variableDefinitions = variableDefinitions();
-
_directives = directives(false);
-
if (input.charCodeAt(idx) === 123 /*'{'*/) {
-
kind: 'OperationDefinition' as Kind.OPERATION_DEFINITION,
-
operation: operation || ('query' as OperationTypeNode.QUERY),
-
name: _name ? { kind: 'Name' as Kind.NAME, value: _name } : undefined,
-
variableDefinitions: _variableDefinitions,
-
directives: _directives,
-
selectionSet: selectionSet(),
function document(input: string, noLoc: boolean): ast.DocumentNode {
-
let match: string | undefined;
-
let definition: ast.OperationDefinitionNode | undefined;
const definitions: ast.ExecutableDefinitionNode[] = [];
-
if ((match = advance(definitionRe)) === 'fragment') {
-
definitions.push(fragmentDefinition());
-
} else if ((definition = operationDefinition(match as OperationTypeNode)) != null) {
-
definitions.push(definition);
-
throw error('Document');
} while (idx < input.length);
···
options?: ParseOptions | undefined
-
input = typeof string.body === 'string' ? string.body : string;
return document(input, options && options.noLocation);
···
_options?: ParseOptions | undefined
-
input = typeof string.body === 'string' ? string.body : string;
···
_options?: ParseOptions | undefined
-
input = typeof string.body === 'string' ? string.body : string;