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

feat: Establish type compatibility with graphql (#3)

* feat: Establish type compatibility with graphql

* Merge null and boolean match

* Remove Kind usage in values.ts

* Turn GraphQLError type compatible

* Fix ASTNode typings

* Fix type compatibility of parser tools

* Add type checks for visitor

* Apply Prettier formatting

* Add run option to vitest

+5
.changeset/shy-oranges-itch.md
···
+
---
+
'benchmark': patch
+
---
+
+
Establish type compatibility with `graphql` package.
+1 -1
package.json
···
"client-side graphql"
],
"scripts": {
-
"test": "vitest",
+
"test": "vitest run",
"check": "tsc",
"lint": "eslint --ext=js,ts .",
"build": "rollup -c scripts/rollup.config.mjs",
+83 -27
src/ast.ts
···
-
import type { Kind } from './kind';
+
import type { Kind, OperationTypeNode } from './kind';
+
import type { Location } from './types';
-
export interface Location {
-
readonly start: number;
-
readonly end: number;
-
readonly source: Source;
-
}
+
import type {
+
TypeSystemDefinitionNode,
+
TypeSystemExtensionNode,
+
SchemaDefinitionNode,
+
OperationTypeDefinitionNode,
+
ScalarTypeDefinitionNode,
+
ObjectTypeDefinitionNode,
+
FieldDefinitionNode,
+
InputValueDefinitionNode,
+
InterfaceTypeDefinitionNode,
+
UnionTypeDefinitionNode,
+
EnumTypeDefinitionNode,
+
EnumValueDefinitionNode,
+
InputObjectTypeDefinitionNode,
+
DirectiveDefinitionNode,
+
SchemaExtensionNode,
+
ScalarTypeExtensionNode,
+
ObjectTypeExtensionNode,
+
InterfaceTypeExtensionNode,
+
UnionTypeExtensionNode,
+
EnumTypeExtensionNode,
+
InputObjectTypeExtensionNode,
+
} from './schemaAst';
-
export interface Source {
-
body: string;
-
name: string;
-
locationOffset: {
-
line: number;
-
column: number;
-
};
-
}
-
-
export declare type ASTNode =
+
export type ASTNode =
| NameNode
| DocumentNode
| OperationDefinitionNode
···
| DirectiveNode
| NamedTypeNode
| ListTypeNode
-
| NonNullTypeNode;
+
| NonNullTypeNode
+
| SchemaDefinitionNode
+
| OperationTypeDefinitionNode
+
| ScalarTypeDefinitionNode
+
| ObjectTypeDefinitionNode
+
| FieldDefinitionNode
+
| InputValueDefinitionNode
+
| InterfaceTypeDefinitionNode
+
| UnionTypeDefinitionNode
+
| EnumTypeDefinitionNode
+
| EnumValueDefinitionNode
+
| InputObjectTypeDefinitionNode
+
| DirectiveDefinitionNode
+
| SchemaExtensionNode
+
| ScalarTypeExtensionNode
+
| ObjectTypeExtensionNode
+
| InterfaceTypeExtensionNode
+
| UnionTypeExtensionNode
+
| EnumTypeExtensionNode
+
| InputObjectTypeExtensionNode;
export interface NameNode {
readonly kind: Kind.NAME;
readonly value: string;
+
readonly loc?: Location;
}
export interface DocumentNode {
readonly kind: Kind.DOCUMENT;
-
readonly definitions: ReadonlyArray<ExecutableDefinitionNode>;
+
readonly definitions: ReadonlyArray<DefinitionNode>;
readonly loc?: Location;
}
-
export type DefinitionNode = OperationDefinitionNode | FragmentDefinitionNode;
+
export type DefinitionNode =
+
| ExecutableDefinitionNode
+
| TypeSystemDefinitionNode
+
| TypeSystemExtensionNode;
+
export type ExecutableDefinitionNode = OperationDefinitionNode | FragmentDefinitionNode;
export interface OperationDefinitionNode {
···
readonly variableDefinitions?: ReadonlyArray<VariableDefinitionNode>;
readonly directives?: ReadonlyArray<DirectiveNode>;
readonly selectionSet: SelectionSetNode;
-
}
-
-
export const enum OperationTypeNode {
-
QUERY = 'query',
-
MUTATION = 'mutation',
-
SUBSCRIPTION = 'subscription',
+
readonly loc?: Location;
}
export interface VariableDefinitionNode {
···
readonly type: TypeNode;
readonly defaultValue?: ConstValueNode;
readonly directives?: ReadonlyArray<ConstDirectiveNode>;
+
readonly loc?: Location;
}
export interface VariableNode {
readonly kind: Kind.VARIABLE;
readonly name: NameNode;
+
readonly loc?: Location;
}
export interface SelectionSetNode {
-
kind: Kind.SELECTION_SET;
-
selections: ReadonlyArray<SelectionNode>;
+
readonly kind: Kind.SELECTION_SET;
+
readonly selections: ReadonlyArray<SelectionNode>;
+
readonly loc?: Location;
}
export declare type SelectionNode = FieldNode | FragmentSpreadNode | InlineFragmentNode;
···
readonly arguments?: ReadonlyArray<ArgumentNode>;
readonly directives?: ReadonlyArray<DirectiveNode>;
readonly selectionSet?: SelectionSetNode;
+
readonly loc?: Location;
}
export interface ArgumentNode {
readonly kind: Kind.ARGUMENT;
readonly name: NameNode;
readonly value: ValueNode;
+
readonly loc?: Location;
}
export interface ConstArgumentNode {
readonly kind: Kind.ARGUMENT;
readonly name: NameNode;
readonly value: ConstValueNode;
+
readonly loc?: Location;
}
export interface FragmentSpreadNode {
readonly kind: Kind.FRAGMENT_SPREAD;
readonly name: NameNode;
readonly directives?: ReadonlyArray<DirectiveNode>;
+
readonly loc?: Location;
}
export interface InlineFragmentNode {
···
readonly typeCondition?: NamedTypeNode;
readonly directives?: ReadonlyArray<DirectiveNode>;
readonly selectionSet: SelectionSetNode;
+
readonly loc?: Location;
}
export interface FragmentDefinitionNode {
···
readonly typeCondition: NamedTypeNode;
readonly directives?: ReadonlyArray<DirectiveNode>;
readonly selectionSet: SelectionSetNode;
+
readonly loc?: Location;
}
export type ValueNode =
···
export interface IntValueNode {
readonly kind: Kind.INT;
readonly value: string;
+
readonly loc?: Location;
}
export interface FloatValueNode {
readonly kind: Kind.FLOAT;
readonly value: string;
+
readonly loc?: Location;
}
+
export interface StringValueNode {
readonly kind: Kind.STRING;
readonly value: string;
readonly block?: boolean;
+
readonly loc?: Location;
}
export interface BooleanValueNode {
readonly kind: Kind.BOOLEAN;
readonly value: boolean;
+
readonly loc?: Location;
}
export interface NullValueNode {
readonly kind: Kind.NULL;
+
readonly loc?: Location;
}
export interface EnumValueNode {
readonly kind: Kind.ENUM;
readonly value: string;
+
readonly loc?: Location;
}
export interface ListValueNode {
readonly kind: Kind.LIST;
readonly values: ReadonlyArray<ValueNode>;
+
readonly loc?: Location;
}
export interface ConstListValueNode {
readonly kind: Kind.LIST;
readonly values: ReadonlyArray<ConstValueNode>;
+
readonly loc?: Location;
}
export interface ObjectValueNode {
readonly kind: Kind.OBJECT;
readonly fields: ReadonlyArray<ObjectFieldNode>;
+
readonly loc?: Location;
}
export interface ConstObjectValueNode {
readonly kind: Kind.OBJECT;
readonly fields: ReadonlyArray<ConstObjectFieldNode>;
+
readonly loc?: Location;
}
export interface ObjectFieldNode {
readonly kind: Kind.OBJECT_FIELD;
readonly name: NameNode;
readonly value: ValueNode;
+
readonly loc?: Location;
}
export interface ConstObjectFieldNode {
readonly kind: Kind.OBJECT_FIELD;
readonly name: NameNode;
readonly value: ConstValueNode;
+
readonly loc?: Location;
}
export interface DirectiveNode {
readonly kind: Kind.DIRECTIVE;
readonly name: NameNode;
readonly arguments?: ReadonlyArray<ArgumentNode>;
+
readonly loc?: Location;
}
export interface ConstDirectiveNode {
readonly kind: Kind.DIRECTIVE;
readonly name: NameNode;
readonly arguments?: ReadonlyArray<ConstArgumentNode>;
+
readonly loc?: Location;
}
export declare type TypeNode = NamedTypeNode | ListTypeNode | NonNullTypeNode;
···
export interface NamedTypeNode {
readonly kind: Kind.NAMED_TYPE;
readonly name: NameNode;
+
readonly loc?: Location;
}
export interface ListTypeNode {
readonly kind: Kind.LIST_TYPE;
readonly type: TypeNode;
+
readonly loc?: Location;
}
export interface NonNullTypeNode {
readonly kind: Kind.NON_NULL_TYPE;
readonly type: NamedTypeNode | ListTypeNode;
+
readonly loc?: Location;
}
+9 -5
src/error.ts
···
-
import { Maybe, Extensions } from './types';
-
import { ASTNode, Source } from './ast';
+
import { Maybe, Extensions, Source } from './types';
+
import { ASTNode } from './ast';
export class GraphQLError extends Error {
-
readonly locations: undefined;
+
readonly locations: ReadonlyArray<any> | undefined;
readonly path: ReadonlyArray<string | number> | undefined;
-
readonly nodes: ReadonlyArray<ASTNode> | undefined;
+
readonly nodes: ReadonlyArray<any> | undefined;
readonly source: Source | undefined;
readonly positions: ReadonlyArray<number> | undefined;
readonly originalError: Error | undefined;
···
this.extensions = extensions || {};
}
-
toJSON() {
+
toJSON(): any {
return { ...this };
}
toString() {
return this.message;
+
}
+
+
get [Symbol.toStringTag]() {
+
return 'GraphQLError';
}
}
+3
src/index.ts
···
+
export type { Source, Location } from './types';
+
export * from './ast';
+
export * from './schemaAst';
export * from './kind';
export * from './error';
export * from './parser';
+62
src/kind.d.ts
···
+
export declare enum Kind {
+
/** Name */
+
NAME = 'Name',
+
/** Document */
+
DOCUMENT = 'Document',
+
OPERATION_DEFINITION = 'OperationDefinition',
+
VARIABLE_DEFINITION = 'VariableDefinition',
+
SELECTION_SET = 'SelectionSet',
+
FIELD = 'Field',
+
ARGUMENT = 'Argument',
+
/** Fragments */
+
FRAGMENT_SPREAD = 'FragmentSpread',
+
INLINE_FRAGMENT = 'InlineFragment',
+
FRAGMENT_DEFINITION = 'FragmentDefinition',
+
/** Values */
+
VARIABLE = 'Variable',
+
INT = 'IntValue',
+
FLOAT = 'FloatValue',
+
STRING = 'StringValue',
+
BOOLEAN = 'BooleanValue',
+
NULL = 'NullValue',
+
ENUM = 'EnumValue',
+
LIST = 'ListValue',
+
OBJECT = 'ObjectValue',
+
OBJECT_FIELD = 'ObjectField',
+
/** Directives */
+
DIRECTIVE = 'Directive',
+
/** Types */
+
NAMED_TYPE = 'NamedType',
+
LIST_TYPE = 'ListType',
+
NON_NULL_TYPE = 'NonNullType',
+
/** Type System Definitions */
+
SCHEMA_DEFINITION = 'SchemaDefinition',
+
OPERATION_TYPE_DEFINITION = 'OperationTypeDefinition',
+
/** Type Definitions */
+
SCALAR_TYPE_DEFINITION = 'ScalarTypeDefinition',
+
OBJECT_TYPE_DEFINITION = 'ObjectTypeDefinition',
+
FIELD_DEFINITION = 'FieldDefinition',
+
INPUT_VALUE_DEFINITION = 'InputValueDefinition',
+
INTERFACE_TYPE_DEFINITION = 'InterfaceTypeDefinition',
+
UNION_TYPE_DEFINITION = 'UnionTypeDefinition',
+
ENUM_TYPE_DEFINITION = 'EnumTypeDefinition',
+
ENUM_VALUE_DEFINITION = 'EnumValueDefinition',
+
INPUT_OBJECT_TYPE_DEFINITION = 'InputObjectTypeDefinition',
+
/** Directive Definitions */
+
DIRECTIVE_DEFINITION = 'DirectiveDefinition',
+
/** Type System Extensions */
+
SCHEMA_EXTENSION = 'SchemaExtension',
+
/** Type Extensions */
+
SCALAR_TYPE_EXTENSION = 'ScalarTypeExtension',
+
OBJECT_TYPE_EXTENSION = 'ObjectTypeExtension',
+
INTERFACE_TYPE_EXTENSION = 'InterfaceTypeExtension',
+
UNION_TYPE_EXTENSION = 'UnionTypeExtension',
+
ENUM_TYPE_EXTENSION = 'EnumTypeExtension',
+
INPUT_OBJECT_TYPE_EXTENSION = 'InputObjectTypeExtension',
+
}
+
+
export declare enum OperationTypeNode {
+
QUERY = 'query',
+
MUTATION = 'mutation',
+
SUBSCRIPTION = 'subscription',
+
}
+47
src/kind.js
···
+
export const Kind = {
+
NAME: 'Name',
+
DOCUMENT: 'Document',
+
OPERATION_DEFINITION: 'OperationDefinition',
+
VARIABLE_DEFINITION: 'VariableDefinition',
+
SELECTION_SET: 'SelectionSet',
+
FIELD: 'Field',
+
ARGUMENT: 'Argument',
+
FRAGMENT_SPREAD: 'FragmentSpread',
+
INLINE_FRAGMENT: 'InlineFragment',
+
FRAGMENT_DEFINITION: 'FragmentDefinition',
+
VARIABLE: 'Variable',
+
OBJECT: 'ObjectValue',
+
OBJECT_FIELD: 'ObjectField',
+
DIRECTIVE: 'Directive',
+
NAMED_TYPE: 'NamedType',
+
LIST_TYPE: 'ListType',
+
NON_NULL_TYPE: 'NonNullType',
+
+
/*
+
SCHEMA_DEFINITION: 'SchemaDefinition',
+
OPERATION_TYPE_DEFINITION: 'OperationTypeDefinition',
+
SCALAR_TYPE_DEFINITION: 'ScalarTypeDefinition',
+
OBJECT_TYPE_DEFINITION: 'ObjectTypeDefinition',
+
FIELD_DEFINITION: 'FieldDefinition',
+
INPUT_VALUE_DEFINITION: 'InputValueDefinition',
+
INTERFACE_TYPE_DEFINITION: 'InterfaceTypeDefinition',
+
UNION_TYPE_DEFINITION: 'UnionTypeDefinition',
+
ENUM_TYPE_DEFINITION: 'EnumTypeDefinition',
+
ENUM_VALUE_DEFINITION: 'EnumValueDefinition',
+
INPUT_OBJECT_TYPE_DEFINITION: 'InputObjectTypeDefinition',
+
DIRECTIVE_DEFINITION: 'DirectiveDefinition',
+
SCHEMA_EXTENSION: 'SchemaExtension',
+
SCALAR_TYPE_EXTENSION: 'ScalarTypeExtension',
+
OBJECT_TYPE_EXTENSION: 'ObjectTypeExtension',
+
INTERFACE_TYPE_EXTENSION: 'InterfaceTypeExtension',
+
UNION_TYPE_EXTENSION: 'UnionTypeExtension',
+
ENUM_TYPE_EXTENSION: 'EnumTypeExtension',
+
INPUT_OBJECT_TYPE_EXTENSION: 'InputObjectTypeExtension',
+
*/
+
};
+
+
export const OperationTypeNode = {
+
QUERY: 'query',
+
MUTATION: 'mutation',
+
SUBSCRIPTION: 'subscription',
+
};
-32
src/kind.ts
···
-
export enum Kind {
-
/** Name */
-
NAME = 'Name',
-
/** Document */
-
DOCUMENT = 'Document',
-
OPERATION_DEFINITION = 'OperationDefinition',
-
VARIABLE_DEFINITION = 'VariableDefinition',
-
SELECTION_SET = 'SelectionSet',
-
FIELD = 'Field',
-
ARGUMENT = 'Argument',
-
/** Fragments */
-
FRAGMENT_SPREAD = 'FragmentSpread',
-
INLINE_FRAGMENT = 'InlineFragment',
-
FRAGMENT_DEFINITION = 'FragmentDefinition',
-
/** Values */
-
VARIABLE = 'Variable',
-
INT = 'IntValue',
-
FLOAT = 'FloatValue',
-
STRING = 'StringValue',
-
BOOLEAN = 'BooleanValue',
-
NULL = 'NullValue',
-
ENUM = 'EnumValue',
-
LIST = 'ListValue',
-
OBJECT = 'ObjectValue',
-
OBJECT_FIELD = 'ObjectField',
-
/** Directives */
-
DIRECTIVE = 'Directive',
-
/** Types */
-
NAMED_TYPE = 'NamedType',
-
LIST_TYPE = 'ListType',
-
NON_NULL_TYPE = 'NonNullType',
-
}
+91 -72
src/parser.ts
···
* in graphql.js it will only parse the query language, but not the schema
* language.
*/
-
import { Kind } from './kind';
+
import { Kind, OperationTypeNode } from './kind';
import { GraphQLError } from './error';
+
import { Source } from './types';
import type * as ast from './ast';
let input: string;
let idx: number;
-
function error(kind: Kind) {
+
function error(kind: string) {
return new GraphQLError(`Syntax Error: Unexpected token at ${idx} in ${kind}`);
}
···
let match: string | undefined;
if ((match = advance(nameRe))) {
return {
-
kind: Kind.NAME,
+
kind: 'Name' as Kind.NAME,
value: match,
};
}
}
-
const nullRe = /null/y;
-
const boolRe = /true|false/y;
+
const constRe = /null|true|false/y;
const variableRe = /\$[_\w][_\d\w]*/y;
const intRe = /[-]?\d+/y;
const floatRe = /(?:[-]?\d+)?(?:\.\d+)(?:[eE][+-]?\d+)?/y;
···
function value(constant: boolean): ast.ValueNode | undefined {
let out: ast.ValueNode | undefined;
let match: string | undefined;
-
if (advance(nullRe)) {
-
out = { kind: Kind.NULL };
-
} else if ((match = advance(boolRe))) {
-
out = {
-
kind: Kind.BOOLEAN,
-
value: match === 'true',
-
};
+
if ((match = advance(constRe))) {
+
out =
+
match === 'null'
+
? {
+
kind: 'NullValue' as Kind.NULL,
+
}
+
: {
+
kind: 'BooleanValue' as Kind.BOOLEAN,
+
value: match === 'true',
+
};
} else if (!constant && (match = advance(variableRe))) {
out = {
-
kind: Kind.VARIABLE,
+
kind: 'Variable' as Kind.VARIABLE,
name: {
-
kind: Kind.NAME,
+
kind: 'Name' as Kind.NAME,
value: match.slice(1),
},
};
} else if ((match = advance(floatRe))) {
out = {
-
kind: Kind.FLOAT,
+
kind: 'FloatValue' as Kind.FLOAT,
value: match,
};
} else if ((match = advance(intRe))) {
out = {
-
kind: Kind.INT,
+
kind: 'IntValue' as Kind.INT,
value: match,
};
} else if ((match = advance(nameRe))) {
out = {
-
kind: Kind.ENUM,
+
kind: 'EnumValue' as Kind.ENUM,
value: match,
};
} else if ((match = advance(blockStringRe))) {
out = {
-
kind: Kind.STRING,
+
kind: 'StringValue' as Kind.STRING,
value: blockString(match.slice(3, -3)),
block: true,
};
} else if ((match = advance(stringRe))) {
out = {
-
kind: Kind.STRING,
+
kind: 'StringValue' as Kind.STRING,
value: complexStringRe.test(match) ? (JSON.parse(match) as string) : match.slice(1, -1),
block: false,
};
···
ignored();
const values: ast.ValueNode[] = [];
while ((match = value(constant))) values.push(match);
-
if (input.charCodeAt(idx++) !== 93 /*']'*/) throw error(Kind.LIST);
+
if (input.charCodeAt(idx++) !== 93 /*']'*/) throw error('ListValue');
ignored();
return {
-
kind: Kind.LIST,
+
kind: 'ListValue' as Kind.LIST,
values,
};
}
···
let _name: ast.NameNode | undefined;
while ((_name = name())) {
ignored();
-
if (input.charCodeAt(idx++) !== 58 /*':'*/) throw error(Kind.OBJECT_FIELD);
+
if (input.charCodeAt(idx++) !== 58 /*':'*/) throw error('ObjectField' as Kind.OBJECT_FIELD);
ignored();
const _value = value(constant);
-
if (!_value) throw error(Kind.OBJECT_FIELD);
+
if (!_value) throw error('ObjectField');
fields.push({
-
kind: Kind.OBJECT_FIELD,
+
kind: 'ObjectField' as Kind.OBJECT_FIELD,
name: _name,
value: _value,
});
}
-
if (input.charCodeAt(idx++) !== 125 /*'}'*/) throw error(Kind.OBJECT);
+
if (input.charCodeAt(idx++) !== 125 /*'}'*/) throw error('ObjectValue');
ignored();
return {
-
kind: Kind.OBJECT,
+
kind: 'ObjectValue' as Kind.OBJECT,
fields,
};
}
···
let _name: ast.NameNode | undefined;
while ((_name = name())) {
ignored();
-
if (input.charCodeAt(idx++) !== 58 /*':'*/) throw error(Kind.ARGUMENT);
+
if (input.charCodeAt(idx++) !== 58 /*':'*/) throw error('Argument');
ignored();
const _value = value(constant);
-
if (!_value) throw error(Kind.ARGUMENT);
+
if (!_value) throw error('Argument');
args.push({
-
kind: Kind.ARGUMENT,
+
kind: 'Argument' as Kind.ARGUMENT,
name: _name,
value: _value,
});
}
-
if (!args.length || input.charCodeAt(idx++) !== 41 /*')'*/) throw error(Kind.ARGUMENT);
+
if (!args.length || input.charCodeAt(idx++) !== 41 /*')'*/) throw error('Argument');
ignored();
}
return args;
···
while (input.charCodeAt(idx) === 64 /*'@'*/) {
idx++;
const _name = name();
-
if (!_name) throw error(Kind.DIRECTIVE);
+
if (!_name) throw error('Directive');
ignored();
directives.push({
-
kind: Kind.DIRECTIVE,
+
kind: 'Directive' as Kind.DIRECTIVE,
name: _name,
arguments: arguments_(constant),
});
···
ignored();
_alias = _name;
_name = name();
-
if (!_name) throw error(Kind.FIELD);
+
if (!_name) throw error('Field');
ignored();
}
return {
-
kind: Kind.FIELD,
+
kind: 'Field' as Kind.FIELD,
alias: _alias,
name: _name,
arguments: arguments_(false),
···
idx++;
ignored();
const _type = type();
-
if (!_type || input.charCodeAt(idx++) !== 93 /*']'*/) throw error(Kind.LIST_TYPE);
+
if (!_type || input.charCodeAt(idx++) !== 93 /*']'*/) throw error('ListType');
match = {
-
kind: Kind.LIST_TYPE,
+
kind: 'ListType' as Kind.LIST_TYPE,
type: _type,
};
} else if ((match = name())) {
match = {
-
kind: Kind.NAMED_TYPE,
+
kind: 'NamedType' as Kind.NAMED_TYPE,
name: match,
};
} else {
-
throw error(Kind.NAMED_TYPE);
+
throw error('NamedType');
}
ignored();
···
idx++;
ignored();
return {
-
kind: Kind.NON_NULL_TYPE,
+
kind: 'NonNullType' as Kind.NON_NULL_TYPE,
type: match,
};
} else {
···
if (advance(typeConditionRe)) {
ignored();
const _name = name();
-
if (!_name) throw error(Kind.NAMED_TYPE);
+
if (!_name) throw error('NamedType');
ignored();
return {
-
kind: Kind.NAMED_TYPE,
+
kind: 'NamedType' as Kind.NAMED_TYPE,
name: _name,
};
}
···
let _name: ast.NameNode | undefined;
if ((_name = name()) && _name.value !== 'on') {
return {
-
kind: Kind.FRAGMENT_SPREAD,
+
kind: 'FragmentSpread' as Kind.FRAGMENT_SPREAD,
name: _name,
directives: directives(false),
};
···
const _typeCondition = typeCondition();
const _directives = directives(false);
const _selectionSet = selectionSet();
-
if (!_selectionSet) throw error(Kind.INLINE_FRAGMENT);
+
if (!_selectionSet) throw error('InlineFragment');
return {
-
kind: Kind.INLINE_FRAGMENT,
+
kind: 'InlineFragment' as Kind.INLINE_FRAGMENT,
typeCondition: _typeCondition,
directives: _directives,
selectionSet: _selectionSet,
···
ignored();
const selections: ast.SelectionNode[] = [];
while ((match = fragmentSpread() || field())) selections.push(match);
-
if (!selections.length || input.charCodeAt(idx++) !== 125 /*'}'*/)
-
throw error(Kind.SELECTION_SET);
+
if (!selections.length || input.charCodeAt(idx++) !== 125 /*'}'*/) throw error('SelectionSet');
ignored();
return {
-
kind: Kind.SELECTION_SET,
+
kind: 'SelectionSet' as Kind.SELECTION_SET,
selections,
};
}
···
ignored();
while ((match = advance(variableRe))) {
ignored();
-
if (input.charCodeAt(idx++) !== 58 /*':'*/) throw error(Kind.VARIABLE_DEFINITION);
+
if (input.charCodeAt(idx++) !== 58 /*':'*/) throw error('VariableDefinition');
const _type = type();
-
if (!_type) throw error(Kind.VARIABLE_DEFINITION);
+
if (!_type) throw error('VariableDefinition');
let _defaultValue: ast.ValueNode | undefined;
if (input.charCodeAt(idx) === 61 /*'='*/) {
idx++;
ignored();
_defaultValue = value(true);
-
if (!_defaultValue) throw error(Kind.VARIABLE_DEFINITION);
+
if (!_defaultValue) throw error('VariableDefinition');
}
ignored();
vars.push({
-
kind: Kind.VARIABLE_DEFINITION,
+
kind: 'VariableDefinition' as Kind.VARIABLE_DEFINITION,
variable: {
-
kind: Kind.VARIABLE,
+
kind: 'Variable' as Kind.VARIABLE,
name: {
-
kind: Kind.NAME,
+
kind: 'Name' as Kind.NAME,
value: match.slice(1),
},
},
···
directives: directives(true),
});
}
-
if (input.charCodeAt(idx++) !== 41 /*')'*/) throw error(Kind.VARIABLE_DEFINITION);
+
if (input.charCodeAt(idx++) !== 41 /*')'*/) throw error('VariableDefinition');
ignored();
}
return vars;
···
if (advance(fragmentDefinitionRe)) {
ignored();
const _name = name();
-
if (!_name) throw error(Kind.FRAGMENT_DEFINITION);
+
if (!_name) throw error('FragmentDefinition');
ignored();
const _typeCondition = typeCondition();
-
if (!_typeCondition) throw error(Kind.FRAGMENT_DEFINITION);
+
if (!_typeCondition) throw error('FragmentDefinition');
const _directives = directives(false);
const _selectionSet = selectionSet();
-
if (!_selectionSet) throw error(Kind.FRAGMENT_DEFINITION);
+
if (!_selectionSet) throw error('FragmentDefinition');
return {
-
kind: Kind.FRAGMENT_DEFINITION,
+
kind: 'FragmentDefinition' as Kind.FRAGMENT_DEFINITION,
name: _name,
typeCondition: _typeCondition,
directives: _directives,
···
const _selectionSet = selectionSet();
if (_selectionSet) {
return {
-
kind: Kind.OPERATION_DEFINITION,
-
operation: (_operation || 'query') as ast.OperationTypeNode,
+
kind: 'OperationDefinition' as Kind.OPERATION_DEFINITION,
+
operation: (_operation || 'query') as OperationTypeNode,
name: _name,
variableDefinitions: _variableDefinitions,
directives: _directives,
···
}
function document(): ast.DocumentNode {
-
let match: ast.DefinitionNode | void;
+
let match: ast.ExecutableDefinitionNode | void;
ignored();
-
const definitions: ast.DefinitionNode[] = [];
+
const definitions: ast.ExecutableDefinitionNode[] = [];
while ((match = fragmentDefinition() || operationDefinition())) definitions.push(match);
-
if (idx !== input.length) throw error(Kind.DOCUMENT);
+
if (idx !== input.length) throw error('Document');
return {
-
kind: Kind.DOCUMENT,
+
kind: 'Document' as Kind.DOCUMENT,
definitions,
};
}
-
export function parse(string: string): ast.DocumentNode {
-
input = string;
+
type ParseOptions = {
+
[option: string]: any;
+
};
+
+
export function parse(
+
string: string | Source,
+
_options?: ParseOptions | undefined
+
): ast.DocumentNode {
+
input = typeof string.body === 'string' ? string.body : string;
idx = 0;
return document();
}
-
export function parseValue(string: string): ast.ValueNode | undefined {
-
input = string;
+
export function parseValue(
+
string: string | Source,
+
_options?: ParseOptions | undefined
+
): ast.ValueNode {
+
input = typeof string.body === 'string' ? string.body : string;
idx = 0;
ignored();
-
return value(false);
+
const _value = value(false);
+
if (!_value) throw error('ValueNode');
+
return _value;
}
-
export function parseType(string: string): ast.TypeNode | undefined {
-
input = string;
+
export function parseType(
+
string: string | Source,
+
_options?: ParseOptions | undefined
+
): ast.TypeNode {
+
input = typeof string.body === 'string' ? string.body : string;
idx = 0;
-
return type();
+
const _type = type();
+
if (!_type) throw error('TypeNode');
+
return _type;
}
+27 -25
src/printer.ts
···
-
import { Kind } from './kind';
import { ASTNode } from './ast';
export function printString(string: string) {
···
export function print(node: ASTNode): string {
let out: string;
switch (node.kind) {
-
case Kind.OPERATION_DEFINITION:
+
case 'OperationDefinition':
if (
node.operation === 'query' &&
!node.name &&
···
if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' ');
return out + ' ' + print(node.selectionSet);
-
case Kind.VARIABLE_DEFINITION:
+
case 'VariableDefinition':
out = print(node.variable) + ': ' + print(node.type);
if (node.defaultValue) out += ' = ' + print(node.defaultValue);
if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' ');
return out;
-
case Kind.FIELD:
+
case 'Field':
out = (node.alias ? print(node.alias) + ': ' : '') + node.name.value;
if (hasItems(node.arguments)) {
const args = node.arguments.map(print);
···
if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' ');
return node.selectionSet ? out + ' ' + print(node.selectionSet) : out;
-
case Kind.STRING:
+
case 'StringValue':
return node.block ? printBlockString(node.value) : printString(node.value);
-
case Kind.BOOLEAN:
+
case 'BooleanValue':
return '' + node.value;
-
case Kind.NULL:
+
case 'NullValue':
return 'null';
-
case Kind.INT:
-
case Kind.FLOAT:
-
case Kind.ENUM:
-
case Kind.NAME:
+
case 'IntValue':
+
case 'FloatValue':
+
case 'EnumValue':
+
case 'Name':
return node.value;
-
case Kind.LIST:
+
case 'ListValue':
return '[' + node.values.map(print).join(', ') + ']';
-
case Kind.OBJECT:
+
case 'ObjectValue':
return '{' + node.fields.map(print).join(', ') + '}';
-
case Kind.OBJECT_FIELD:
+
case 'ObjectField':
return node.name.value + ': ' + print(node.value);
-
case Kind.VARIABLE:
+
case 'Variable':
return '$' + node.name.value;
-
case Kind.DOCUMENT:
+
case 'Document':
return hasItems(node.definitions) ? node.definitions.map(print).join('\n\n') : '';
-
case Kind.SELECTION_SET:
+
case 'SelectionSet':
return '{\n ' + node.selections.map(print).join('\n').replace(/\n/g, '\n ') + '\n}';
-
case Kind.ARGUMENT:
+
case 'Argument':
return node.name.value + ': ' + print(node.value);
-
case Kind.FRAGMENT_SPREAD:
+
case 'FragmentSpread':
out = '...' + node.name.value;
if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' ');
return out;
-
case Kind.INLINE_FRAGMENT:
+
case 'InlineFragment':
out = '...';
if (node.typeCondition) out += ' on ' + node.typeCondition.name.value;
if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' ');
return out + ' ' + print(node.selectionSet);
-
case Kind.FRAGMENT_DEFINITION:
+
case 'FragmentDefinition':
out = 'fragment ' + node.name.value;
out += ' on ' + node.typeCondition.name.value;
if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' ');
return out + ' ' + print(node.selectionSet);
-
case Kind.DIRECTIVE:
+
case 'Directive':
out = '@' + node.name.value;
if (hasItems(node.arguments)) out += '(' + node.arguments.map(print).join(', ') + ')';
return out;
-
case Kind.NAMED_TYPE:
+
case 'NamedType':
return node.name.value;
-
case Kind.LIST_TYPE:
+
case 'ListType':
return '[' + print(node.type) + ']';
-
case Kind.NON_NULL_TYPE:
+
case 'NonNullType':
return print(node.type) + '!';
+
+
default:
+
return '';
}
}
+198
src/schemaAst.ts
···
+
import type { Location } from './types';
+
import type { Kind, OperationTypeNode } from './kind';
+
+
import type {
+
StringValueNode,
+
ConstDirectiveNode,
+
ConstValueNode,
+
NamedTypeNode,
+
TypeNode,
+
NameNode,
+
} from './ast';
+
+
/** Type System Definition */
+
export declare type TypeSystemDefinitionNode =
+
| SchemaDefinitionNode
+
| TypeDefinitionNode
+
| DirectiveDefinitionNode;
+
+
export interface SchemaDefinitionNode {
+
readonly kind: Kind.SCHEMA_DEFINITION;
+
readonly loc?: Location;
+
readonly description?: StringValueNode;
+
readonly directives?: ReadonlyArray<ConstDirectiveNode>;
+
readonly operationTypes: ReadonlyArray<OperationTypeDefinitionNode>;
+
}
+
+
export interface OperationTypeDefinitionNode {
+
readonly kind: Kind.OPERATION_TYPE_DEFINITION;
+
readonly loc?: Location;
+
readonly operation: OperationTypeNode;
+
readonly type: NamedTypeNode;
+
}
+
+
/** Type Definition */
+
export declare type TypeDefinitionNode =
+
| ScalarTypeDefinitionNode
+
| ObjectTypeDefinitionNode
+
| InterfaceTypeDefinitionNode
+
| UnionTypeDefinitionNode
+
| EnumTypeDefinitionNode
+
| InputObjectTypeDefinitionNode;
+
+
export interface ScalarTypeDefinitionNode {
+
readonly kind: Kind.SCALAR_TYPE_DEFINITION;
+
readonly loc?: Location;
+
readonly description?: StringValueNode;
+
readonly name: NameNode;
+
readonly directives?: ReadonlyArray<ConstDirectiveNode>;
+
}
+
+
export interface ObjectTypeDefinitionNode {
+
readonly kind: Kind.OBJECT_TYPE_DEFINITION;
+
readonly loc?: Location;
+
readonly description?: StringValueNode;
+
readonly name: NameNode;
+
readonly interfaces?: ReadonlyArray<NamedTypeNode>;
+
readonly directives?: ReadonlyArray<ConstDirectiveNode>;
+
readonly fields?: ReadonlyArray<FieldDefinitionNode>;
+
}
+
+
export interface FieldDefinitionNode {
+
readonly kind: Kind.FIELD_DEFINITION;
+
readonly loc?: Location;
+
readonly description?: StringValueNode;
+
readonly name: NameNode;
+
readonly arguments?: ReadonlyArray<InputValueDefinitionNode>;
+
readonly type: TypeNode;
+
readonly directives?: ReadonlyArray<ConstDirectiveNode>;
+
}
+
+
export interface InputValueDefinitionNode {
+
readonly kind: Kind.INPUT_VALUE_DEFINITION;
+
readonly loc?: Location;
+
readonly description?: StringValueNode;
+
readonly name: NameNode;
+
readonly type: TypeNode;
+
readonly defaultValue?: ConstValueNode;
+
readonly directives?: ReadonlyArray<ConstDirectiveNode>;
+
}
+
+
export interface InterfaceTypeDefinitionNode {
+
readonly kind: Kind.INTERFACE_TYPE_DEFINITION;
+
readonly loc?: Location;
+
readonly description?: StringValueNode;
+
readonly name: NameNode;
+
readonly interfaces?: ReadonlyArray<NamedTypeNode>;
+
readonly directives?: ReadonlyArray<ConstDirectiveNode>;
+
readonly fields?: ReadonlyArray<FieldDefinitionNode>;
+
}
+
+
export interface UnionTypeDefinitionNode {
+
readonly kind: Kind.UNION_TYPE_DEFINITION;
+
readonly loc?: Location;
+
readonly description?: StringValueNode;
+
readonly name: NameNode;
+
readonly directives?: ReadonlyArray<ConstDirectiveNode>;
+
readonly types?: ReadonlyArray<NamedTypeNode>;
+
}
+
+
export interface EnumTypeDefinitionNode {
+
readonly kind: Kind.ENUM_TYPE_DEFINITION;
+
readonly loc?: Location;
+
readonly description?: StringValueNode;
+
readonly name: NameNode;
+
readonly directives?: ReadonlyArray<ConstDirectiveNode>;
+
readonly values?: ReadonlyArray<EnumValueDefinitionNode>;
+
}
+
+
export interface EnumValueDefinitionNode {
+
readonly kind: Kind.ENUM_VALUE_DEFINITION;
+
readonly loc?: Location;
+
readonly description?: StringValueNode;
+
readonly name: NameNode;
+
readonly directives?: ReadonlyArray<ConstDirectiveNode>;
+
}
+
+
export interface InputObjectTypeDefinitionNode {
+
readonly kind: Kind.INPUT_OBJECT_TYPE_DEFINITION;
+
readonly loc?: Location;
+
readonly description?: StringValueNode;
+
readonly name: NameNode;
+
readonly directives?: ReadonlyArray<ConstDirectiveNode>;
+
readonly fields?: ReadonlyArray<InputValueDefinitionNode>;
+
}
+
/** Directive Definitions */
+
export interface DirectiveDefinitionNode {
+
readonly kind: Kind.DIRECTIVE_DEFINITION;
+
readonly loc?: Location;
+
readonly description?: StringValueNode;
+
readonly name: NameNode;
+
readonly arguments?: ReadonlyArray<InputValueDefinitionNode>;
+
readonly repeatable: boolean;
+
readonly locations: ReadonlyArray<NameNode>;
+
}
+
/** Type System Extensions */
+
export declare type TypeSystemExtensionNode = SchemaExtensionNode | TypeExtensionNode;
+
export interface SchemaExtensionNode {
+
readonly kind: Kind.SCHEMA_EXTENSION;
+
readonly loc?: Location;
+
readonly directives?: ReadonlyArray<ConstDirectiveNode>;
+
readonly operationTypes?: ReadonlyArray<OperationTypeDefinitionNode>;
+
}
+
/** Type Extensions */
+
export declare type TypeExtensionNode =
+
| ScalarTypeExtensionNode
+
| ObjectTypeExtensionNode
+
| InterfaceTypeExtensionNode
+
| UnionTypeExtensionNode
+
| EnumTypeExtensionNode
+
| InputObjectTypeExtensionNode;
+
export interface ScalarTypeExtensionNode {
+
readonly kind: Kind.SCALAR_TYPE_EXTENSION;
+
readonly loc?: Location;
+
readonly name: NameNode;
+
readonly directives?: ReadonlyArray<ConstDirectiveNode>;
+
}
+
+
export interface ObjectTypeExtensionNode {
+
readonly kind: Kind.OBJECT_TYPE_EXTENSION;
+
readonly loc?: Location;
+
readonly name: NameNode;
+
readonly interfaces?: ReadonlyArray<NamedTypeNode>;
+
readonly directives?: ReadonlyArray<ConstDirectiveNode>;
+
readonly fields?: ReadonlyArray<FieldDefinitionNode>;
+
}
+
+
export interface InterfaceTypeExtensionNode {
+
readonly kind: Kind.INTERFACE_TYPE_EXTENSION;
+
readonly loc?: Location;
+
readonly name: NameNode;
+
readonly interfaces?: ReadonlyArray<NamedTypeNode>;
+
readonly directives?: ReadonlyArray<ConstDirectiveNode>;
+
readonly fields?: ReadonlyArray<FieldDefinitionNode>;
+
}
+
+
export interface UnionTypeExtensionNode {
+
readonly kind: Kind.UNION_TYPE_EXTENSION;
+
readonly loc?: Location;
+
readonly name: NameNode;
+
readonly directives?: ReadonlyArray<ConstDirectiveNode>;
+
readonly types?: ReadonlyArray<NamedTypeNode>;
+
}
+
+
export interface EnumTypeExtensionNode {
+
readonly kind: Kind.ENUM_TYPE_EXTENSION;
+
readonly loc?: Location;
+
readonly name: NameNode;
+
readonly directives?: ReadonlyArray<ConstDirectiveNode>;
+
readonly values?: ReadonlyArray<EnumValueDefinitionNode>;
+
}
+
+
export interface InputObjectTypeExtensionNode {
+
readonly kind: Kind.INPUT_OBJECT_TYPE_EXTENSION;
+
readonly loc?: Location;
+
readonly name: NameNode;
+
readonly directives?: ReadonlyArray<ConstDirectiveNode>;
+
readonly fields?: ReadonlyArray<InputValueDefinitionNode>;
+
}
+19
src/types.ts
···
export interface Extensions {
[extension: string]: unknown;
}
+
+
export type Source =
+
| any
+
| {
+
body: string;
+
name: string;
+
locationOffset: {
+
line: number;
+
column: number;
+
};
+
};
+
+
export type Location =
+
| any
+
| {
+
start: number;
+
end: number;
+
source: Source;
+
};
+16 -17
src/values.ts
···
import { TypeNode, ValueNode } from './ast';
-
import { Kind } from './kind';
import { Maybe } from './types';
export function valueFromASTUntyped(
···
variables?: Maybe<Record<string, any>>
): unknown {
switch (node.kind) {
-
case Kind.NULL:
+
case 'NullValue':
return null;
-
case Kind.INT:
+
case 'IntValue':
return parseInt(node.value, 10);
-
case Kind.FLOAT:
+
case 'FloatValue':
return parseFloat(node.value);
-
case Kind.STRING:
-
case Kind.ENUM:
-
case Kind.BOOLEAN:
+
case 'StringValue':
+
case 'EnumValue':
+
case 'BooleanValue':
return node.value;
-
case Kind.LIST: {
+
case 'ListValue': {
const values: unknown[] = [];
for (const value of node.values) values.push(valueFromASTUntyped(value, variables));
return values;
}
-
case Kind.OBJECT: {
+
case 'ObjectValue': {
const obj = Object.create(null);
for (const field of node.fields)
obj[field.name.value] = valueFromASTUntyped(field.value, variables);
return obj;
}
-
case Kind.VARIABLE:
+
case 'Variable':
return variables && variables[node.name.value];
}
}
···
type: TypeNode,
variables?: Maybe<Record<string, any>>
): unknown {
-
if (node.kind === Kind.VARIABLE) {
+
if (node.kind === 'Variable') {
const variableName = node.name.value;
return variables ? valueFromTypeNode(variables[variableName], type, variables) : undefined;
-
} else if (type.kind === Kind.NON_NULL_TYPE) {
-
return node.kind !== Kind.NULL ? valueFromTypeNode(node, type, variables) : undefined;
-
} else if (node.kind === Kind.NULL) {
+
} else if (type.kind === 'NonNullType') {
+
return node.kind !== 'NullValue' ? valueFromTypeNode(node, type, variables) : undefined;
+
} else if (node.kind === 'NullValue') {
return null;
-
} else if (type.kind === Kind.LIST_TYPE) {
-
if (node.kind === Kind.LIST) {
+
} else if (type.kind === 'ListType') {
+
if (node.kind === 'ListValue') {
const values: unknown[] = [];
for (const value of node.values) {
const coerced = valueFromTypeNode(value, type.type, variables);
···
}
return values;
}
-
} else if (type.kind === Kind.NAMED_TYPE) {
+
} else if (type.kind === 'NamedType') {
switch (type.name.value) {
case 'Int':
case 'Float':
+3 -3
tsconfig.json
···
"noEmit": true,
"esModuleInterop": true,
"noUnusedLocals": true,
-
"rootDir": "./src",
+
"rootDir": ".",
"baseUrl": ".",
-
"outDir": "dist/cjs",
+
"allowJs": true,
"lib": ["dom", "esnext"],
"jsx": "react",
"declaration": false,
···
"skipLibCheck": true,
"isolatedModules": true
},
-
"include": ["src"]
+
"include": ["src", "typings"]
}
+18
typings/document.ts
···
+
import type * as graphql from 'graphql';
+
import type * as graphqlWeb from '../src/index';
+
+
export function documentInput(input: graphqlWeb.DocumentNode): graphql.DocumentNode {
+
return input;
+
}
+
+
export function documentOutput(input: graphql.DocumentNode): graphqlWeb.DocumentNode {
+
return input;
+
}
+
+
export function nodeInput(input: graphqlWeb.ASTNode): graphql.ASTNode {
+
return input;
+
}
+
+
export function nodeOutput(input: graphql.ASTNode): graphqlWeb.ASTNode {
+
return input;
+
}
+10
typings/error.ts
···
+
import type * as graphql from 'graphql';
+
import type * as graphqlWeb from '../src/index';
+
+
export function errorInput(input: graphqlWeb.GraphQLError): graphql.GraphQLError {
+
return input;
+
}
+
+
export function errorOutput(input: graphql.GraphQLError): graphqlWeb.GraphQLError {
+
return input;
+
}
+18
typings/parser.ts
···
+
import type * as graphql from 'graphql';
+
import type * as graphqlWeb from '../src/index';
+
+
export function parseInput(input: typeof graphqlWeb.parse): typeof graphql.parse {
+
return input;
+
}
+
+
export function parseOutput(input: typeof graphql.parse): typeof graphqlWeb.parse {
+
return input;
+
}
+
+
export function parseValueInput(input: typeof graphqlWeb.parseValue): typeof graphql.parseValue {
+
return input;
+
}
+
+
export function parseValueOutput(input: typeof graphql.parseValue): typeof graphqlWeb.parseValue {
+
return input;
+
}
+10
typings/visitor.ts
···
+
import type * as graphql from 'graphql';
+
import type * as graphqlWeb from '../src/index';
+
+
export function visitInput(input: typeof graphqlWeb.visit): typeof graphql.visit {
+
return input;
+
}
+
+
export function visitOutput(input: typeof graphql.visit): typeof graphqlWeb.visit {
+
return input;
+
}