diff --git a/types/relay-compiler/index.d.ts b/types/relay-compiler/index.d.ts new file mode 100644 index 0000000000..c0093092aa --- /dev/null +++ b/types/relay-compiler/index.d.ts @@ -0,0 +1,17 @@ +// Type definitions for relay-compiler 5.0 +// Project: https://relay.dev +// Definitions by: n1ru4l +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 3.0 + +import { GraphQLCompilerContext } from './lib/GraphQLCompilerContext'; +import * as ASTConvert from './lib/ASTConvert'; + +import * as Parser from './lib/RelayParser'; +import * as Printer from './lib/GraphQLIRPrinter'; +import ConsoleReporter = require('./lib/GraphQLConsoleReporter'); +import MultiReporter = require('./lib/GraphQLMultiReporter'); + +declare var transformASTSchema: typeof ASTConvert.transformASTSchema; + +export { GraphQLCompilerContext, ASTConvert, transformASTSchema, Parser, Printer, ConsoleReporter, MultiReporter }; diff --git a/types/relay-compiler/lib/ASTConvert.d.ts b/types/relay-compiler/lib/ASTConvert.d.ts new file mode 100644 index 0000000000..3c99db2c71 --- /dev/null +++ b/types/relay-compiler/lib/ASTConvert.d.ts @@ -0,0 +1,5 @@ +import { GraphQLSchema } from 'graphql'; +export function transformASTSchema( + schema: GraphQLSchema, + transforms: string[], +): GraphQLSchema; diff --git a/types/relay-compiler/lib/FlattenTransform.d.ts b/types/relay-compiler/lib/FlattenTransform.d.ts new file mode 100644 index 0000000000..d74853f39f --- /dev/null +++ b/types/relay-compiler/lib/FlattenTransform.d.ts @@ -0,0 +1,9 @@ +import { GraphQLCompilerContext } from '../'; + +export interface FlattenOptions { + flattenAbstractTypes?: boolean; +} + +export function transformWithOptions( + options: FlattenOptions, +): (context: GraphQLCompilerContext) => GraphQLCompilerContext; diff --git a/types/relay-compiler/lib/GraphQLCompilerContext.d.ts b/types/relay-compiler/lib/GraphQLCompilerContext.d.ts new file mode 100644 index 0000000000..1b41950d9e --- /dev/null +++ b/types/relay-compiler/lib/GraphQLCompilerContext.d.ts @@ -0,0 +1,38 @@ +import { GraphQLSchema } from 'graphql'; +import { Root, Fragment, SplitOperation, Location } from './GraphQLIR'; +import { GraphQLReporter } from './GraphQLReporter'; + +export type IRTransform = ( + context: GraphQLCompilerContext, +) => GraphQLCompilerContext; +export type IRValidation = (contect: GraphQLCompilerContext) => void; + +export type CompilerContextDocument = Fragment | Root | SplitOperation; + +export class GraphQLCompilerContext { + constructor(serverSchema: GraphQLSchema, clientSchema?: GraphQLSchema); + documents(): ReadonlyArray; + forEachDocument(fn: (doc: CompilerContextDocument) => void): void; + replace(node: CompilerContextDocument): GraphQLCompilerContext; + add(node: CompilerContextDocument): GraphQLCompilerContext; + addAll(nodes: ReadonlyArray): GraphQLCompilerContext; + applyTransforms( + transforms: ReadonlyArray, + reporter?: GraphQLReporter, + ): GraphQLCompilerContext; + applyTransform( + transform: IRTransform, + reporter?: GraphQLReporter, + ): GraphQLCompilerContext; + applyValidations( + validations: ReadonlyArray, + reporter?: GraphQLReporter, + ): void; + get(name: string): CompilerContextDocument | undefined; + getFragment(name: string, referencedFrom?: Location): Fragment; + getRoot(name: string): Root; + remove(name: string): GraphQLCompilerContext; + withMutations( + fn: (context: GraphQLCompilerContext) => GraphQLCompilerContext, + ): GraphQLCompilerContext; +} diff --git a/types/relay-compiler/lib/GraphQLConsoleReporter.d.ts b/types/relay-compiler/lib/GraphQLConsoleReporter.d.ts new file mode 100644 index 0000000000..5dcecd85fd --- /dev/null +++ b/types/relay-compiler/lib/GraphQLConsoleReporter.d.ts @@ -0,0 +1,9 @@ +import { GraphQLReporter } from './GraphQLReporter'; + +declare class GraphQLMultiReporter implements GraphQLReporter { + reportMessage(message: string): void; + reportTime(name: string, ms: number): void; + reportError(caughtLocation: string, error: Error): void; +} + +export = GraphQLMultiReporter; diff --git a/types/relay-compiler/lib/GraphQLIR.d.ts b/types/relay-compiler/lib/GraphQLIR.d.ts new file mode 100644 index 0000000000..96c9e4c479 --- /dev/null +++ b/types/relay-compiler/lib/GraphQLIR.d.ts @@ -0,0 +1,334 @@ +import { + Source, + GraphQLInputType, + GraphQLOutputType, + GraphQLCompositeType, + GraphQLLeafType, + GraphQLList, + GraphQLNonNull, +} from 'graphql'; + +export type Metadata = { [key: string]: unknown } | undefined; + +export interface SourceLocation { + kind: 'Source'; + start: number; + end: number; + source: Source; +} + +export interface GeneratedLocation { + kind: 'Generated'; +} + +export interface DerivedLocation { + kind: 'Derived'; + source: Location; +} +export interface UnknownLocation { + kind: 'Unknown'; +} + +export type Location = SourceLocation | GeneratedLocation | DerivedLocation | UnknownLocation; + +export interface Argument { + kind: 'Argument'; + loc: Location; + metadata: Metadata; + name: string; + type?: GraphQLInputType; + value: ArgumentValue; +} + +export type ArgumentDefinition = LocalArgumentDefinition | RootArgumentDefinition; + +export type ArgumentValue = ListValue | Literal | ObjectValue | Variable; + +export interface Condition { + condition: Literal | Variable; + kind: 'Condition'; + loc: Location; + metadata: Metadata; + passingValue: boolean; + selections: ReadonlyArray; +} + +export interface Directive { + args: ReadonlyArray; + kind: 'Directive'; + loc: Location; + metadata: Metadata; + name: string; +} + +export type Field = LinkedField | ScalarField | ConnectionField; + +export interface Fragment { + argumentDefinitions: ReadonlyArray; + directives: ReadonlyArray; + kind: 'Fragment'; + loc: Location; + metadata: Metadata; + name: string; + selections: ReadonlyArray; + type: GraphQLCompositeType; +} + +export interface FragmentSpread { + args: ReadonlyArray; + directives: ReadonlyArray; + kind: 'FragmentSpread'; + loc: Location; + metadata: Metadata; + name: string; +} + +export interface Defer { + kind: 'Defer'; + loc: Location; + metadata: Metadata; + selections: ReadonlyArray; + label: string; + if: ArgumentValue | null; +} + +export interface Stream { + kind: 'Stream'; + loc: Location; + metadata: Metadata; + selections: ReadonlyArray; + label: string; + if: ArgumentValue | null; + initialCount: ArgumentValue; +} + +export interface InlineDataFragmentSpread { + kind: 'InlineDataFragmentSpread'; + loc: Location; + metadata: Metadata; + name: string; + selections: ReadonlyArray; +} + +export type IR = + | Argument + | ClientExtension + | Condition + | Defer + | ConnectionField + | Directive + | Fragment + | FragmentSpread + | InlineFragment + | LinkedField + | ListValue + | Literal + | LocalArgumentDefinition + | ModuleImport + | ObjectFieldValue + | ObjectValue + | Request + | Root + | RootArgumentDefinition + | ScalarField + | SplitOperation + | Stream + | InlineDataFragmentSpread + | Variable; + +export interface RootArgumentDefinition { + kind: 'RootArgumentDefinition'; + loc: Location; + metadata: Metadata; + name: string; + type: GraphQLInputType; +} + +export interface InlineFragment { + directives: ReadonlyArray; + kind: 'InlineFragment'; + loc: Location; + metadata: Metadata; + selections: ReadonlyArray; + typeCondition: GraphQLCompositeType; +} + +export interface Handle { + name: string; + key: string; + dynamicKey: Variable | null; + filters?: Readonly; +} + +export interface ClientExtension { + kind: 'ClientExtension'; + loc: Location; + metadata: Metadata; + selections: ReadonlyArray; +} + +export interface ConnectionField { + alias: string; + args: ReadonlyArray; + directives: ReadonlyArray; + kind: 'ConnectionField'; + label: string; + loc: Location; + metadata: Metadata; + name: string; + resolver: string; + selections: ReadonlyArray; + type: GraphQLOutputType; +} + +export interface LinkedField { + alias: string; + args: ReadonlyArray; + directives: ReadonlyArray; + handles?: ReadonlyArray; + kind: 'LinkedField'; + loc: Location; + metadata: Metadata; + name: string; + selections: ReadonlyArray; + type: GraphQLOutputType; +} + +export interface ListValue { + kind: 'ListValue'; + items: ReadonlyArray; + loc: Location; + metadata: Metadata; +} + +export interface Literal { + kind: 'Literal'; + loc: Location; + metadata: Metadata; + value: unknown; +} + +export interface LocalArgumentDefinition { + defaultValue: unknown; + kind: 'LocalArgumentDefinition'; + loc: Location; + metadata: Metadata; + name: string; + type: GraphQLInputType; +} + +export interface ModuleImport { + kind: 'ModuleImport'; + loc: Location; + documentName: string; + module: string; + id: string; + name: string; + selections: ReadonlyArray; +} + +export type Node = + | ClientExtension + | Condition + | Defer + | ConnectionField + | Fragment + | InlineDataFragmentSpread + | InlineFragment + | LinkedField + | ModuleImport + | Root + | SplitOperation + | Stream; + +export interface ObjectFieldValue { + kind: 'ObjectFieldValue'; + loc: Location; + metadata: Metadata; + name: string; + value: ArgumentValue; +} + +export interface ObjectValue { + kind: 'ObjectValue'; + fields: ReadonlyArray; + loc: Location; + metadata: Metadata; +} + +export interface Request { + kind: 'Request'; + fragment: Fragment; + id?: string; + loc: Location; + metadata: Metadata; + name: string; + root: Root; + text?: string; +} + +export interface Root { + argumentDefinitions: Readonly; + directives: Readonly; + kind: 'Root'; + loc: Location; + metadata: Metadata; + name: string; + operation: 'query' | 'mutation' | 'subscription'; + selections: Readonly; + type: GraphQLCompositeType; +} + +// workaround for circular reference +// tslint:disable-next-line:no-empty-interface +export interface ScalarFieldTypeGraphQLList extends GraphQLList {} + +export type ScalarFieldType = + | GraphQLLeafType + | ScalarFieldTypeGraphQLList + | GraphQLNonNull; + +export interface ScalarField { + alias: string; + args: ReadonlyArray; + directives: ReadonlyArray; + handles?: ReadonlyArray; + kind: 'ScalarField'; + loc: Location; + metadata: Metadata; + name: string; + type: ScalarFieldType; +} + +export type Selection = + | ClientExtension + | Condition + | Defer + | ConnectionField + | FragmentSpread + | InlineFragment + | LinkedField + | ModuleImport + | ScalarField + | InlineDataFragmentSpread + | Stream; + +export type Definition = Fragment | Root | SplitOperation; +export type GeneratedDefinition = Fragment | Request | SplitOperation; + +export interface SplitOperation { + kind: 'SplitOperation'; + name: string; + selections: ReadonlyArray; + loc: Location; + metadata: Metadata; + type: GraphQLCompositeType; +} + +export interface Variable { + kind: 'Variable'; + loc: Location; + metadata: Metadata; + variableName: string; + type?: GraphQLInputType; +} diff --git a/types/relay-compiler/lib/GraphQLIRPrinter.d.ts b/types/relay-compiler/lib/GraphQLIRPrinter.d.ts new file mode 100644 index 0000000000..a6e09d25ad --- /dev/null +++ b/types/relay-compiler/lib/GraphQLIRPrinter.d.ts @@ -0,0 +1,2 @@ +import { CompilerContextDocument } from './GraphQLCompilerContext'; +export function print(node: CompilerContextDocument): string; diff --git a/types/relay-compiler/lib/GraphQLMultiReporter.d.ts b/types/relay-compiler/lib/GraphQLMultiReporter.d.ts new file mode 100644 index 0000000000..5dcecd85fd --- /dev/null +++ b/types/relay-compiler/lib/GraphQLMultiReporter.d.ts @@ -0,0 +1,9 @@ +import { GraphQLReporter } from './GraphQLReporter'; + +declare class GraphQLMultiReporter implements GraphQLReporter { + reportMessage(message: string): void; + reportTime(name: string, ms: number): void; + reportError(caughtLocation: string, error: Error): void; +} + +export = GraphQLMultiReporter; diff --git a/types/relay-compiler/lib/GraphQLReporter.d.ts b/types/relay-compiler/lib/GraphQLReporter.d.ts new file mode 100644 index 0000000000..845eb521d4 --- /dev/null +++ b/types/relay-compiler/lib/GraphQLReporter.d.ts @@ -0,0 +1,5 @@ +export interface GraphQLReporter { + reportMessage(message: string): void; + reportTime(name: string, ms: number): void; + reportError(caughtLocation: string, error: Error): void; +} diff --git a/types/relay-compiler/lib/InlineFragmentsTransform.d.ts b/types/relay-compiler/lib/InlineFragmentsTransform.d.ts new file mode 100644 index 0000000000..f7fe04302c --- /dev/null +++ b/types/relay-compiler/lib/InlineFragmentsTransform.d.ts @@ -0,0 +1,5 @@ +import { GraphQLCompilerContext } from '../'; + +export function transform( + context: GraphQLCompilerContext, +): GraphQLCompilerContext; diff --git a/types/relay-compiler/lib/RelayApplyFragmentArgumentTransform.d.ts b/types/relay-compiler/lib/RelayApplyFragmentArgumentTransform.d.ts new file mode 100644 index 0000000000..f7fe04302c --- /dev/null +++ b/types/relay-compiler/lib/RelayApplyFragmentArgumentTransform.d.ts @@ -0,0 +1,5 @@ +import { GraphQLCompilerContext } from '../'; + +export function transform( + context: GraphQLCompilerContext, +): GraphQLCompilerContext; diff --git a/types/relay-compiler/lib/RelayParser.d.ts b/types/relay-compiler/lib/RelayParser.d.ts new file mode 100644 index 0000000000..281d78fcd9 --- /dev/null +++ b/types/relay-compiler/lib/RelayParser.d.ts @@ -0,0 +1,13 @@ +import { GraphQLSchema, DefinitionNode } from 'graphql'; +import { Root, Fragment } from './GraphQLIR'; + +export function parse( + schema: GraphQLSchema, + text: string, + filename?: string, +): ReadonlyArray; + +export function transform( + schema: GraphQLSchema, + documents: DefinitionNode[], +): ReadonlyArray; diff --git a/types/relay-compiler/lib/SkipRedundantNodesTransform.d.ts b/types/relay-compiler/lib/SkipRedundantNodesTransform.d.ts new file mode 100644 index 0000000000..f7fe04302c --- /dev/null +++ b/types/relay-compiler/lib/SkipRedundantNodesTransform.d.ts @@ -0,0 +1,5 @@ +import { GraphQLCompilerContext } from '../'; + +export function transform( + context: GraphQLCompilerContext, +): GraphQLCompilerContext; diff --git a/types/relay-compiler/relay-compiler-tests.ts b/types/relay-compiler/relay-compiler-tests.ts new file mode 100644 index 0000000000..2b749ebd0d --- /dev/null +++ b/types/relay-compiler/relay-compiler-tests.ts @@ -0,0 +1,35 @@ +import { + GraphQLCompilerContext, + transformASTSchema, + Parser as RelayParser, + Printer as GraphQLIRPrinter, +} from 'relay-compiler'; + +import * as InlineFragmentsTransform from 'relay-compiler/lib/InlineFragmentsTransform'; +import * as SkipRedundantNodesTransform from 'relay-compiler/lib/SkipRedundantNodesTransform'; +import * as RelayApplyFragmentArgumentTransform from 'relay-compiler/lib/RelayApplyFragmentArgumentTransform'; +import * as FlattenTransform from 'relay-compiler/lib/FlattenTransform'; + +import { GraphQLSchema, DefinitionNode } from 'graphql'; + +const documentAsts: DefinitionNode[] = []; +const schema: GraphQLSchema = (undefined as any) as GraphQLSchema; + +const adjustedSchema = transformASTSchema(schema, [ + /* GraphQL */ ` + directive @connection(key: String!) on FIELD + directive @client on FIELD + `, +]); + +const relayDocuments = RelayParser.transform(adjustedSchema, documentAsts); +const queryCompilerContext = new GraphQLCompilerContext(adjustedSchema) + .addAll(relayDocuments) + .applyTransforms([ + RelayApplyFragmentArgumentTransform.transform, + InlineFragmentsTransform.transform, + FlattenTransform.transformWithOptions({ flattenAbstractTypes: false }), + SkipRedundantNodesTransform.transform, + ]); + +queryCompilerContext.documents().map(doc => GraphQLIRPrinter.print(doc)); diff --git a/types/relay-compiler/tsconfig.json b/types/relay-compiler/tsconfig.json new file mode 100644 index 0000000000..3ecfab82fe --- /dev/null +++ b/types/relay-compiler/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es6", + "esnext.asynciterable" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictFunctionTypes": true, + "strictNullChecks": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "relay-compiler-tests.ts", + "lib/FlattenTransform.d.ts", + "lib/InlineFragmentsTransform.d.ts", + "lib/RelayApplyFragmentArgumentTransform.d.ts", + "lib/SkipRedundantNodesTransform.d.ts" + ] +} diff --git a/types/relay-compiler/tslint.json b/types/relay-compiler/tslint.json new file mode 100644 index 0000000000..3db14f85ea --- /dev/null +++ b/types/relay-compiler/tslint.json @@ -0,0 +1 @@ +{ "extends": "dtslint/dt.json" }