Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

graphql-jit

Package Overview
Dependencies
Maintainers
3
Versions
47
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

graphql-jit - npm Package Compare versions

Comparing version 0.3.3 to 0.4.0

114

dist/execution.d.ts

@@ -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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc