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

Add value utilities

Changed files
+82 -1
src
+1
README.md
···
| `visit` | A recursive reimplementation of GraphQL.js’ visitor. | [Source](./src/printer.ts) |
| `Kind` | The GraphQL.js’ `Kind` enum, containing supported `ASTNode` kinds. | [Source](./src/kind.ts) |
| `GraphQLError` | `GraphQLError` stripped of source/location debugging. | [Source](./src/kind.ts) |
The stated goals of any reimplementation are:
1. Not to implement any execution or type system parts of the GraphQL
···
| `visit` | A recursive reimplementation of GraphQL.js’ visitor. | [Source](./src/printer.ts) |
| `Kind` | The GraphQL.js’ `Kind` enum, containing supported `ASTNode` kinds. | [Source](./src/kind.ts) |
| `GraphQLError` | `GraphQLError` stripped of source/location debugging. | [Source](./src/kind.ts) |
+
| `valueFromASTUntyped` | Coerces AST values into JS values. | [Source](./src/values.ts) |
The stated goals of any reimplementation are:
1. Not to implement any execution or type system parts of the GraphQL
+1 -1
package.json
···
{
"name": "@0no-co/graphql.web",
"description": "A spec-compliant client-side GraphQL implementation",
-
"version": "0.1.2",
"author": "0no.co <hi@0no.co>",
"source": "./src/index.ts",
"main": "./dist/graphql.web",
···
{
"name": "@0no-co/graphql.web",
"description": "A spec-compliant client-side GraphQL implementation",
+
"version": "0.1.3",
"author": "0no.co <hi@0no.co>",
"source": "./src/index.ts",
"main": "./dist/graphql.web",
+1
src/index.ts
···
export * from './parser';
export * from './visitor';
export * from './printer';
···
export * from './parser';
export * from './visitor';
export * from './printer';
+
export * from './values';
+79
src/values.ts
···
···
+
import { TypeNode, ValueNode } from './ast';
+
import { Kind } from './kind';
+
import { Maybe } from './types';
+
+
export function valueFromASTUntyped(
+
node: ValueNode,
+
variables?: Maybe<Record<string, any>>,
+
): unknown {
+
switch (node.kind) {
+
case Kind.NULL:
+
return null;
+
case Kind.INT:
+
return parseInt(node.value, 10);
+
case Kind.FLOAT:
+
return parseFloat(node.value);
+
case Kind.STRING:
+
case Kind.ENUM:
+
case Kind.BOOLEAN:
+
return node.value;
+
case Kind.LIST: {
+
const values: unknown[] = [];
+
for (const value of node.values)
+
values.push(valueFromASTUntyped(value, variables));
+
return values;
+
}
+
case Kind.OBJECT: {
+
const obj = Object.create(null);
+
for (const field of node.fields)
+
obj[field.name.value] = valueFromASTUntyped(field.value, variables);
+
return obj;
+
}
+
case Kind.VARIABLE:
+
return variables && variables[node.name.value];
+
}
+
}
+
+
export function valueFromTypeNode(
+
node: ValueNode,
+
type: TypeNode,
+
variables?: Maybe<Record<string, any>>,
+
): unknown {
+
if (node.kind === 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) {
+
return null;
+
} else if (type.kind === Kind.LIST_TYPE) {
+
if (node.kind === Kind.LIST) {
+
const values: unknown[] = [];
+
for (const value of node.values) {
+
const coerced = valueFromTypeNode(value, type.type, variables);
+
if (coerced === undefined) {
+
return undefined;
+
} else {
+
values.push(coerced);
+
}
+
}
+
return values;
+
}
+
} else if (type.kind === Kind.NAMED_TYPE) {
+
switch (type.name.value) {
+
case 'Int':
+
case 'Float':
+
case 'String':
+
case 'Bool':
+
return type.name.value + 'Value' === node.kind
+
? valueFromASTUntyped(node, variables)
+
: undefined;
+
default:
+
return valueFromASTUntyped(node, variables);
+
}
+
}
+
}