import type { ConstValueNode, DirectiveNode, FieldNode, GraphQLEnumValueConfig, GraphQLFieldConfig, GraphQLInputFieldConfig, GraphQLInputObjectTypeConfig, GraphQLInputType, GraphQLNamedType, GraphQLObjectTypeConfig, GraphQLSchema, ValueNode } from "graphql"; import * as graphql from "graphql"; import type { LayerPlan, LayerPlanReasonDefer, LayerPlanReasonListItem, LayerPlanReasonSubscription } from "./engine/LayerPlan.ts"; import type { OperationPlan } from "./engine/OperationPlan.ts"; import type { BaseGraphQLArguments, GrafastFieldConfig, GrafastInputFieldConfig, Maybe } from "./interfaces.ts"; import type { Step } from "./step.ts"; /** * The parent object is used as the key in `GetValueStepId()`; for root level * fields it's possible that the parent will be null/undefined (in all other * cases it will be an object), so we need a value that can be the key in a * WeakMap to represent the root. */ export declare const ROOT_VALUE_OBJECT: any; export declare function assertNullPrototype(object: Record, description: string): void; /** * Specifically allows for the `defaultValue` to be undefined, but otherwise * defers to {@link rawValueToValueNode} */ export declare function defaultValueToValueNode(type: GraphQLInputType, defaultValue: unknown): ConstValueNode | undefined; export declare function isPromise(t: T | Promise): t is Promise; /** * Is "thenable". */ export declare function isPromiseLike(t: T | PromiseLike): t is PromiseLike; /** * Returns true if array1 and array2 have the same length, and every pair of * values within them pass the `comparator` check (which defaults to `===`). */ export declare function arraysMatch(array1: ReadonlyArray, array2: ReadonlyArray, comparator?: (val1: T, val2: T) => boolean): boolean; export declare function maybeArraysMatch(array1: Maybe>, array2: Maybe>, comparator?: (val1: T, val2: T) => boolean): boolean; /** * Returns true if map1 and map2 have the same keys, and every matching entry * value within them pass the `comparator` check (which defaults to `===`). */ export declare function mapsMatch(map1: ReadonlyMap, map2: ReadonlyMap, comparator?: (k: TKey, val1: TVal | undefined, val2: TVal | undefined) => boolean): boolean; /** * Returns true if record1 and record2 are equivalent, i.e. every value within * them pass the `comparator` check (which defaults to `===`). * * Currently keys are ignored (`record[key] = undefined` is treated the same as * `record[key]` being unset), but this may not always be the case. */ export declare function recordsMatch(record1: TRecord, record2: TRecord, comparator?: (k: keyof TRecord, val1: TRecord[typeof k], val2: TRecord[typeof k]) => boolean): boolean; export declare function setsMatch(s1: ReadonlySet | null, s2: ReadonlySet | null): boolean; export type ObjectTypeFields = { [key: string]: GrafastFieldConfig; }; export type ObjectTypeSpec> = Omit, "fields"> & { fields: TFields | (() => TFields); assertStep?: TParentStep extends Step ? ((step: Step) => asserts step is TParentStep) | { new (...args: any[]): TParentStep; } : null; planType?: ($specifier: Step) => TParentStep; }; /** * Saves us having to write `extensions: {grafast: {...}}` everywhere. */ export declare function objectSpec>(spec: ObjectTypeSpec): GraphQLObjectTypeConfig; export type GrafastObjectType> = graphql.GraphQLObjectType ? U : never> & { TParentStep: TParentStep; TFields: TFields; }; /** * @remarks This is a mess because the first two generics need to be specified manually, but the latter one we want inferred. */ export declare function newObjectTypeBuilder(assertStep: TParentStep extends Step ? ((step: Step) => asserts step is TParentStep) | { new (...args: any[]): TParentStep; } : never): >(spec: ObjectTypeSpec) => GrafastObjectType; /** * Saves us having to write `extensions: {grafast: {...}}` everywhere. */ export declare function objectFieldSpec(grafastSpec: GrafastFieldConfig, path: string): GraphQLFieldConfig; /** * "Constrainted identity function" for field configs. * * @see {@link https://kentcdodds.com/blog/how-to-write-a-constrained-identity-function-in-typescript} */ export declare function newGrafastFieldConfigBuilder(): (config: GrafastFieldConfig) => typeof config; export type GrafastInputFieldConfigMap = { [key: string]: GrafastInputFieldConfig; }; export type InputObjectTypeSpec = Omit & { fields: GrafastInputFieldConfigMap | (() => GrafastInputFieldConfigMap); }; export type GrafastInputObjectType = graphql.GraphQLInputObjectType & { TParent: TParent; }; export declare function newInputObjectTypeBuilder(): (spec: InputObjectTypeSpec) => GrafastInputObjectType; /** * Saves us having to write `extensions: {grafast: {...}}` everywhere. */ export declare function inputObjectFieldSpec(grafastSpec: GrafastInputFieldConfig, path: string): GraphQLInputFieldConfig; declare module "graphql" { interface GraphQLEnumType { [$$valueConfigByValue]?: Record; } } declare const $$valueConfigByValue: unique symbol; export declare function getEnumValueConfigs(enumType: graphql.GraphQLEnumType): { [outputValue: string]: GraphQLEnumValueConfig | undefined; }; /** * This would be equivalent to `enumType._valueLookup.get(outputValue)` except * that's not a public API so we have to do a bit of heavy lifting here. Since * it is heavy lifting, we cache the result, but we don't know when enumType * will go away so we use a weakmap. */ export declare function getEnumValueConfig(enumType: graphql.GraphQLEnumType, outputValue: string): GraphQLEnumValueConfig | undefined; /** * Ridiculously, this is faster than `new Array(length).fill(fill)` */ export declare function arrayOfLength(length: number, fill?: any): any[]; export declare const valueNodeToStaticValue: typeof graphql.valueFromAST; export declare function findVariableNamesUsedInValueNode(valueNode: ValueNode, variableNames: Set): void; /** * Given a FieldNode, recursively walks and finds all the variable references, * returning a list of the (unique) variable names used. */ export declare function findVariableNamesUsed(operationPlan: OperationPlan, field: FieldNode): string[]; export declare function isTypePlanned(schema: GraphQLSchema, namedType: GraphQLNamedType): boolean; /** * Returns `true` if the first argument depends on the second argument either * directly or indirectly (via a chain of dependencies). */ export declare function stepADependsOnStepB(stepA: Step, stepB: Step, sansSideEffects?: boolean): boolean; /** * Returns true if stepA is allowed to depend on stepB, false otherwise. (This * mostly relates to heirarchy.) */ export declare function stepAMayDependOnStepB($a: Step, $b: Step): boolean; export declare function stepAShouldTryAndInlineIntoStepB($a: Step, $b: Step): boolean; export declare function pathsFromAncestorToTargetLayerPlan(ancestor: LayerPlan, lp: LayerPlan): readonly LayerPlan[][]; export declare function layerPlanHeirarchyContains(lp: LayerPlan, targetLp: LayerPlan): boolean; /** * For a regular GraphQL query with no `@stream`/`@defer`, the entire result is * calculated and then the output is generated and sent to the client at once. * Thus you can think of this as every plan is in the same "phase". * * However, if you introduce a `@stream`/`@defer` selection, then the steps * inside that selection should run _later_ than the steps in the parent * selection - they should run in two different phases. Similar is true for * subscriptions. * * When optimizing your plans, if you are not careful you may end up pushing * what should be later work into the earlier phase, resulting in the initial * payload being delayed whilst things that should have been deferred are being * calculated. Thus, you should generally check that two plans are in the same phase * before you try and merge them. * * This is not a strict rule, though, because sometimes it makes more sense to * push work into the parent phase because it would be faster overall to do * that work there, and would not significantly delay the initial payload's * execution time - for example it's unlikely that it would make sense to defer * selecting an additional boolean column from a database table even if the * operation indicates that's what you should do. * * As a step class author, it's your responsiblity to figure out the right * approach. Once you have, you can use this function to help you, should you * need it. */ export declare function stepsAreInSamePhase(ancestor: Step, descendent: Step): boolean; export declare function isPhaseTransitionLayerPlan(layerPlan: LayerPlan): layerPlan is LayerPlan | LayerPlan | LayerPlan; export declare const canonicalJSONStringify: (o: object) => string; export declare function assertNotAsync(fn: any, name: string): void; export declare function assertNotPromise(value: TVal, fn: any, name: string): TVal; export declare function hasItemPlan(step: Step & { itemPlan?: ($item: Step) => Step; }): step is Step & { itemPlan: ($item: Step) => Step; }; export declare function exportNameHint(obj: any, nameHint: string): void; export declare function isTuple(t: any | T): t is T; /** * Turns an array of keys into a digest, avoiding conflicts. * Symbols are treated as equivalent. (Theoretically faster * than JSON.stringify().) */ export declare function digestKeys(keys: ReadonlyArray): string; /** * If the directive has the argument `argName`, return a step representing that * arguments value, whether that be a step representing the relevant variable * or a constant step representing the hardcoded value in the document. * * @remarks NOT SUITABLE FOR USAGE WITH LISTS OR OBJECTS! Does not evaluate * internal variable usages e.g. `[1, $b, 3]` */ export declare function directiveArgument(operationPlan: OperationPlan, directive: DirectiveNode, argName: string, expectedKind: graphql.Kind.INT | graphql.Kind.FLOAT | graphql.Kind.BOOLEAN | graphql.Kind.STRING): Step | undefined; export declare function stableStringSort(a: string, z: string): 0 | 1 | -1; /** * Sorts tuples by a string sort of their first entry - useful for * `Object.fromEntries(Object.entries(...).sort(stableStringSortFirstTupleEntry))` */ export declare function stableStringSortFirstTupleEntry(a: readonly [string, ...any[]], z: readonly [string, ...any[]]): 0 | 1 | -1; export declare const sleep: (ms: number) => Promise; /** * Returns a new version of `iterable` that calls `callback()` on termination, * **even if `next()` is never called**. * * @experimental */ export declare function asyncIteratorWithCleanup(iterable: AsyncIterable, callback: (error?: unknown) => void): AsyncGenerator & AsyncIteratorObject; export declare function terminateIterable(iterable: readonly any[] | Iterable | AsyncIterable): void; export declare const GraphQLSpecifiedErrorBehaviors: readonly ["PROPAGATE", "NULL", "HALT"]; export declare function markSyncAndSafe any) & { displayName?: string; }>(fn: T, displayName?: string): T; export {}; //# sourceMappingURL=utils.d.ts.map