graphql-jit
Advanced tools
Comparing version 0.3.3 to 0.4.0
@@ -1,8 +0,12 @@ | ||
import { DocumentNode, ExecutionResult, GraphQLError, GraphQLObjectType, GraphQLOutputType, GraphQLScalarSerializer, GraphQLSchema } from "graphql"; | ||
import { ExecutionContext } from "graphql/execution/execute"; | ||
import { CoercedVariableValues } from "graphql/execution/values"; | ||
import { DocumentNode, ExecutionResult, GraphQLError, GraphQLFieldResolver, GraphQLIsTypeOfFn, GraphQLObjectType, GraphQLOutputType, GraphQLSchema } from "graphql"; | ||
import { ExecutionContext as GraphQLContext } from "graphql/execution/execute"; | ||
import { FieldNode } from "graphql/language/ast"; | ||
import Maybe from "graphql/tsutils/Maybe"; | ||
import { GraphQLTypeResolver } from "graphql/type/definition"; | ||
import { Arguments, ObjectPath } from "./ast"; | ||
import { GraphQLError as GraphqlJitError } from "./error"; | ||
import { NullTrimmer } from "./non-null"; | ||
import { ResolveInfoEnricherInput } from "./resolve-info"; | ||
import { CoercedVariableValues } from "./variables"; | ||
declare const inspect: (value: any) => string; | ||
export interface CompilerOptions { | ||
@@ -22,4 +26,20 @@ customJSONSerializer: boolean; | ||
*/ | ||
interface CompilationContext extends ExecutionContext { | ||
dependencies: Map<string, (...args: any[]) => any>; | ||
interface CompilationContext extends GraphQLContext { | ||
resolvers: { | ||
[key: string]: GraphQLFieldResolver<any, any, any>; | ||
}; | ||
serializers: { | ||
[key: string]: (c: ExecutionContext, v: any, onError: (c: ExecutionContext, msg: string) => void) => any; | ||
}; | ||
hoistedFunctions: string[]; | ||
hoistedFunctionNames: Map<string, number>; | ||
typeResolvers: { | ||
[key: string]: GraphQLTypeResolver<any, any>; | ||
}; | ||
isTypeOfs: { | ||
[key: string]: GraphQLIsTypeOfFn<any, any>; | ||
}; | ||
resolveInfos: { | ||
[key: string]: any; | ||
}; | ||
deferred: DeferredField[]; | ||
@@ -29,2 +49,33 @@ options: CompilerOptions; | ||
} | ||
interface ExecutionContext { | ||
promiseCounter: number; | ||
data: any; | ||
errors: GraphQLError[]; | ||
nullErrors: GraphQLError[]; | ||
resolve?: () => void; | ||
inspect: typeof inspect; | ||
variables: { | ||
[key: string]: any; | ||
}; | ||
context: any; | ||
rootValue: any; | ||
safeMap: typeof safeMap; | ||
GraphQLError: typeof GraphqlJitError; | ||
resolvers: { | ||
[key: string]: GraphQLFieldResolver<any, any, any>; | ||
}; | ||
trimmer: NullTrimmer; | ||
serializers: { | ||
[key: string]: (c: ExecutionContext, v: any, onError: (c: ExecutionContext, msg: string) => void) => any; | ||
}; | ||
typeResolvers: { | ||
[key: string]: GraphQLTypeResolver<any, any>; | ||
}; | ||
isTypeOfs: { | ||
[key: string]: GraphQLIsTypeOfFn<any, any>; | ||
}; | ||
resolveInfos: { | ||
[key: string]: any; | ||
}; | ||
} | ||
interface DeferredField { | ||
@@ -41,8 +92,6 @@ name: string; | ||
} | ||
export declare type Callback = (d: object | null, e: Error | null) => void; | ||
export declare type JITCallback = (p: object, d: object | null, e: Error | null) => void; | ||
export interface CompiledQuery { | ||
operationName?: string; | ||
query: (root: any, context: any, variables: Maybe<{ | ||
[key: string]: GraphQLScalarSerializer<any>; | ||
[key: string]: any; | ||
}>) => Promise<ExecutionResult> | ExecutionResult; | ||
@@ -61,3 +110,3 @@ stringify: (v: any) => string; | ||
export declare function isCompiledQuery<C extends CompiledQuery, E extends ExecutionResult>(query: C | E): query is C; | ||
export declare function createBoundQuery(compilationContext: CompilationContext, document: DocumentNode, func: (...args: any[]) => any, getVariableValues: (inputs: { | ||
export declare function createBoundQuery(compilationContext: CompilationContext, document: DocumentNode, func: (context: ExecutionContext) => Promise<any> | undefined, getVariableValues: (inputs: { | ||
[key: string]: any; | ||
@@ -67,42 +116,15 @@ }) => CoercedVariableValues, operationName?: string): (rootValue: any, context: any, variables: Maybe<{ | ||
}>) => ExecutionResult<import("graphql/execution/execute").ExecutionResultDataDefault> | Promise<ExecutionResult<import("graphql/execution/execute").ExecutionResultDataDefault>>; | ||
export declare function isPromise(value: any): value is Promise<any>; | ||
/** | ||
* Handles the book keeping of running promises | ||
* loosely and returning a final callback. | ||
* Implements a generic map operation for any iterable. | ||
* | ||
* The final callback is called after every possible promise has returned. | ||
* | ||
* Exported only for tests. | ||
* | ||
* @param finalCb callback to be called once the all promises have been resolved | ||
* @param {(err: Error) => void} errorHandler global error handler in case of bugs in the runtime | ||
* @returns an object with two function, a execute function and checker when everything is resolved | ||
* If the iterable is not valid, null is returned. | ||
* @param context | ||
* @param {Iterable<any> | string} iterable possible iterable | ||
* @param {(a: any) => any} cb callback that receives the item being iterated | ||
* @param idx | ||
* @returns {any[]} a new array with the result of the callback | ||
*/ | ||
export declare function loosePromiseExecutor(finalCb: (data: object, errors: GraphQLError[], nullErrors: GraphQLError[]) => void, errorHandler: (err: Error) => void): { | ||
executor: (resolver: () => Promise<any>, cb: JITCallback, parent: object, data: object, errors: GraphQLError[], nullErrors: GraphQLError[]) => void; | ||
resolveIfDone: (data: object, errors: GraphQLError[], nullErrors: GraphQLError[]) => void; | ||
}; | ||
/** | ||
* Handles the book keeping of running the top level promises serially. | ||
* The serial phase places all units of work in a queue which | ||
* is only started once startExecution is triggered. | ||
* | ||
* From then on, any new work is executed with the parallel executor. | ||
* New work is executed within the lifespan of the top level promise. | ||
* Once all promises are over, the executor will move on to the next serial | ||
* piece of work. | ||
* | ||
* The final callback is called after every possible promise has returned. | ||
* | ||
* Exported only for tests. | ||
* | ||
* @param finalCb callback to be called once the all promises have been resolved | ||
* @param {(err: Error) => void} errorHandler global error handler in case of bugs in the runtime | ||
* @returns an object with two function, a execute function to submit work and | ||
* startExecution to trigger the execution of everything submitted so far. | ||
*/ | ||
export declare function serialPromiseExecutor(finalCb: (data: object, errors: GraphQLError[], nullErrors: GraphQLError[]) => void, errorHandler: (err: Error) => void): { | ||
addToQueue: (resolver: () => Promise<any>, cb: JITCallback, parent: object, data: object, errors: GraphQLError[], nullErrors: GraphQLError[]) => void; | ||
startExecution: (data: object, errors: GraphQLError[], nullErrors: GraphQLError[]) => void; | ||
}; | ||
declare function safeMap(context: ExecutionContext, iterable: Iterable<any> | string, cb: (context: ExecutionContext, a: any, index: number, newArray: any[], ...idx: number[]) => any, ...idx: number[]): any[]; | ||
export declare function isPromise(value: any): value is Promise<any>; | ||
export declare function isPromiseInliner(value: string): string; | ||
export {}; |
@@ -19,10 +19,14 @@ "use strict"; | ||
const SAFETY_CHECK_PREFIX = "__validNode"; | ||
const GLOBAL_DATA_NAME = "__globalData"; | ||
const GLOBAL_ERRORS_NAME = "__globalErrors"; | ||
const GLOBAL_NULL_ERRORS_NAME = "__globalNullErrors"; | ||
const GLOBAL_EXECUTOR_NAME = "__executor"; | ||
const GLOBAL_ROOT_NAME = "__rootValue"; | ||
const GLOBAL_VARIABLES_NAME = "__variables"; | ||
const GLOBAL_CONTEXT_NAME = "__context"; | ||
const GLOBAL_INSPECT_NAME = "__inspect"; | ||
const GLOBAL_DATA_NAME = "__context.data"; | ||
const GLOBAL_ERRORS_NAME = "__context.errors"; | ||
const GLOBAL_NULL_ERRORS_NAME = "__context.nullErrors"; | ||
const GLOBAL_ROOT_NAME = "__context.rootValue"; | ||
const GLOBAL_VARIABLES_NAME = "__context.variables"; | ||
const GLOBAL_CONTEXT_NAME = "__context.context"; | ||
const GLOBAL_EXECUTION_CONTEXT = "__context"; | ||
const GLOBAL_PROMISE_COUNTER = "__context.promiseCounter"; | ||
const GLOBAL_INSPECT_NAME = "__context.inspect"; | ||
const GLOBAL_SAFE_MAP_NAME = "__context.safeMap"; | ||
const GRAPHQL_ERROR = "__context.GraphQLError"; | ||
const GLOBAL_RESOLVE = "__context.resolve"; | ||
const GLOBAL_PARENT_NAME = "__parent"; | ||
@@ -63,16 +67,13 @@ /** | ||
const getVariables = variables_1.compileVariableParsing(schema, context.operation.variableDefinitions || []); | ||
const mainBody = compileOperation(context); | ||
const functionBody = ` | ||
${getFunctionSignature(context)} { | ||
${functionHeader} | ||
${mainBody} | ||
${functionFooter} | ||
}`; | ||
const func = new Function(functionBody)(); | ||
return { | ||
query: createBoundQuery(context, document, func, getVariables, context.operation.name != null | ||
const functionBody = compileOperation(context); | ||
const compiledQuery = { | ||
query: createBoundQuery(context, document, new Function("return " + functionBody)(), getVariables, context.operation.name != null | ||
? context.operation.name.value | ||
: undefined), | ||
stringify | ||
stringify, | ||
// result of the compilation useful for debugging issues | ||
// and visualization tools like try-jit. | ||
__DO_NOT_USE_THIS_OR_YOU_WILL_BE_FIRED_compilation: functionBody | ||
}; | ||
return compiledQuery; | ||
} | ||
@@ -92,5 +93,4 @@ catch (err) { | ||
function createBoundQuery(compilationContext, document, func, getVariableValues, operationName) { | ||
const { operation: { operation } } = compilationContext; | ||
const { resolvers, typeResolvers, isTypeOfs, serializers, resolveInfos } = compilationContext; | ||
const trimmer = non_null_1.createNullTrimmer(compilationContext); | ||
const resolvers = getFunctionResolvers(compilationContext); | ||
const fnName = operationName ? operationName : "query"; | ||
@@ -112,60 +112,30 @@ /* tslint:disable */ | ||
// this can be shared across in a batch request | ||
const { errors, coerced } = getVariableValues(variables || {}); | ||
const parsedVariables = getVariableValues(variables || {}); | ||
// Return early errors if variable coercing failed. | ||
if (errors) { | ||
return { errors }; | ||
if (variables_1.failToParseVariables(parsedVariables)) { | ||
return { errors: parsedVariables.errors }; | ||
} | ||
let result = null; | ||
const maybePromise = { | ||
resolve: (r) => { | ||
result = r; | ||
}, | ||
reject: (err) => { | ||
throw err; | ||
} | ||
}; | ||
const callback = (data, errors, nullErrors) => { | ||
if (result) { | ||
throw new Error("called the final cb more than once"); | ||
} | ||
maybePromise.resolve(postProcessResult(trimmer, data, errors, nullErrors)); | ||
}; | ||
const globalErrorHandler = (err) => { | ||
// Logging the culprit | ||
// tslint:disable-next-line | ||
console.error(`bad function: ${func.toString()}`); | ||
// tslint:disable-next-line | ||
console.error(`good query: ${graphql_1.print(document)}`); | ||
maybePromise.reject(err); | ||
}; | ||
let executor; | ||
let resolveIfDone; | ||
if (operation === "mutation") { | ||
const serial = serialPromiseExecutor(callback, globalErrorHandler); | ||
executor = serial.addToQueue; | ||
resolveIfDone = serial.startExecution; | ||
} | ||
else { | ||
const loose = loosePromiseExecutor(callback, globalErrorHandler); | ||
executor = loose.executor; | ||
resolveIfDone = loose.resolveIfDone; | ||
} | ||
func.apply(null, [ | ||
const executionContext = { | ||
rootValue, | ||
context, | ||
coerced, | ||
executor, | ||
resolveIfDone, | ||
variables: parsedVariables.coerced, | ||
safeMap, | ||
inspect, | ||
error_1.GraphQLError, | ||
...resolvers | ||
]); | ||
if (result) { | ||
return result; | ||
GraphQLError: error_1.GraphQLError, | ||
resolvers, | ||
typeResolvers, | ||
isTypeOfs, | ||
serializers, | ||
resolveInfos, | ||
trimmer, | ||
promiseCounter: 0, | ||
data: {}, | ||
nullErrors: [], | ||
errors: [] | ||
}; | ||
const result = func.call(null, executionContext); | ||
if (isPromise(result)) { | ||
return result.then(postProcessResult); | ||
} | ||
return new Promise((resolve, reject) => { | ||
maybePromise.resolve = resolve; | ||
maybePromise.reject = reject; | ||
}); | ||
return postProcessResult(executionContext); | ||
} | ||
@@ -176,3 +146,3 @@ }; | ||
exports.createBoundQuery = createBoundQuery; | ||
function postProcessResult(trimmer, data, errors, nullErrors) { | ||
function postProcessResult({ data, nullErrors, errors, trimmer }) { | ||
if (nullErrors.length > 0) { | ||
@@ -206,7 +176,51 @@ const trimmed = trimmer(data, nullErrors); | ||
const type = graphql_1.getOperationRootType(context.schema, context.operation); | ||
const serialExecution = context.operation.operation === "mutation"; | ||
const fieldMap = execute_1.collectFields(context, type, context.operation.selectionSet, Object.create(null), Object.create(null)); | ||
const topLevel = compileObjectType(context, type, [], [GLOBAL_ROOT_NAME], [GLOBAL_DATA_NAME], undefined, GLOBAL_ERRORS_NAME, fieldMap, true); | ||
let body = generateUniqueDeclarations(context, true); | ||
body += `const ${GLOBAL_DATA_NAME} = ${topLevel}\n`; | ||
body += compileDeferredFields(context); | ||
let body = `function query (${GLOBAL_EXECUTION_CONTEXT}) { | ||
"use strict"; | ||
`; | ||
if (serialExecution) { | ||
body += `${GLOBAL_EXECUTION_CONTEXT}.queue = [];`; | ||
} | ||
body += generateUniqueDeclarations(context, true); | ||
body += `${GLOBAL_DATA_NAME} = ${topLevel}\n`; | ||
if (serialExecution) { | ||
body += compileDeferredFieldsSerially(context); | ||
body += ` | ||
${GLOBAL_EXECUTION_CONTEXT}.finalResolve = () => {}; | ||
${GLOBAL_RESOLVE} = (context) => { | ||
if (context.jobCounter >= context.queue.length) { | ||
// All mutations have finished | ||
context.finalResolve(context); | ||
return; | ||
} | ||
context.queue[context.jobCounter++](context); | ||
}; | ||
// There might not be a job to run due to invalid queries | ||
if (${GLOBAL_EXECUTION_CONTEXT}.queue.length > 0) { | ||
${GLOBAL_EXECUTION_CONTEXT}.jobCounter = 1; // since the first one will be run manually | ||
${GLOBAL_EXECUTION_CONTEXT}.queue[0](${GLOBAL_EXECUTION_CONTEXT}); | ||
} | ||
// Promises have been scheduled so a new promise is returned | ||
// that will be resolved once every promise is done | ||
if (${GLOBAL_PROMISE_COUNTER} > 0) { | ||
return new Promise(resolve => ${GLOBAL_EXECUTION_CONTEXT}.finalResolve = resolve); | ||
} | ||
`; | ||
} | ||
else { | ||
body += compileDeferredFields(context); | ||
body += ` | ||
// Promises have been scheduled so a new promise is returned | ||
// that will be resolved once every promise is done | ||
if (${GLOBAL_PROMISE_COUNTER} > 0) { | ||
return new Promise(resolve => ${GLOBAL_RESOLVE} = resolve); | ||
}`; | ||
} | ||
body += ` | ||
// sync execution, the results are ready | ||
return undefined; | ||
}`; | ||
body += context.hoistedFunctions.join("\n"); | ||
return body; | ||
@@ -224,29 +238,80 @@ } | ||
let body = ""; | ||
context.deferred.forEach(({ name, originPaths, destinationPaths, fieldNodes, fieldType, fieldName, responsePath, parentType, args }, index) => { | ||
const subContext = createSubCompilationContext(context); | ||
const nodeBody = compileType(subContext, parentType, fieldType, fieldNodes, [fieldName], [`${GLOBAL_PARENT_NAME}.${name}`], responsePath); | ||
const resolverName = getResolverName(parentType.name, fieldName); | ||
const topLevelArgs = getArgumentsVarName(resolverName); | ||
const validArgs = getValidArgumentsVarName(resolverName); | ||
context.deferred.forEach((deferredField, index) => { | ||
body += ` | ||
if (${SAFETY_CHECK_PREFIX}${index}) { | ||
${getArguments(subContext, args, topLevelArgs, validArgs, fieldType, responsePath)} | ||
if (${validArgs} === true) { | ||
${GLOBAL_EXECUTOR_NAME}(() => ${resolverName}( | ||
${originPaths.join(".")}, | ||
${topLevelArgs}, | ||
${GLOBAL_CONTEXT_NAME}, | ||
${getExecutionInfo(subContext, parentType, fieldType, fieldName, fieldNodes, responsePath)}), | ||
(${GLOBAL_PARENT_NAME}, ${fieldName}, err) => { | ||
if (err != null) { | ||
${graphql_1.isNonNullType(fieldType) | ||
? GLOBAL_NULL_ERRORS_NAME | ||
: GLOBAL_ERRORS_NAME}.push(${createErrorObject(context, fieldNodes, responsePath, "err.message != null ? err.message : err", "err") /* TODO: test why no return here*/}); | ||
if (${SAFETY_CHECK_PREFIX}${index}) { | ||
${compileDeferredField(context, deferredField)} | ||
}`; | ||
}); | ||
return body; | ||
} | ||
function compileDeferredField(context, deferredField, appendix) { | ||
const { name, originPaths, destinationPaths, fieldNodes, fieldType, fieldName, responsePath, parentType, args } = deferredField; | ||
const subContext = createSubCompilationContext(context); | ||
const nodeBody = compileType(subContext, parentType, fieldType, fieldNodes, [fieldName], [`${GLOBAL_PARENT_NAME}.${name}`], responsePath); | ||
const parentIndexes = getParentArgIndexes(context); | ||
const resolverName = getResolverName(parentType.name, fieldName); | ||
const resolverHandler = getHoistedFunctionName(context, `${name}${resolverName}Handler`); | ||
const topLevelArgs = getArgumentsName(resolverName); | ||
const validArgs = getValidArgumentsVarName(resolverName); | ||
const executionError = createErrorObject(context, fieldNodes, responsePath, "err.message != null ? err.message : err", "err"); | ||
const executionInfo = getExecutionInfo(subContext, parentType, fieldType, fieldName, fieldNodes, responsePath); | ||
const emptyError = createErrorObject(context, fieldNodes, responsePath, '""'); | ||
const resolverParentPath = originPaths.join("."); | ||
const resolverCall = `${GLOBAL_EXECUTION_CONTEXT}.resolvers.${resolverName}( | ||
${resolverParentPath},${topLevelArgs},${GLOBAL_CONTEXT_NAME}, ${executionInfo})`; | ||
const resultParentPath = destinationPaths.join("."); | ||
const compiledArgs = compileArguments(subContext, args, topLevelArgs, validArgs, fieldType, responsePath); | ||
const body = ` | ||
${compiledArgs} | ||
if (${validArgs} === true) { | ||
var __value = null; | ||
try { | ||
__value = ${resolverCall}; | ||
} catch (err) { | ||
${getErrorDestination(fieldType)}.push(${executionError}); | ||
} | ||
${generateUniqueDeclarations(subContext)} | ||
${GLOBAL_PARENT_NAME}.${name} = ${nodeBody};\n | ||
${compileDeferredFields(subContext)} | ||
},${destinationPaths.join(".")}, ${GLOBAL_DATA_NAME}, ${GLOBAL_ERRORS_NAME}, ${GLOBAL_NULL_ERRORS_NAME}) | ||
if (${isPromiseInliner("__value")}) { | ||
${promiseStarted()} | ||
__value.then(result => { | ||
${resolverHandler}(${GLOBAL_EXECUTION_CONTEXT}, ${resultParentPath}, result, ${parentIndexes}); | ||
${promiseDone()} | ||
}, err => { | ||
if (err) { | ||
${getErrorDestination(fieldType)}.push(${executionError}); | ||
} else { | ||
${getErrorDestination(fieldType)}.push(${emptyError}); | ||
} | ||
${promiseDone()} | ||
}); | ||
} else { | ||
${resolverHandler}(${GLOBAL_EXECUTION_CONTEXT}, ${resultParentPath}, __value, ${parentIndexes}); | ||
} | ||
}`; | ||
context.hoistedFunctions.push(` | ||
function ${resolverHandler}(${GLOBAL_EXECUTION_CONTEXT}, ${GLOBAL_PARENT_NAME}, ${fieldName}, ${parentIndexes}) { | ||
${generateUniqueDeclarations(subContext)} | ||
${GLOBAL_PARENT_NAME}.${name} = ${nodeBody}; | ||
${compileDeferredFields(subContext)} | ||
${appendix ? appendix : ""} | ||
} | ||
`); | ||
return body; | ||
} | ||
function compileDeferredFieldsSerially(context) { | ||
let body = ""; | ||
context.deferred.forEach(deferredField => { | ||
const { name, fieldName, parentType } = deferredField; | ||
const resolverName = getResolverName(parentType.name, fieldName); | ||
const mutationHandler = getHoistedFunctionName(context, `${name}${resolverName}Mutation`); | ||
body += `${GLOBAL_EXECUTION_CONTEXT}.queue.push(${mutationHandler});\n`; | ||
const appendix = ` | ||
if (${GLOBAL_PROMISE_COUNTER} === 0) { | ||
${GLOBAL_RESOLVE}(${GLOBAL_EXECUTION_CONTEXT}); | ||
} | ||
}`; | ||
`; | ||
context.hoistedFunctions.push(` | ||
function ${mutationHandler}(${GLOBAL_EXECUTION_CONTEXT}) { | ||
${compileDeferredField(context, deferredField, appendix)} | ||
} | ||
`); | ||
}); | ||
@@ -313,5 +378,11 @@ return body; | ||
else { | ||
context.dependencies.set(getSerializerName(type.name), getSerializer(type, context.options.customSerializers[type.name])); | ||
body += getSerializerName(type.name); | ||
body += `(${originPaths.join(".")}, (message) => {${errorDestination}.push(${createErrorObject(context, fieldNodes, previousPath, "message")});})`; | ||
const serializerName = getSerializerName(type.name); | ||
context.serializers[serializerName] = getSerializer(type, context.options.customSerializers[type.name]); | ||
const parentIndexes = getParentArgIndexes(context); | ||
const serializerErrorHandler = getHoistedFunctionName(context, `${type.name}${originPaths.join("")}SerializerErrorHandler`); | ||
context.hoistedFunctions.push(` | ||
function ${serializerErrorHandler}(${GLOBAL_EXECUTION_CONTEXT}, message, ${parentIndexes}) { | ||
${errorDestination}.push(${createErrorObject(context, fieldNodes, previousPath, "message")});} | ||
`); | ||
body += `${GLOBAL_EXECUTION_CONTEXT}.serializers.${serializerName}(${GLOBAL_EXECUTION_CONTEXT}, ${originPaths.join(".")}, ${serializerErrorHandler}, ${parentIndexes})`; | ||
} | ||
@@ -336,4 +407,4 @@ return body; | ||
if (typeof type.isTypeOf === "function" && !alwaysDefer) { | ||
context.dependencies.set(type.name + "IsTypeOf", type.isTypeOf); | ||
body += `!${type.name}IsTypeOf(${originPaths.join(".")}) ? (${errorDestination}.push(${createErrorObject(context, fieldNodes, responsePath, `\`Expected value of type "${type.name}" but got: $\{${GLOBAL_INSPECT_NAME}(${originPaths.join(".")})}.\``)}), null) :`; | ||
context.isTypeOfs[type.name + "IsTypeOf"] = type.isTypeOf; | ||
body += `!${GLOBAL_EXECUTION_CONTEXT}.isTypeOfs["${type.name}IsTypeOf"](${originPaths.join(".")}) ? (${errorDestination}.push(${createErrorObject(context, fieldNodes, responsePath, `\`Expected value of type "${type.name}" but got: $\{${GLOBAL_INSPECT_NAME}(${originPaths.join(".")})}.\``)}), null) :`; | ||
} | ||
@@ -374,3 +445,3 @@ body += "{"; | ||
}); | ||
context.dependencies.set(getResolverName(type.name, field.name), resolver); | ||
context.resolvers[getResolverName(type.name, field.name)] = resolver; | ||
body += `(${SAFETY_CHECK_PREFIX}${context.deferred.length - | ||
@@ -395,3 +466,4 @@ 1} = true, null)`; | ||
} | ||
context.dependencies.set(getTypeResolverName(type.name), resolveType); | ||
const typeResolverName = getTypeResolverName(type.name); | ||
context.typeResolvers[typeResolverName] = resolveType; | ||
const collectedTypes = context.schema | ||
@@ -436,4 +508,4 @@ .getPossibleTypes(type) | ||
})( | ||
${getTypeResolverName(type.name)}(${originPaths.join(".")}, | ||
__context, | ||
${GLOBAL_EXECUTION_CONTEXT}.typeResolvers.${typeResolverName}(${originPaths.join(".")}, | ||
${GLOBAL_CONTEXT_NAME}, | ||
${getExecutionInfo(context, parentType, type, type.name, fieldNodes, previousPath)}))`; | ||
@@ -458,73 +530,46 @@ } | ||
const newDepth = ++listContext.depth; | ||
const dataBody = compileType(listContext, parentType, type.ofType, fieldNodes, ["__safeMapNode"], ["__child"], ast_1.addPath(responsePath, "idx" + newDepth, "variable")); | ||
const fieldType = type.ofType; | ||
const dataBody = compileType(listContext, parentType, fieldType, fieldNodes, ["__safeMapNode"], ["__child"], ast_1.addPath(responsePath, "idx" + newDepth, "variable")); | ||
const errorMessage = `"Expected Iterable, but did not find one for field ${parentType.name}.${getFieldNodesName(fieldNodes)}."`; | ||
const errorCase = `(${errorDestination}.push(${createErrorObject(context, fieldNodes, responsePath, errorMessage)}), null)`; | ||
return `(typeof ${name} === "string" || typeof ${name}[Symbol.iterator] !== "function") ? ${errorCase} : | ||
__safeMap(${name}, (__safeMapNode, idx${newDepth}) => { | ||
${generateUniqueDeclarations(listContext)} | ||
const __child = ${dataBody}; | ||
${compileDeferredFields(listContext)} | ||
return __child; | ||
})`; | ||
} | ||
/** | ||
* Converts a promise to a callbackable interface | ||
* @param valueGen a function that can return a promise or an value | ||
* @param {Callback} cb callback to be called with the result, the cb should only called once | ||
* @param errorHandler handler for unexpected errors caused by bugs | ||
*/ | ||
function unpromisify(valueGen, cb, errorHandler) { | ||
let value; | ||
try { | ||
value = valueGen(); | ||
} | ||
catch (e) { | ||
cb(null, e); | ||
return; | ||
} | ||
if (isPromise(value)) { | ||
value | ||
.then((res) => cb(res, null), (err) => err != null | ||
? cb(null, err) | ||
: cb(null, new error_1.GraphQLError(""))) | ||
.catch(errorHandler); | ||
return; | ||
} | ||
else if (Array.isArray(value)) { | ||
return handleArrayValue(value, cb, errorHandler); | ||
} | ||
cb(value, null); | ||
} | ||
/** | ||
* Ensure that an array with possible local errors are handled cleanly. | ||
* | ||
* @param {any[]} value Array<Promise<any> | any> array of value | ||
* @param {Callback} cb | ||
* @param errorHandler handler for unexpected errors caused by bugs | ||
*/ | ||
function handleArrayValue(value, cb, errorHandler) { | ||
// The array might have local errors which need to be handled locally in order for proper error messages | ||
let hasPromises = false; | ||
const values = value.map(item => { | ||
if (isPromise(item)) { | ||
// return the error | ||
// the following transformations will take care of the error | ||
hasPromises = true; | ||
return item.catch((err) => { | ||
return err; | ||
}); | ||
const executionError = createErrorObject(context, fieldNodes, ast_1.addPath(responsePath, "idx" + newDepth, "variable"), "err.message != null ? err.message : err", "err"); | ||
const emptyError = createErrorObject(context, fieldNodes, responsePath, '""'); | ||
const uniqueDeclarations = generateUniqueDeclarations(listContext); | ||
const deferredFields = compileDeferredFields(listContext); | ||
const promiseHandler = getHoistedFunctionName(context, `${parentType.name}${originalObjectPaths.join("")}MapPromiseHandler`); | ||
const childIndexes = getParentArgIndexes(listContext); | ||
listContext.hoistedFunctions.push(` | ||
function ${promiseHandler}(${GLOBAL_EXECUTION_CONTEXT}, ${GLOBAL_PARENT_NAME}, __safeMapNode, ${childIndexes}) { | ||
${uniqueDeclarations} | ||
${GLOBAL_PARENT_NAME}[idx${newDepth}] = ${dataBody}; | ||
${deferredFields} | ||
} | ||
`); | ||
const safeMapHandler = getHoistedFunctionName(context, `${parentType.name}${originalObjectPaths.join("")}MapHandler`); | ||
const parentIndexes = getParentArgIndexes(context); | ||
listContext.hoistedFunctions.push(` | ||
function ${safeMapHandler}(${GLOBAL_EXECUTION_CONTEXT}, __safeMapNode, idx${newDepth}, newArray, ${parentIndexes}) { | ||
if (${isPromiseInliner("__safeMapNode")}) { | ||
${promiseStarted()} | ||
__safeMapNode.then(result => { | ||
${promiseHandler}(${GLOBAL_EXECUTION_CONTEXT}, newArray, result, ${childIndexes}); | ||
${promiseDone()} | ||
}, err => { | ||
if (err) { | ||
${getErrorDestination(fieldType)}.push(${executionError}); | ||
} else { | ||
${getErrorDestination(fieldType)}.push(${emptyError}); | ||
} | ||
return item; | ||
}); | ||
if (hasPromises) { | ||
return unpromisify( | ||
// This promise should not reject but it is handled anyway | ||
() => Promise.all(values), (v, err) => { | ||
if (err != null) { | ||
return cb(v, err); | ||
} | ||
return cb(v, null); | ||
}, errorHandler); | ||
${promiseDone()} | ||
}); | ||
return null; | ||
} | ||
cb(values, null); | ||
${uniqueDeclarations} | ||
const __child = ${dataBody}; | ||
${deferredFields} | ||
return __child; | ||
} | ||
`); | ||
return `(typeof ${name} === "string" || typeof ${name}[Symbol.iterator] !== "function") ? ${errorCase} : | ||
${GLOBAL_SAFE_MAP_NAME}(${GLOBAL_EXECUTION_CONTEXT}, ${name}, ${safeMapHandler}, ${parentIndexes})`; | ||
} | ||
@@ -535,11 +580,13 @@ /** | ||
* If the iterable is not valid, null is returned. | ||
* @param context | ||
* @param {Iterable<any> | string} iterable possible iterable | ||
* @param {(a: any) => any} cb callback that receives the item being iterated | ||
* @param idx | ||
* @returns {any[]} a new array with the result of the callback | ||
*/ | ||
function safeMap(iterable, cb) { | ||
function safeMap(context, iterable, cb, ...idx) { | ||
let index = 0; | ||
const result = []; | ||
for (const a of iterable) { | ||
const item = cb(a, index); | ||
const item = cb(context, a, index, result, ...idx); | ||
result.push(item); | ||
@@ -550,26 +597,2 @@ ++index; | ||
} | ||
/** | ||
* Extracts the names to be bounded on the compiled function | ||
* @param {CompilationContext} context that contains the function args | ||
* @returns {string} a comma separated string with variable names | ||
*/ | ||
function getResolversVariablesName(context) { | ||
let decl = ""; | ||
for (const name of context.dependencies.keys()) { | ||
decl += `${name},`; | ||
} | ||
return decl; | ||
} | ||
/** | ||
* Gets the variables that should be bounded to the compiled function | ||
* @param {CompilationContext} context that contains the function args | ||
* @returns {any[]} an array with references to the boundable variables | ||
*/ | ||
function getFunctionResolvers(context) { | ||
const resolvers = []; | ||
for (const resolver of context.dependencies.values()) { | ||
resolvers.push(resolver); | ||
} | ||
return resolvers; | ||
} | ||
const MAGIC_MINUS_INFINITY = "__MAGIC_MINUS_INFINITY__71d4310a-d4a3-4a05-b1fe-e60779d24998"; | ||
@@ -611,3 +634,3 @@ const MAGIC_PLUS_INFINITY = "__MAGIC_PLUS_INFINITY__bb201c39-3333-4695-b4ad-7f1722e7aa7a"; | ||
const { schema, fragments, operation } = context; | ||
context.dependencies.set(resolveInfoName, resolve_info_1.createResolveInfoThunk({ | ||
context.resolveInfos[resolveInfoName] = resolve_info_1.createResolveInfoThunk({ | ||
schema, | ||
@@ -620,6 +643,6 @@ fragments, | ||
fieldNodes | ||
}, context.options.resolverInfoEnricher)); | ||
return `${resolveInfoName}(${GLOBAL_ROOT_NAME}, ${GLOBAL_VARIABLES_NAME}, ${serializeResponsePath(responsePath)})`; | ||
}, context.options.resolverInfoEnricher); | ||
return `${GLOBAL_EXECUTION_CONTEXT}.resolveInfos.${resolveInfoName}(${GLOBAL_ROOT_NAME}, ${GLOBAL_VARIABLES_NAME}, ${serializeResponsePath(responsePath)})`; | ||
} | ||
function getArgumentsVarName(prefixName) { | ||
function getArgumentsName(prefixName) { | ||
return `${prefixName}Args`; | ||
@@ -638,2 +661,3 @@ } | ||
else { | ||
/* istanbul ignore next */ | ||
throw new Error("should only have received literal paths"); | ||
@@ -654,3 +678,3 @@ } | ||
*/ | ||
function getArguments(context, args, topLevelArg, validArgs, returnType, path) { | ||
function compileArguments(context, args, topLevelArg, validArgs, returnType, path) { | ||
// default to assuming arguments are valid | ||
@@ -661,5 +685,3 @@ let body = ` | ||
`; | ||
const errorDestination = graphql_1.isNonNullType(returnType) | ||
? GLOBAL_NULL_ERRORS_NAME | ||
: GLOBAL_ERRORS_NAME; | ||
const errorDestination = getErrorDestination(returnType); | ||
for (const variable of args.missing) { | ||
@@ -716,2 +738,6 @@ const varName = variable.valueNode.name.value; | ||
exports.isPromise = isPromise; | ||
function isPromiseInliner(value) { | ||
return `${value} != null && typeof ${value} === "object" && typeof ${value}.then === "function"`; | ||
} | ||
exports.isPromiseInliner = isPromiseInliner; | ||
/** | ||
@@ -738,2 +764,5 @@ * Serializes the response path for an error response. | ||
} | ||
function getErrorDestination(type) { | ||
return graphql_1.isNonNullType(type) ? GLOBAL_NULL_ERRORS_NAME : GLOBAL_ERRORS_NAME; | ||
} | ||
function createResolveInfoName(path) { | ||
@@ -774,7 +803,7 @@ return (ast_1.flattenPath(path) | ||
: (val) => scalar.serialize(val); | ||
return (v, onError) => { | ||
return function leafSerializer(context, v, onError, ...idx) { | ||
try { | ||
const value = serialize(v); | ||
if (isInvalid(value)) { | ||
onError(`Expected a value of type "${name}" but received: ${v}`); | ||
onError(context, `Expected a value of type "${name}" but received: ${v}`, ...idx); | ||
return null; | ||
@@ -785,4 +814,4 @@ } | ||
catch (e) { | ||
onError((e && e.message) || | ||
`Expected a value of type "${name}" but received an Error`); | ||
onError(context, (e && e.message) || | ||
`Expected a value of type "${name}" but received an Error`, ...idx); | ||
return null; | ||
@@ -869,5 +898,11 @@ } | ||
options, | ||
dependencies: new Map(), | ||
resolvers: {}, | ||
serializers: {}, | ||
typeResolvers: {}, | ||
isTypeOfs: {}, | ||
resolveInfos: {}, | ||
hoistedFunctions: [], | ||
hoistedFunctionNames: new Map(), | ||
deferred: [], | ||
depth: 0, | ||
depth: -1, | ||
variableValues: {}, | ||
@@ -883,4 +918,13 @@ fieldResolver: undefined, | ||
} | ||
function getHoistedFunctionName(context, name) { | ||
const count = context.hoistedFunctionNames.get(name); | ||
if (count === undefined) { | ||
context.hoistedFunctionNames.set(name, 0); | ||
return name; | ||
} | ||
context.hoistedFunctionNames.set(name, count + 1); | ||
return `${name}${count + 1}`; | ||
} | ||
function createErrorObject(context, nodes, path, message, originalError) { | ||
return `new GraphQLError(${message}, | ||
return `new ${GRAPHQL_ERROR}(${message}, | ||
${JSON.stringify(ast_1.computeLocations(nodes))}, | ||
@@ -900,117 +944,16 @@ ${serializeResponsePathAsArray(path)}, | ||
} | ||
/** | ||
* Create the function signature | ||
* @param {CompilationContext} context compilation context | ||
* @returns {string} compiled function signature | ||
*/ | ||
function getFunctionSignature(context) { | ||
return `return function query ( | ||
${GLOBAL_ROOT_NAME}, ${GLOBAL_CONTEXT_NAME}, ${GLOBAL_VARIABLES_NAME}, ${GLOBAL_EXECUTOR_NAME}, | ||
__resolveIfDone, __safeMap, ${GLOBAL_INSPECT_NAME}, GraphQLError, | ||
${getResolversVariablesName(context)})`; | ||
function promiseStarted() { | ||
return ` | ||
// increase the promise counter | ||
++${GLOBAL_PROMISE_COUNTER}; | ||
`; | ||
} | ||
// static function footer that contain bookkeeping for sync resolutions | ||
const functionFooter = ` | ||
__resolveIfDone(${GLOBAL_DATA_NAME}, ${GLOBAL_ERRORS_NAME}, ${GLOBAL_NULL_ERRORS_NAME}) | ||
`; | ||
// static function header that contain bookkeeping | ||
// for the callbacks being used throughout the tree | ||
const functionHeader = ` | ||
"use strict"; | ||
const ${GLOBAL_NULL_ERRORS_NAME} = []; | ||
const ${GLOBAL_ERRORS_NAME} = []; | ||
`; | ||
/** | ||
* Handles the book keeping of running promises | ||
* loosely and returning a final callback. | ||
* | ||
* The final callback is called after every possible promise has returned. | ||
* | ||
* Exported only for tests. | ||
* | ||
* @param finalCb callback to be called once the all promises have been resolved | ||
* @param {(err: Error) => void} errorHandler global error handler in case of bugs in the runtime | ||
* @returns an object with two function, a execute function and checker when everything is resolved | ||
*/ | ||
function loosePromiseExecutor(finalCb, errorHandler) { | ||
let counter = 1; // start with one to handle sync operations | ||
// this will be called in the function footer for sync | ||
function resolveIfDone(data, errors, nullErrors) { | ||
--counter; | ||
if (counter === 0) { | ||
finalCb(data, errors, nullErrors); | ||
} | ||
function promiseDone() { | ||
return ` | ||
--${GLOBAL_PROMISE_COUNTER}; | ||
if (${GLOBAL_PROMISE_COUNTER} === 0) { | ||
${GLOBAL_RESOLVE}(${GLOBAL_EXECUTION_CONTEXT}); | ||
} | ||
function executor(resolver, cb, parent, data, errors, nullErrors) { | ||
counter++; | ||
unpromisify(resolver, (res, err) => { | ||
cb(parent, res, err); | ||
resolveIfDone(data, errors, nullErrors); | ||
}, errorHandler); | ||
} | ||
return { | ||
executor, | ||
resolveIfDone | ||
}; | ||
`; | ||
} | ||
exports.loosePromiseExecutor = loosePromiseExecutor; | ||
/** | ||
* Handles the book keeping of running the top level promises serially. | ||
* The serial phase places all units of work in a queue which | ||
* is only started once startExecution is triggered. | ||
* | ||
* From then on, any new work is executed with the parallel executor. | ||
* New work is executed within the lifespan of the top level promise. | ||
* Once all promises are over, the executor will move on to the next serial | ||
* piece of work. | ||
* | ||
* The final callback is called after every possible promise has returned. | ||
* | ||
* Exported only for tests. | ||
* | ||
* @param finalCb callback to be called once the all promises have been resolved | ||
* @param {(err: Error) => void} errorHandler global error handler in case of bugs in the runtime | ||
* @returns an object with two function, a execute function to submit work and | ||
* startExecution to trigger the execution of everything submitted so far. | ||
*/ | ||
function serialPromiseExecutor(finalCb, errorHandler) { | ||
const queue = []; | ||
// Serial phase is running until execution starts | ||
let serialPhase = true; | ||
let currentExecutor; | ||
// this will be called in the function footer for starting the execution | ||
function continueExecution(data, errors, nullErrors) { | ||
serialPhase = false; | ||
const postponedWork = queue.shift(); | ||
if (postponedWork) { | ||
const { resolver, cb, parent, executor, resolveIfDone } = postponedWork; | ||
currentExecutor = executor; | ||
currentExecutor(resolver, cb, parent, data, errors, nullErrors); | ||
resolveIfDone(data, errors, nullErrors); | ||
return; | ||
} | ||
finalCb(data, errors, nullErrors); | ||
} | ||
function addToQueue(resolver, cb, parent, data, errors, nullErrors) { | ||
if (serialPhase) { | ||
const { executor, resolveIfDone } = loosePromiseExecutor((data, errors, nullErrors) => continueExecution(data, errors, nullErrors), errorHandler); | ||
queue.push({ | ||
executor, | ||
resolveIfDone, | ||
resolver, | ||
cb, | ||
parent | ||
}); | ||
} | ||
else { | ||
// We are using the parallel executor once the serial phase is over | ||
currentExecutor(resolver, cb, parent, data, errors, nullErrors); | ||
} | ||
} | ||
return { | ||
addToQueue, | ||
startExecution: continueExecution | ||
}; | ||
} | ||
exports.serialPromiseExecutor = serialPromiseExecutor; | ||
function normalizeErrors(err) { | ||
@@ -1033,2 +976,12 @@ if (Array.isArray(err)) { | ||
} | ||
function getParentArgIndexes(context) { | ||
let args = ""; | ||
for (let i = 0; i <= context.depth; ++i) { | ||
if (i > 0) { | ||
args += ", "; | ||
} | ||
args += `idx${i}`; | ||
} | ||
return args; | ||
} | ||
//# sourceMappingURL=execution.js.map |
@@ -1,5 +0,15 @@ | ||
import { GraphQLSchema, VariableDefinitionNode } from "graphql"; | ||
import { CoercedVariableValues } from "graphql/execution/values"; | ||
import { GraphQLError, GraphQLSchema, VariableDefinitionNode } from "graphql"; | ||
export declare type CoercedVariableValues = FailedVariableCoercion | VariableValues; | ||
interface FailedVariableCoercion { | ||
errors: ReadonlyArray<GraphQLError>; | ||
} | ||
interface VariableValues { | ||
coerced: { | ||
[key: string]: any; | ||
}; | ||
} | ||
export declare function failToParseVariables(x: any): x is FailedVariableCoercion; | ||
export declare function compileVariableParsing(schema: GraphQLSchema, varDefNodes: ReadonlyArray<VariableDefinitionNode>): (inputs: { | ||
[key: string]: any; | ||
}) => CoercedVariableValues; | ||
export {}; |
@@ -12,2 +12,6 @@ "use strict"; | ||
const inspect = inspect_1.default(); | ||
function failToParseVariables(x) { | ||
return x.errors; | ||
} | ||
exports.failToParseVariables = failToParseVariables; | ||
function createSubCompilationContext(context) { | ||
@@ -64,3 +68,3 @@ return Object.assign({}, context); | ||
`); | ||
return Function.apply(null, ["GraphQLError", "inspect"] | ||
return Function.apply(null, ["GraphQLJITError", "inspect"] | ||
.concat(Array.from(dependencies.keys())) | ||
@@ -95,3 +99,3 @@ .concat(gen.toString())).apply(null, [error_1.GraphQLError, inspect].concat(Array.from(dependencies.values()))); | ||
if (${currentOutput} == null) { | ||
errors.push(new GraphQLError(${hasValueName} ? ${nonNullMessage} : ${omittedMessage}, ${errorLocation})); | ||
errors.push(new GraphQLJITError(${hasValueName} ? ${nonNullMessage} : ${omittedMessage}, ${errorLocation})); | ||
} | ||
@@ -115,3 +119,3 @@ `); | ||
} else { | ||
errors.push(new GraphQLError('Variable "$${varName}" got invalid value ' + | ||
errors.push(new GraphQLJITError('Variable "$${varName}" got invalid value ' + | ||
inspect(${currentInput}) + "; " + | ||
@@ -130,3 +134,3 @@ 'Expected type ${varType.name}; ' + | ||
} else { | ||
errors.push(new GraphQLError('Variable "$${varName}" got invalid value ' + | ||
errors.push(new GraphQLJITError('Variable "$${varName}" got invalid value ' + | ||
inspect(${currentInput}) + "; " + | ||
@@ -145,3 +149,3 @@ 'Expected type ${varType.name}; ' + | ||
} else { | ||
errors.push(new GraphQLError('Variable "$${varName}" got invalid value ' + | ||
errors.push(new GraphQLJITError('Variable "$${varName}" got invalid value ' + | ||
inspect(${currentInput}) + "; " + | ||
@@ -158,3 +162,3 @@ 'Expected type ${varType.name}; ' + | ||
if (${currentInput} > ${MAX_32BIT_INT} || ${currentInput} < ${MIN_32BIT_INT}) { | ||
errors.push(new GraphQLError('Variable "$${varName}" got invalid value ' + | ||
errors.push(new GraphQLJITError('Variable "$${varName}" got invalid value ' + | ||
inspect(${currentInput}) + "; " + | ||
@@ -168,3 +172,3 @@ 'Expected type ${varType.name}; ' + | ||
} else { | ||
errors.push(new GraphQLError('Variable "$${varName}" got invalid value ' + | ||
errors.push(new GraphQLJITError('Variable "$${varName}" got invalid value ' + | ||
inspect(${currentInput}) + "; " + | ||
@@ -183,3 +187,3 @@ 'Expected type ${varType.name}; ' + | ||
} else { | ||
errors.push(new GraphQLError('Variable "$${varName}" got invalid value ' + | ||
errors.push(new GraphQLJITError('Variable "$${varName}" got invalid value ' + | ||
inspect(${currentInput}) + "; " + | ||
@@ -199,3 +203,3 @@ 'Expected type ${varType.name}; ' + | ||
if (parseResult === undefined || parseResult !== parseResult) { | ||
errors.push(new GraphQLError('Variable "$${varName}" got invalid value ' + | ||
errors.push(new GraphQLJITError('Variable "$${varName}" got invalid value ' + | ||
inspect(${currentInput}) + "; " + | ||
@@ -206,3 +210,3 @@ 'Expected type ${varType.name}.', ${errorLocation})); | ||
} catch (error) { | ||
errors.push(new GraphQLError('Variable "$${varName}" got invalid value ' + | ||
errors.push(new GraphQLJITError('Variable "$${varName}" got invalid value ' + | ||
inspect(${currentInput}) + "; " + | ||
@@ -224,3 +228,3 @@ 'Expected type ${varType.name}.', ${errorLocation}) | ||
errors.push( | ||
new GraphQLError('Variable "$${varName}" got invalid value ' + | ||
new GraphQLJITError('Variable "$${varName}" got invalid value ' + | ||
inspect(${currentInput}) + "; " + | ||
@@ -232,3 +236,3 @@ 'Expected type ${varType.name}.', ${errorLocation}) | ||
errors.push( | ||
new GraphQLError('Variable "$${varName}" got invalid value ' + | ||
new GraphQLJITError('Variable "$${varName}" got invalid value ' + | ||
inspect(${currentInput}) + "; " + | ||
@@ -264,3 +268,3 @@ 'Expected type ${varType.name}.', ${errorLocation}) | ||
if (typeof ${currentInput} !== 'object') { | ||
errors.push(new GraphQLError('Variable "$${varName}" got invalid value ' + | ||
errors.push(new GraphQLJITError('Variable "$${varName}" got invalid value ' + | ||
inspect(${currentInput}) + "; " + | ||
@@ -293,3 +297,3 @@ 'Expected type ${varType.name} to be an object.', ${errorLocation})); | ||
if (!allowedFields.includes(fieldName)) { | ||
errors.push(new GraphQLError('Variable "$${varName}" got invalid value ' + | ||
errors.push(new GraphQLJITError('Variable "$${varName}" got invalid value ' + | ||
inspect(${currentInput}) + "; " + | ||
@@ -296,0 +300,0 @@ 'Field "' + fieldName + '" is not defined by type ${varType.name}.', ${errorLocation})); |
{ | ||
"name": "graphql-jit", | ||
"version": "0.3.3", | ||
"version": "0.4.0", | ||
"description": "GraphQL JIT Compiler to JS", | ||
@@ -41,3 +41,3 @@ "main": "dist/index.js", | ||
"global": { | ||
"branches": 96, | ||
"branches": 95, | ||
"functions": 96, | ||
@@ -44,0 +44,0 @@ "lines": 96, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
182369
2740