Skip to content

Commit

Permalink
Add TS typings (#2102)
Browse files Browse the repository at this point in the history
  • Loading branch information
IvanGoncharov authored Aug 21, 2019
1 parent 85ae274 commit d1391ee
Show file tree
Hide file tree
Showing 94 changed files with 5,715 additions and 15 deletions.
10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,16 @@
"node": ">= 6.x"
},
"scripts": {
"test": "npm run prettier:check && npm run lint && npm run check && npm run testonly",
"test:ci": "yarn check --integrity && npm run prettier:check && npm run lint -- --no-cache && npm run check && npm run testonly:cover && npm run build",
"test": "npm run prettier:check && npm run lint && npm run check && npm run testonly && npm run check:ts",
"test:ci": "yarn check --integrity && npm run prettier:check && npm run lint -- --no-cache && npm run check && npm run testonly:cover && npm run check:ts && npm run build",
"testonly": "mocha --full-trace src/**/__tests__/**/*-test.js",
"testonly:cover": "nyc npm run testonly",
"lint": "eslint --cache --report-unused-disable-directives src resources",
"benchmark": "node --noconcurrent_sweeping --expose-gc --predictable ./resources/benchmark.js",
"prettier": "prettier --ignore-path .gitignore --write --list-different \"**/*.{js,md,json,yml}\"",
"prettier:check": "prettier --ignore-path .gitignore --check \"**/*.{js,md,json,yml}\"",
"prettier": "prettier --ignore-path .gitignore --write --list-different \"**/*.{js,ts,md,json,yml}\"",
"prettier:check": "prettier --ignore-path .gitignore --check \"**/*.{js,ts,md,json,yml}\"",
"check": "flow check",
"check:ts": "dtslint tstypes",
"check:cover": "node resources/check-cover.js && nyc report --nycrc-path .nycflowrc.yml",
"build": "node resources/build.js",
"changelog": "node resources/gen-changelog.js",
Expand All @@ -50,6 +51,7 @@
"@babel/register": "7.5.5",
"babel-eslint": "10.0.2",
"chai": "4.2.0",
"dtslint": "^0.8.0",
"eslint": "5.16.0",
"eslint-plugin-flowtype": "3.12.1",
"flow-bin": "0.105.2",
Expand Down
10 changes: 10 additions & 0 deletions resources/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ if (require.main === module) {
}
}

const tsFiles = readdirRecursive('./tstypes', { ignoreDir: /^__.*__$/ });
for (const filepath of tsFiles) {
if (filepath.endsWith('.d.ts')) {
const srcPath = path.join('./tstypes', filepath);
const destPath = path.join('./dist', filepath);

copyFile(srcPath, destPath);
}
}

const packageJSON = buildPackageJSON();
assert(
packageJSON.version === require('../dist/version').version,
Expand Down
78 changes: 78 additions & 0 deletions tstypes/error/GraphQLError.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import Maybe from '../tsutils/Maybe';
import { getLocation } from '../language';
import { ASTNode } from '../language/ast';
import { Source } from '../language/source';
import { SourceLocation } from '../language/location';

/**
* A GraphQLError describes an Error found during the parse, validate, or
* execute phases of performing a GraphQL operation. In addition to a message
* and stack trace, it also includes information about the locations in a
* GraphQL document and/or execution result that correspond to the Error.
*/
export class GraphQLError extends Error {
/**
* A message describing the Error for debugging purposes.
*
* Enumerable, and appears in the result of JSON.stringify().
*
* Note: should be treated as readonly, despite invariant usage.
*/
message: string;

/**
* An array of { line, column } locations within the source GraphQL document
* which correspond to this error.
*
* Errors during validation often contain multiple locations, for example to
* point out two things with the same name. Errors during execution include a
* single location, the field which produced the error.
*
* Enumerable, and appears in the result of JSON.stringify().
*/
readonly locations: ReadonlyArray<SourceLocation> | undefined;

/**
* An array describing the JSON-path into the execution response which
* corresponds to this error. Only included for errors during execution.
*
* Enumerable, and appears in the result of JSON.stringify().
*/
readonly path: ReadonlyArray<string | number> | undefined;

/**
* An array of GraphQL AST Nodes corresponding to this error.
*/
readonly nodes: ReadonlyArray<ASTNode> | undefined;

/**
* The source GraphQL document corresponding to this error.
*/
readonly source: Source | undefined;

/**
* An array of character offsets within the source GraphQL document
* which correspond to this error.
*/
readonly positions: ReadonlyArray<number> | undefined;

/**
* The original error thrown from a field resolver during execution.
*/
readonly originalError: Maybe<Error>;

/**
* Extension fields to add to the formatted error.
*/
readonly extensions: { [key: string]: any } | undefined;

constructor(
message: string,
nodes?: ReadonlyArray<ASTNode> | ASTNode | undefined,
source?: Maybe<Source>,
positions?: Maybe<ReadonlyArray<number>>,
path?: Maybe<ReadonlyArray<string | number>>,
originalError?: Maybe<Error>,
extensions?: Maybe<{ [key: string]: any }>,
);
}
39 changes: 39 additions & 0 deletions tstypes/error/formatError.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { GraphQLError } from './GraphQLError';
import { SourceLocation } from '../language/location';

/**
* Given a GraphQLError, format it according to the rules described by the
* Response Format, Errors section of the GraphQL Specification.
*/
export function formatError(error: GraphQLError): GraphQLFormattedError;

/**
* @see https://github.com/graphql/graphql-spec/blob/master/spec/Section%207%20--%20Response.md#errors
*/
export interface GraphQLFormattedError<
TExtensions extends Record<string, any> = Record<string, any>
> {
/**
* A short, human-readable summary of the problem that **SHOULD NOT** change
* from occurrence to occurrence of the problem, except for purposes of
* localization.
*/
readonly message: string;
/**
* If an error can be associated to a particular point in the requested
* GraphQL document, it should contain a list of locations.
*/
readonly locations?: ReadonlyArray<SourceLocation>;
/**
* If an error can be associated to a particular field in the GraphQL result,
* it _must_ contain an entry with the key `path` that details the path of
* the response field which experienced the error. This allows clients to
* identify whether a null result is intentional or caused by a runtime error.
*/
readonly path?: ReadonlyArray<string | number>;
/**
* Reserved for implementors to extend the protocol however they see fit,
* and hence there are no additional restrictions on its contents.
*/
readonly extensions?: TExtensions;
}
5 changes: 5 additions & 0 deletions tstypes/error/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export { GraphQLError } from './GraphQLError';
export { syntaxError } from './syntaxError';
export { locatedError } from './locatedError';
export { printError } from './printError';
export { formatError, GraphQLFormattedError } from './formatError';
13 changes: 13 additions & 0 deletions tstypes/error/locatedError.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { GraphQLError } from './GraphQLError';
import { ASTNode } from '../language/ast';

/**
* Given an arbitrary Error, presumably thrown while attempting to execute a
* GraphQL operation, produce a new GraphQLError aware of the location in the
* document responsible for the original Error.
*/
export function locatedError(
originalError: Error | GraphQLError,
nodes: ReadonlyArray<ASTNode>,
path: ReadonlyArray<string | number>,
): GraphQLError;
7 changes: 7 additions & 0 deletions tstypes/error/printError.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { GraphQLError } from './GraphQLError';

/**
* Prints a GraphQLError to a string, representing useful location information
* about the error's position in the source.
*/
export function printError(error: GraphQLError): string;
12 changes: 12 additions & 0 deletions tstypes/error/syntaxError.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Source } from '../language/source';
import { GraphQLError } from './GraphQLError';

/**
* Produces a GraphQLError representing a syntax error, containing useful
* descriptive information about the syntax error's position in the source.
*/
export function syntaxError(
source: Source,
position: number,
description: string,
): GraphQLError;
189 changes: 189 additions & 0 deletions tstypes/execution/execute.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import Maybe from '../tsutils/Maybe';
import { GraphQLError, locatedError } from '../error';
import { GraphQLSchema } from '../type/schema';
import {
GraphQLField,
GraphQLFieldResolver,
ResponsePath,
GraphQLObjectType,
GraphQLResolveInfo,
} from '../type/definition';
import {
DirectiveNode,
DocumentNode,
OperationDefinitionNode,
SelectionSetNode,
FieldNode,
InlineFragmentNode,
FragmentDefinitionNode,
} from '../language/ast';
import { PromiseOrValue } from '../jsutils/PromiseOrValue';

/**
* Data that must be available at all points during query execution.
*
* Namely, schema of the type system that is currently executing,
* and the fragments defined in the query document
*/
export interface ExecutionContext {
schema: GraphQLSchema;
fragments: { [key: string]: FragmentDefinitionNode };
rootValue: any;
contextValue: any;
operation: OperationDefinitionNode;
variableValues: { [key: string]: any };
fieldResolver: GraphQLFieldResolver<any, any>;
errors: GraphQLError[];
}

export interface ExecutionResultDataDefault {
[key: string]: any;
}

/**
* The result of GraphQL execution.
*
* - `errors` is included when any errors occurred as a non-empty array.
* - `data` is the result of a successful execution of the query.
*/
export interface ExecutionResult<TData = ExecutionResultDataDefault> {
errors?: ReadonlyArray<GraphQLError>;
data?: TData;
}

export type ExecutionArgs = {
schema: GraphQLSchema;
document: DocumentNode;
rootValue?: any;
contextValue?: any;
variableValues?: Maybe<{ [key: string]: any }>;
operationName?: Maybe<string>;
fieldResolver?: Maybe<GraphQLFieldResolver<any, any>>;
};

/**
* Implements the "Evaluating requests" section of the GraphQL specification.
*
* Returns either a synchronous ExecutionResult (if all encountered resolvers
* are synchronous), or a Promise of an ExecutionResult that will eventually be
* resolved and never rejected.
*
* If the arguments to this function do not result in a legal execution context,
* a GraphQLError will be thrown immediately explaining the invalid input.
*
* Accepts either an object with named arguments, or individual arguments.
*/
export function execute<TData = ExecutionResultDataDefault>(
args: ExecutionArgs,
): PromiseOrValue<ExecutionResult<TData>>;
export function execute<TData = ExecutionResultDataDefault>(
schema: GraphQLSchema,
document: DocumentNode,
rootValue?: any,
contextValue?: any,
variableValues?: Maybe<{ [key: string]: any }>,
operationName?: Maybe<string>,
fieldResolver?: Maybe<GraphQLFieldResolver<any, any>>,
): PromiseOrValue<ExecutionResult<TData>>;

/**
* Given a ResponsePath (found in the `path` entry in the information provided
* as the last argument to a field resolver), return an Array of the path keys.
*/
export function responsePathAsArray(
path: ResponsePath,
): ReadonlyArray<string | number>;

/**
* Given a ResponsePath and a key, return a new ResponsePath containing the
* new key.
*/
export function addPath(
prev: ResponsePath | undefined,
key: string | number,
): { prev: ResponsePath | undefined; key: string | number };

/**
* Essential assertions before executing to provide developer feedback for
* improper use of the GraphQL library.
*/
export function assertValidExecutionArguments(
schema: GraphQLSchema,
document: DocumentNode,
rawVariableValues: Maybe<{ [key: string]: any }>,
): void;

/**
* Constructs a ExecutionContext object from the arguments passed to
* execute, which we will pass throughout the other execution methods.
*
* Throws a GraphQLError if a valid execution context cannot be created.
*/
export function buildExecutionContext(
schema: GraphQLSchema,
document: DocumentNode,
rootValue: any,
contextValue: any,
rawVariableValues: Maybe<{ [key: string]: any }>,
operationName: Maybe<string>,
fieldResolver: Maybe<GraphQLFieldResolver<any, any>>,
): ReadonlyArray<GraphQLError> | ExecutionContext;

/**
* Given a selectionSet, adds all of the fields in that selection to
* the passed in map of fields, and returns it at the end.
*
* CollectFields requires the "runtime type" of an object. For a field which
* returns an Interface or Union type, the "runtime type" will be the actual
* Object type returned by that field.
*/
export function collectFields(
exeContext: ExecutionContext,
runtimeType: GraphQLObjectType,
selectionSet: SelectionSetNode,
fields: { [key: string]: Array<FieldNode> },
visitedFragmentNames: { [key: string]: boolean },
): { [key: string]: Array<FieldNode> };

export function buildResolveInfo(
exeContext: ExecutionContext,
fieldDef: GraphQLField<any, any>,
fieldNodes: ReadonlyArray<FieldNode>,
parentType: GraphQLObjectType,
path: ResponsePath,
): GraphQLResolveInfo;

// Isolates the "ReturnOrAbrupt" behavior to not de-opt the `resolveField`
// function. Returns the result of resolveFn or the abrupt-return Error object.
export function resolveFieldValueOrError<TSource>(
exeContext: ExecutionContext,
fieldDef: GraphQLField<TSource, any>,
fieldNodes: ReadonlyArray<FieldNode>,
resolveFn: GraphQLFieldResolver<TSource, any>,
source: TSource,
info: GraphQLResolveInfo,
): Error | any;

/**
* If a resolve function is not given, then a default resolve behavior is used
* which takes the property of the source object of the same name as the field
* and returns it as the result, or if it's a function, returns the result
* of calling that function while passing along args and context.
*/
export const defaultFieldResolver: GraphQLFieldResolver<any, any>;

/**
* This method looks up the field on the given type defintion.
* It has special casing for the two introspection fields, __schema
* and __typename. __typename is special because it can always be
* queried as a field, even in situations where no other fields
* are allowed, like on a Union. __schema could get automatically
* added to the query type, but that would require mutating type
* definitions, which would cause issues.
*/
export function getFieldDef(
schema: GraphQLSchema,
parentType: GraphQLObjectType,
fieldName: string,
): Maybe<GraphQLField<any, any>>;
Loading

0 comments on commit d1391ee

Please sign in to comment.