Compare commits

...

9 Commits

Author SHA1 Message Date
Sam Burba 9e5c27c509
docs: Fix readme converter link (#1108) 2023-03-16 11:04:52 -04:00
Jan Piotrowski 601c2f03f4
fix(prisma): Replace outdated note (#1153)Co-authored-by: Andrew Carlson <5479270+andrewicarlson@users.noreply.github.com>
* fix(prisma): Remove outdated note

* Update 010-overview.mdx

---------

Co-authored-by: Andrew Carlson <5479270+andrewicarlson@users.noreply.github.com>
2023-03-16 11:04:26 -04:00
Andrew Carlson 4e085dc7b2
Feature/update docs (#1136)
* Replaced Prisma reference

* Updated copyright info
2023-02-02 10:48:58 -06:00
Alex Kunin 1e6b9212d3
chore: remove irrelevant paragraph in docs (#1128)
Resolver shorthands were removed in v0.18.0, docs need to be updated.
2022-10-31 09:25:32 -04:00
Tim Griesser 4d8e37177b
feat: better esm support, remove top-level node imports (#1112)
* test for esm/esbuild use of nexus

* refactor: add nodeImports, remove top-level references

* Don't minify the esbuild test script

* A bit more explicit of a check on the process being node
2022-07-02 16:08:16 -04:00
Tim Griesser eec4b91091
feat: add sourceType option to fieldDefinition (#1106)
* feat: add sourceType option to fieldDefinition

* add additional configurability for field-level sourceType
2022-06-28 13:21:58 -04:00
Tim Griesser 8e65081539
fix: remove hasSDLDirectives internal state (#1091)
* fix: remove hasSDLDirectives from schema construction
2022-05-16 00:12:23 -04:00
Tim Griesser 7ee48c4f2c
fix: add missing as const on the RequestDirectiveLocation (#1090) 2022-05-15 22:48:26 -04:00
Tim Griesser e9dc7e0c4a chore: Fix codecov 2022-05-15 16:59:29 -04:00
28 changed files with 419 additions and 149 deletions

View File

@ -38,7 +38,7 @@ jobs:
run: yarn -s test:ci run: yarn -s test:ci
- name: Upload coverage to Codecov - name: Upload coverage to Codecov
uses: codecov/codecov-action@v1 uses: codecov/codecov-action@v1
if: matrix.os == 'ubuntu-latest' && matrix.node-version == '10.x' if: matrix.os == 'ubuntu-latest' && matrix.node-version == '14.x'
with: with:
directory: ./coverage directory: ./coverage

View File

@ -38,7 +38,7 @@ jobs:
- name: Test - name: Test
run: yarn -s test:ci run: yarn -s test:ci
- name: Upload coverage to Codecov - name: Upload coverage to Codecov
if: matrix.os == 'ubuntu-latest' && matrix.node-version == '10.x' if: matrix.os == 'ubuntu-latest' && matrix.node-version == '14.x'
uses: codecov/codecov-action@v1 uses: codecov/codecov-action@v1
with: with:
directory: ./coverage directory: ./coverage

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ examples/*/dist
website/static/playground-dist website/static/playground-dist
yarn-error.log yarn-error.log
coverage/* coverage/*
tests/esm/out/

View File

@ -1,4 +1,4 @@
(c) 2018-2019 Tim Griesser (c) 2018-2022 Tim Griesser
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation obtaining a copy of this software and associated documentation

View File

@ -74,4 +74,4 @@ You can find the docs for Nexus [here](http://nexusjs.org/).
## Migrate from SDL ## Migrate from SDL
If you've been following an [SDL-first](https://www.prisma.io/blog/the-problems-of-schema-first-graphql-development-x1mn4cb0tyl3/) approach to build your GraphQL server and want to see what your code looks like when written with GraphQL Nexus, you can use the [**SDL converter**](https://nexus.js.org/converter). If you've been following an [SDL-first](https://www.prisma.io/blog/the-problems-of-schema-first-graphql-development-x1mn4cb0tyl3/) approach to build your GraphQL server and want to see what your code looks like when written with GraphQL Nexus, you can use the [**SDL converter**](https://nexusjs.org/converter).

View File

@ -28,18 +28,3 @@ Each public API is documented below, feel free to open a PR with more examples/c
- [extendType / extendInputType](/api/extend-type) - [extendType / extendInputType](/api/extend-type)
- [mutationField](/api/mutation-field) - [mutationField](/api/mutation-field)
- [queryField](/api/query-field) - [queryField](/api/query-field)
## Resolving: Inline Function
One common idiom in GraphQL is exposing fields that mask or rename the property name on the backing object. GraphQL Nexus makes this simple by allowing a function as the second parameter to any built-in scalar resolver function.
```ts
const User = objectType({
name: 'User',
definition(t) {
t.id('id', o => o.user_id)
t.string('name', o => o.user_name)
t.string('description', o => o.user_description)
},
})
```

View File

@ -6,7 +6,7 @@ title: Overview
This plugin integrates [Prisma](https://www.prisma.io/) into [Nexus](https://nexusjs.org/). It gives you an API to project fields from models defined in your Prisma schema into your GraphQL API. It also gives you an API to build GraphQL root fields that allow your API clients to query and mutate data. This plugin integrates [Prisma](https://www.prisma.io/) into [Nexus](https://nexusjs.org/). It gives you an API to project fields from models defined in your Prisma schema into your GraphQL API. It also gives you an API to build GraphQL root fields that allow your API clients to query and mutate data.
> **Note**: The Prisma team is currently [rewriting](https://github.com/graphql-nexus/nexus-plugin-prisma/issues/1039) the plugin to make it maintainable longterm. **Note**: You may also use [`nexus-prisma`](https://github.com/graphql-nexus/nexus-prisma), a newer API for integrating Nexus and Prisma.
## Installation ## Installation

View File

@ -214,8 +214,7 @@ const Footer = ({ footerProps }: FooterViewProps) => {
} }
</div> </div>
<p className="social-text">Prisma © 2018-2020</p> <p className="social-text">Tim Griesser © 2018-2022</p>
<p>Made with in Berlin</p>
</div> </div>
</SocialWrapper> </SocialWrapper>
</div> </div>

View File

@ -79,6 +79,7 @@
"@types/prettier": "^1.18.3", "@types/prettier": "^1.18.3",
"@typescript-eslint/eslint-plugin": "2.7.0", "@typescript-eslint/eslint-plugin": "2.7.0",
"dripip": "^0.10.0", "dripip": "^0.10.0",
"esbuild": "^0.14.48",
"eslint": "^6.6.0", "eslint": "^6.6.0",
"get-port": "^5.1.1", "get-port": "^5.1.1",
"graphql": "^16.3.0", "graphql": "^16.3.0",

View File

@ -504,9 +504,6 @@ export class SchemaBuilder {
/** All Schema Directives */ /** All Schema Directives */
// private schemaDirectives: GraphQLDirective[] = [] // private schemaDirectives: GraphQLDirective[] = []
/** Whether we have used any custom directives within the schema construction */
private hasSDLDirectives: boolean = false
/** All types that need to be traversed for children types */ /** All types that need to be traversed for children types */
private typesToWalk: TypeToWalk[] = [] private typesToWalk: TypeToWalk[] = []
@ -999,14 +996,14 @@ export class SchemaBuilder {
this.beforeBuildTypes() this.beforeBuildTypes()
this.checkForInterfaceCircularDependencies() this.checkForInterfaceCircularDependencies()
this.buildNexusTypes() this.buildNexusTypes()
return { return {
finalConfig: this.config, finalConfig: this.config,
typeMap: this.finalTypeMap, typeMap: this.finalTypeMap,
schemaExtension: this.schemaExtension!, schemaExtension: this.schemaExtension,
missingTypes: this.missingTypes, missingTypes: this.missingTypes,
onAfterBuildFns: this.onAfterBuildFns, onAfterBuildFns: this.onAfterBuildFns,
customDirectives: this.directivesMap, customDirectives: this.directivesMap,
hasSDLDirectives: this.hasSDLDirectives,
schemaDirectives: this.maybeAddDirectiveUses('SCHEMA', this.config.schemaDirectives), schemaDirectives: this.maybeAddDirectiveUses('SCHEMA', this.config.schemaDirectives),
} }
} }
@ -1200,11 +1197,7 @@ export class SchemaBuilder {
for (const directive of directives) { for (const directive of directives) {
this.addDirective(directive) this.addDirective(directive)
} }
const result = maybeAddDirectiveUses(kind, directives, this.directivesMap) return maybeAddDirectiveUses(kind, directives, this.directivesMap)
if (result) {
this.hasSDLDirectives = true
}
return result
} }
private buildEnumType(config: NexusEnumTypeConfig<any>) { private buildEnumType(config: NexusEnumTypeConfig<any>) {
@ -1901,7 +1894,6 @@ export interface BuildTypes<TypeMapDefs extends Record<string, GraphQLNamedType>
schemaExtension: NexusSchemaExtension schemaExtension: NexusSchemaExtension
onAfterBuildFns: SchemaBuilder['onAfterBuildFns'] onAfterBuildFns: SchemaBuilder['onAfterBuildFns']
customDirectives: Record<string, GraphQLDirective> customDirectives: Record<string, GraphQLDirective>
hasSDLDirectives: boolean
schemaDirectives?: Partial<{ astNode: ASTKindToNode['SchemaDefinition'] }> schemaDirectives?: Partial<{ astNode: ASTKindToNode['SchemaDefinition'] }>
} }

View File

@ -111,8 +111,36 @@ export type CommonOutputFieldConfig<TypeName extends string, FieldName extends s
* directives: [addDirective('ExampleDirective', { arg: true })] * directives: [addDirective('ExampleDirective', { arg: true })]
*/ */
directives?: Directives directives?: Directives
/**
* Defines a typing for the field, overriding the default behavior to default to the scalar,
* and omit the field if a resolver exists. Most useful in situations where we have a resolver
* but we still want the field defined on the output type.
*
* @example
* sourceType: 'string | number'
*/
sourceType?: string | FieldSourceType | NamedFieldSourceType[]
} & NexusGenPluginFieldConfig<TypeName, FieldName> } & NexusGenPluginFieldConfig<TypeName, FieldName>
export interface FieldSourceType {
/**
* String representing the TypeScript type output as the value
*/
type: string
/**
* If true, marks the field as optional `?:`
* @default false
*/
optional?: boolean
}
export interface NamedFieldSourceType extends FieldSourceType {
/**
* Property name in the output TypeScript field
*/
name: string
}
export type CommonInputFieldConfig<TypeName extends string, FieldName extends string> = CommonFieldConfig & { export type CommonInputFieldConfig<TypeName extends string, FieldName extends string> = CommonFieldConfig & {
/** The default value for the field, if any */ /** The default value for the field, if any */
default?: GetGen3<'inputTypes', TypeName, FieldName> default?: GetGen3<'inputTypes', TypeName, FieldName>

View File

@ -27,7 +27,7 @@ export const RequestDirectiveLocation = [
'FRAGMENT_SPREAD', 'FRAGMENT_SPREAD',
'INLINE_FRAGMENT', 'INLINE_FRAGMENT',
'VARIABLE_DEFINITION', 'VARIABLE_DEFINITION',
] ] as const
export const SchemaDirectiveLocation = [ export const SchemaDirectiveLocation = [
/** Type System Definitions */ /** Type System Definitions */

View File

@ -5,13 +5,17 @@ import type { NexusOutputFieldConfig } from './definitions/definitionBlocks'
import type { NexusInputObjectTypeConfig } from './definitions/inputObjectType' import type { NexusInputObjectTypeConfig } from './definitions/inputObjectType'
import type { NexusInterfaceTypeConfig } from './definitions/interfaceType' import type { NexusInterfaceTypeConfig } from './definitions/interfaceType'
import type { NexusObjectTypeConfig } from './definitions/objectType' import type { NexusObjectTypeConfig } from './definitions/objectType'
import type { Directives } from './core' import type { Directives, FieldSourceType, NamedFieldSourceType } from './core'
/** @internal */ /** @internal */
export function hasNexusExtension(val: any): val is any { export function hasNexusExtension(val: any): val is any {
return Boolean(val) return Boolean(val)
} }
export function isNexusFieldExtension(val: any): val is NexusFieldExtension {
return Boolean(val?._type === 'NexusFieldExtension')
}
export type NexusGraphQLNamedType = GraphQLNamedType & { export type NexusGraphQLNamedType = GraphQLNamedType & {
extensions?: { extensions?: {
nexus?: { nexus?: {
@ -24,13 +28,17 @@ export type NexusTypeExtensions = NexusObjectTypeExtension | NexusInterfaceTypeE
/** Container object living on `fieldDefinition.extensions.nexus` */ /** Container object living on `fieldDefinition.extensions.nexus` */
export class NexusFieldExtension<TypeName extends string = any, FieldName extends string = any> { export class NexusFieldExtension<TypeName extends string = any, FieldName extends string = any> {
readonly _type = 'NexusFieldExtension' as const
readonly config: Omit<NexusOutputFieldConfig<TypeName, FieldName>, 'resolve'> readonly config: Omit<NexusOutputFieldConfig<TypeName, FieldName>, 'resolve'>
/** Whether the user has provided a custom "resolve" function, or whether we're using GraphQL's defaultResolver */ /** Whether the user has provided a custom "resolve" function, or whether we're using GraphQL's defaultResolver */
readonly hasDefinedResolver: boolean readonly hasDefinedResolver: boolean
readonly sourceType: string | FieldSourceType | NamedFieldSourceType[] | undefined
constructor(config: NexusOutputFieldConfig<TypeName, FieldName>) { constructor(config: NexusOutputFieldConfig<TypeName, FieldName>) {
const { resolve, ...rest } = config const { resolve, ...rest } = config
this.config = rest this.config = rest
this.hasDefinedResolver = Boolean(resolve && resolve !== defaultFieldResolver) this.hasDefinedResolver = Boolean(resolve && resolve !== defaultFieldResolver)
this.sourceType = rest.sourceType
} }
/** Called when there are modifications on the interface fields */ /** Called when there are modifications on the interface fields */
modify(modifications: Partial<NexusOutputFieldConfig<any, any>>) { modify(modifications: Partial<NexusOutputFieldConfig<any, any>>) {
@ -40,6 +48,7 @@ export class NexusFieldExtension<TypeName extends string = any, FieldName extend
/** Container object living on `inputObjectType.extensions.nexus` */ /** Container object living on `inputObjectType.extensions.nexus` */
export class NexusInputObjectTypeExtension<TypeName extends string = any> { export class NexusInputObjectTypeExtension<TypeName extends string = any> {
readonly _type = 'NexusInputObjectTypeExtension' as const
readonly config: Omit<NexusInputObjectTypeConfig<TypeName>, 'definition'> readonly config: Omit<NexusInputObjectTypeConfig<TypeName>, 'definition'>
constructor(config: NexusInputObjectTypeConfig<TypeName>) { constructor(config: NexusInputObjectTypeConfig<TypeName>) {
const { definition, ...rest } = config const { definition, ...rest } = config
@ -49,6 +58,7 @@ export class NexusInputObjectTypeExtension<TypeName extends string = any> {
/** Container object living on `objectType.extensions.nexus` */ /** Container object living on `objectType.extensions.nexus` */
export class NexusObjectTypeExtension<TypeName extends string = any> { export class NexusObjectTypeExtension<TypeName extends string = any> {
readonly _type = 'NexusObjectTypeExtension' as const
readonly config: Omit<NexusObjectTypeConfig<TypeName>, 'definition' | 'isTypeOf'> readonly config: Omit<NexusObjectTypeConfig<TypeName>, 'definition' | 'isTypeOf'>
constructor(config: NexusObjectTypeConfig<TypeName>) { constructor(config: NexusObjectTypeConfig<TypeName>) {
const { definition, ...rest } = config const { definition, ...rest } = config
@ -58,6 +68,7 @@ export class NexusObjectTypeExtension<TypeName extends string = any> {
/** Container object living on `interfaceType.extensions.nexus` */ /** Container object living on `interfaceType.extensions.nexus` */
export class NexusInterfaceTypeExtension<TypeName extends string = any> { export class NexusInterfaceTypeExtension<TypeName extends string = any> {
readonly _type = 'NexusInterfaceTypeExtension' as const
readonly config: Omit<NexusInterfaceTypeConfig<TypeName>, 'definition' | 'resolveType'> readonly config: Omit<NexusInterfaceTypeConfig<TypeName>, 'definition' | 'resolveType'>
constructor(config: NexusInterfaceTypeConfig<TypeName>) { constructor(config: NexusInterfaceTypeConfig<TypeName>) {
const { definition, ...rest } = config const { definition, ...rest } = config

View File

@ -19,14 +19,14 @@ import { assertNoMissingTypes, objValues, runAbstractTypeRuntimeChecks } from '.
* Requires at least one type be named "Query", which will be used as the root query type. * Requires at least one type be named "Query", which will be used as the root query type.
*/ */
export function makeSchema(config: SchemaConfig): NexusGraphQLSchema { export function makeSchema(config: SchemaConfig): NexusGraphQLSchema {
const { schema, missingTypes, finalConfig, hasSDLDirectives } = makeSchemaInternal(config) const { schema, missingTypes, finalConfig } = makeSchemaInternal(config)
const typegenConfig = resolveTypegenConfig(finalConfig) const typegenConfig = resolveTypegenConfig(finalConfig)
const sdl = typegenConfig.outputs.schema const sdl = typegenConfig.outputs.schema
const typegen = typegenConfig.outputs.typegen const typegen = typegenConfig.outputs.typegen
if (sdl || typegen) { if (sdl || typegen) {
// Generating in the next tick allows us to use the schema // Generating in the next tick allows us to use the schema
// in the optional thunk for the typegen config // in the optional thunk for the typegen config
const typegenPromise = new TypegenMetadata(typegenConfig).generateArtifacts(schema, hasSDLDirectives) const typegenPromise = new TypegenMetadata(typegenConfig).generateArtifacts(schema)
if (config.shouldExitAfterGenerateArtifacts) { if (config.shouldExitAfterGenerateArtifacts) {
let typegenPath = '(not enabled)' let typegenPath = '(not enabled)'
if (typegenConfig.outputs.typegen) { if (typegenConfig.outputs.typegen) {
@ -59,9 +59,9 @@ export function makeSchema(config: SchemaConfig): NexusGraphQLSchema {
/** Like makeSchema except that typegen is always run and waited upon. */ /** Like makeSchema except that typegen is always run and waited upon. */
export async function generateSchema(config: SchemaConfig): Promise<NexusGraphQLSchema> { export async function generateSchema(config: SchemaConfig): Promise<NexusGraphQLSchema> {
const { schema, missingTypes, finalConfig, hasSDLDirectives } = makeSchemaInternal(config) const { schema, missingTypes, finalConfig } = makeSchemaInternal(config)
const typegenConfig = resolveTypegenConfig(finalConfig) const typegenConfig = resolveTypegenConfig(finalConfig)
await new TypegenMetadata(typegenConfig).generateArtifacts(schema, hasSDLDirectives) await new TypegenMetadata(typegenConfig).generateArtifacts(schema)
assertNoMissingTypes(schema, missingTypes) assertNoMissingTypes(schema, missingTypes)
runAbstractTypeRuntimeChecks(schema, finalConfig.features) runAbstractTypeRuntimeChecks(schema, finalConfig.features)
return schema return schema
@ -80,11 +80,11 @@ generateSchema.withArtifacts = async (
tsTypes: string tsTypes: string
globalTypes: string | null globalTypes: string | null
}> => { }> => {
const { schema, missingTypes, finalConfig, hasSDLDirectives } = makeSchemaInternal(config) const { schema, missingTypes, finalConfig } = makeSchemaInternal(config)
const typegenConfig = resolveTypegenConfig(finalConfig) const typegenConfig = resolveTypegenConfig(finalConfig)
const { schemaTypes, tsTypes, globalTypes } = await new TypegenMetadata( const { schemaTypes, tsTypes, globalTypes } = await new TypegenMetadata(
typegenConfig typegenConfig
).generateArtifactContents(schema, typegen, hasSDLDirectives) ).generateArtifactContents(schema, typegen)
assertNoMissingTypes(schema, missingTypes) assertNoMissingTypes(schema, missingTypes)
runAbstractTypeRuntimeChecks(schema, finalConfig.features) runAbstractTypeRuntimeChecks(schema, finalConfig.features)
return { schema, schemaTypes, tsTypes, globalTypes } return { schema, schemaTypes, tsTypes, globalTypes }
@ -125,7 +125,6 @@ export function makeSchemaInternal(config: SchemaConfig) {
onAfterBuildFns, onAfterBuildFns,
customDirectives, customDirectives,
schemaDirectives, schemaDirectives,
hasSDLDirectives,
} = builder.getFinalTypeMap() } = builder.getFinalTypeMap()
const schema = new GraphQLSchema({ const schema = new GraphQLSchema({
@ -144,7 +143,7 @@ export function makeSchemaInternal(config: SchemaConfig) {
onAfterBuildFns.forEach((fn) => fn(schema)) onAfterBuildFns.forEach((fn) => fn(schema))
return { schema, missingTypes, finalConfig, hasSDLDirectives } return { schema, missingTypes, finalConfig }
} }
type OmittedVals = Partial<{ [K in keyof MakeSchemaOptions]: never }> type OmittedVals = Partial<{ [K in keyof MakeSchemaOptions]: never }>

8
src/node.ts Normal file
View File

@ -0,0 +1,8 @@
export function nodeImports() {
const fs = require('fs') as typeof import('fs')
const path = require('path') as typeof import('path')
return {
fs,
path,
}
}

View File

@ -1,8 +1,8 @@
import { GraphQLNamedType, GraphQLSchema, isOutputType } from 'graphql' import { GraphQLNamedType, GraphQLSchema, isOutputType } from 'graphql'
import * as path from 'path'
import type { TypegenInfo } from './builder' import type { TypegenInfo } from './builder'
import type { TypingImport } from './definitions/_types' import type { TypingImport } from './definitions/_types'
import { TYPEGEN_HEADER } from './lang' import { TYPEGEN_HEADER } from './lang'
import { nodeImports } from './node'
import { getOwnPackage, log, objValues, relativePathTo, typeScriptFileExtension } from './utils' import { getOwnPackage, log, objValues, relativePathTo, typeScriptFileExtension } from './utils'
/** Any common types / constants that would otherwise be circular-imported */ /** Any common types / constants that would otherwise be circular-imported */
@ -129,16 +129,12 @@ export function typegenAutoConfig(options: SourceTypesConfigOptions, contextType
} }
}) })
const path = nodeImports().path
const typeSources = await Promise.all( const typeSources = await Promise.all(
options.modules.map(async (source) => { options.modules.map(async (source) => {
// Keeping all of this in here so if we don't have any sources // Keeping all of this in here so if we don't have any sources
// e.g. in the Playground, it doesn't break things. // e.g. in the Playground, it doesn't break things.
// Yeah, this doesn't exist in Node 6, but since this is a new
// lib and Node 6 is close to EOL so if you really need it, open a PR :)
const fs = require('fs') as typeof import('fs')
const util = require('util') as typeof import('util')
const readFile = util.promisify(fs.readFile)
const { module: pathOrModule, glob = true, onlyTypes, alias, typeMatch } = source const { module: pathOrModule, glob = true, onlyTypes, alias, typeMatch } = source
if (path.isAbsolute(pathOrModule) && path.extname(pathOrModule) !== '.ts') { if (path.isAbsolute(pathOrModule) && path.extname(pathOrModule) !== '.ts') {
return console.warn( return console.warn(
@ -154,7 +150,7 @@ export function typegenAutoConfig(options: SourceTypesConfigOptions, contextType
if (path.extname(resolvedPath) !== '.ts') { if (path.extname(resolvedPath) !== '.ts') {
resolvedPath = findTypingForFile(resolvedPath, pathOrModule) resolvedPath = findTypingForFile(resolvedPath, pathOrModule)
} }
fileContents = await readFile(resolvedPath, 'utf-8') fileContents = String(await nodeImports().fs.promises.readFile(resolvedPath, 'utf-8'))
} catch (e) { } catch (e) {
if (e instanceof Error && e.message.indexOf('Cannot find module') !== -1) { if (e instanceof Error && e.message.indexOf('Cannot find module') !== -1) {
console.error(`GraphQL Nexus: Unable to find file or module ${pathOrModule}, skipping`) console.error(`GraphQL Nexus: Unable to find file or module ${pathOrModule}, skipping`)
@ -277,7 +273,7 @@ export function typegenAutoConfig(options: SourceTypesConfigOptions, contextType
function findTypingForFile(absolutePath: string, pathOrModule: string) { function findTypingForFile(absolutePath: string, pathOrModule: string) {
// First try to find the "d.ts" adjacent to the file // First try to find the "d.ts" adjacent to the file
try { try {
const typeDefPath = absolutePath.replace(path.extname(absolutePath), '.d.ts') const typeDefPath = absolutePath.replace(nodeImports().path.extname(absolutePath), '.d.ts')
require.resolve(typeDefPath) require.resolve(typeDefPath)
return typeDefPath return typeDefPath
} catch (e) { } catch (e) {

View File

@ -1,5 +1,5 @@
import * as path from 'path'
import type * as Prettier from 'prettier' import type * as Prettier from 'prettier'
import { nodeImports } from './node'
export type TypegenFormatFn = (content: string, type: 'types' | 'schema') => string | Promise<string> export type TypegenFormatFn = (content: string, type: 'types' | 'schema') => string | Promise<string>
@ -22,6 +22,8 @@ export function typegenFormatPrettier(prettierConfig: string | object): TypegenF
let prettierConfigResolved: Prettier.Options let prettierConfigResolved: Prettier.Options
const path = nodeImports().path
if (typeof prettierConfig === 'string') { if (typeof prettierConfig === 'string') {
/* istanbul ignore if */ /* istanbul ignore if */
if (!path.isAbsolute(prettierConfig)) { if (!path.isAbsolute(prettierConfig)) {

View File

@ -1,9 +1,9 @@
import { GraphQLSchema, lexicographicSortSchema, printSchema } from 'graphql' import { GraphQLSchema, lexicographicSortSchema } from 'graphql'
import * as path from 'path'
import type { BuilderConfigInput, TypegenInfo } from './builder' import type { BuilderConfigInput, TypegenInfo } from './builder'
import type { ConfiguredTypegen } from './core' import type { ConfiguredTypegen } from './core'
import type { NexusGraphQLSchema } from './definitions/_types' import type { NexusGraphQLSchema } from './definitions/_types'
import { SDL_HEADER, TYPEGEN_HEADER } from './lang' import { SDL_HEADER, TYPEGEN_HEADER } from './lang'
import { nodeImports } from './node'
import { printSchemaWithDirectives } from './printSchemaWithDirectives' import { printSchemaWithDirectives } from './printSchemaWithDirectives'
import { typegenAutoConfig } from './typegenAutoConfig' import { typegenAutoConfig } from './typegenAutoConfig'
import { typegenFormatPrettier } from './typegenFormatPrettier' import { typegenFormatPrettier } from './typegenFormatPrettier'
@ -26,15 +26,11 @@ export class TypegenMetadata {
constructor(protected config: TypegenMetadataConfig) {} constructor(protected config: TypegenMetadataConfig) {}
/** Generates the artifacts of the build based on what we know about the schema and how it was defined. */ /** Generates the artifacts of the build based on what we know about the schema and how it was defined. */
async generateArtifacts(schema: NexusGraphQLSchema, hasSDLDirectives: boolean) { async generateArtifacts(schema: NexusGraphQLSchema) {
const sortedSchema = this.sortSchema(schema) const sortedSchema = this.sortSchema(schema)
const { typegen } = this.config.outputs const { typegen } = this.config.outputs
if (this.config.outputs.schema || typegen) { if (this.config.outputs.schema || typegen) {
const { schemaTypes, tsTypes, globalTypes } = await this.generateArtifactContents( const { schemaTypes, tsTypes, globalTypes } = await this.generateArtifactContents(sortedSchema, typegen)
sortedSchema,
typegen,
hasSDLDirectives
)
if (this.config.outputs.schema) { if (this.config.outputs.schema) {
await this.writeFile('schema', schemaTypes, this.config.outputs.schema) await this.writeFile('schema', schemaTypes, this.config.outputs.schema)
} }
@ -51,13 +47,9 @@ export class TypegenMetadata {
} }
} }
async generateArtifactContents( async generateArtifactContents(schema: NexusGraphQLSchema, typegen: string | null | ConfiguredTypegen) {
schema: NexusGraphQLSchema,
typegen: string | null | ConfiguredTypegen,
hasSDLDirectives: boolean
) {
const result = { const result = {
schemaTypes: this.generateSchemaFile(schema, hasSDLDirectives), schemaTypes: this.generateSchemaFile(schema),
tsTypes: '', tsTypes: '',
globalTypes: null as null | string, globalTypes: null as null | string,
} }
@ -83,30 +75,26 @@ export class TypegenMetadata {
} }
async writeFile(type: 'schema' | 'types', output: string, filePath: string) { async writeFile(type: 'schema' | 'types', output: string, filePath: string) {
if (typeof filePath !== 'string' || !path.isAbsolute(filePath)) { if (typeof filePath !== 'string' || !nodeImports().path.isAbsolute(filePath)) {
return Promise.reject( return Promise.reject(
new Error(`Expected an absolute path to output the Nexus ${type}, saw ${filePath}`) new Error(`Expected an absolute path to output the Nexus ${type}, saw ${filePath}`)
) )
} }
const fs = require('fs') as typeof import('fs') const fs = nodeImports().fs
const util = require('util') as typeof import('util')
const [readFile, writeFile, removeFile, mkdir] = [
util.promisify(fs.readFile),
util.promisify(fs.writeFile),
util.promisify(fs.unlink),
util.promisify(fs.mkdir),
]
const formattedOutput = const formattedOutput =
typeof this.config.formatTypegen === 'function' ? await this.config.formatTypegen(output, type) : output typeof this.config.formatTypegen === 'function' ? await this.config.formatTypegen(output, type) : output
const content = this.config.prettierConfig const content = this.config.prettierConfig
? await typegenFormatPrettier(this.config.prettierConfig)(formattedOutput, type) ? await typegenFormatPrettier(this.config.prettierConfig)(formattedOutput, type)
: formattedOutput : formattedOutput
const [toSave, existing] = await Promise.all([content, readFile(filePath, 'utf8').catch(() => '')]) const [toSave, existing] = await Promise.all([
content,
fs.promises.readFile(filePath, 'utf8').catch(() => ''),
])
if (toSave !== existing) { if (toSave !== existing) {
const dirPath = path.dirname(filePath) const dirPath = nodeImports().path.dirname(filePath)
try { try {
await mkdir(dirPath, { recursive: true }) await fs.promises.mkdir(dirPath, { recursive: true })
} catch (e) { } catch (e) {
if (e.code !== 'EEXIST') { if (e.code !== 'EEXIST') {
throw e throw e
@ -116,23 +104,22 @@ export class TypegenMetadata {
// apparently. See issue motivating this logic here: // apparently. See issue motivating this logic here:
// https://github.com/graphql-nexus/schema/issues/247. // https://github.com/graphql-nexus/schema/issues/247.
try { try {
await removeFile(filePath) await fs.promises.unlink(filePath)
} catch (e) { } catch (e) {
/* istanbul ignore next */ /* istanbul ignore next */
if (e.code !== 'ENOENT' && e.code !== 'ENOTDIR') { if (e.code !== 'ENOENT' && e.code !== 'ENOTDIR') {
throw e throw e
} }
} }
return writeFile(filePath, toSave) return fs.promises.writeFile(filePath, toSave)
} }
} }
/** Generates the schema, adding any directives as necessary */ /** Generates the schema, adding any directives as necessary */
generateSchemaFile(schema: GraphQLSchema, hasSDLDirectives: boolean): string { generateSchemaFile(schema: GraphQLSchema): string {
const printer = hasSDLDirectives ? printSchemaWithDirectives : printSchema
let printedSchema = this.config.customPrintSchemaFn let printedSchema = this.config.customPrintSchemaFn
? this.config.customPrintSchemaFn(schema) ? this.config.customPrintSchemaFn(schema)
: printer(schema) : printSchemaWithDirectives(schema)
return [SDL_HEADER, printedSchema].join('\n\n') return [SDL_HEADER, printedSchema].join('\n\n')
} }

View File

@ -28,7 +28,7 @@ import { isNexusPrintedGenTyping, isNexusPrintedGenTypingImport } from './defini
import type { NexusGraphQLSchema } from './definitions/_types' import type { NexusGraphQLSchema } from './definitions/_types'
import { TYPEGEN_HEADER } from './lang' import { TYPEGEN_HEADER } from './lang'
import type { StringLike } from './plugin' import type { StringLike } from './plugin'
import { hasNexusExtension } from './extensions' import { hasNexusExtension, isNexusFieldExtension } from './extensions'
import { import {
eachObj, eachObj,
getOwnPackage, getOwnPackage,
@ -641,8 +641,17 @@ export class TypegenPrinter {
} else { } else {
eachObj(type.getFields(), (field) => { eachObj(type.getFields(), (field) => {
const obj = (rootTypeMap[type.name] = rootTypeMap[type.name] || {}) const obj = (rootTypeMap[type.name] = rootTypeMap[type.name] || {})
if (!this.hasResolver(field, type)) { const fieldSourceType = this.fieldSourceType(field, type)
if (typeof obj !== 'string') { if (typeof obj !== 'string') {
if (Array.isArray(fieldSourceType)) {
for (const field of fieldSourceType) {
obj[field.name] = [field.optional ? '?:' : ':', field.type]
}
} else if (typeof fieldSourceType === 'object') {
obj[field.name] = [fieldSourceType.optional ? '?:' : ':', fieldSourceType.type]
} else if (fieldSourceType) {
obj[field.name] = [':', fieldSourceType]
} else if (!this.hasResolver(field, type)) {
obj[field.name] = [ obj[field.name] = [
this.argSeparator(field.type as GraphQLInputType, false), this.argSeparator(field.type as GraphQLInputType, false),
this.printOutputType(field.type), this.printOutputType(field.type),
@ -663,6 +672,17 @@ export class TypegenPrinter {
return (this.typegenInfo.sourceTypeMap as any)[typeName] return (this.typegenInfo.sourceTypeMap as any)[typeName]
} }
private fieldSourceType(
field: GraphQLField<any, any>,
// Used in test mocking
_type: GraphQLObjectType
) {
if (field.extensions && isNexusFieldExtension(field.extensions.nexus)) {
return field.extensions.nexus.sourceType
}
return undefined
}
private hasResolver( private hasResolver(
field: GraphQLField<any, any>, field: GraphQLField<any, any>,
// Used in test mocking // Used in test mocking

View File

@ -1,18 +1,15 @@
import * as path from 'path'
import type { BuilderConfigInput } from './builder' import type { BuilderConfigInput } from './builder'
import type { ConfiguredTypegen } from './core' import type { ConfiguredTypegen } from './core'
import { nodeImports } from './node'
import type { TypegenMetadataConfig } from './typegenMetadata' import type { TypegenMetadataConfig } from './typegenMetadata'
import { assertAbsolutePath, getOwnPackage, isProductionStage } from './utils' import { assertAbsolutePath, getOwnPackage, isProductionStage } from './utils'
/** Normalizes the builder config into the config we need for typegen */ /** Normalizes the builder config into the config we need for typegen */
export function resolveTypegenConfig(config: BuilderConfigInput): TypegenMetadataConfig { export function resolveTypegenConfig(config: BuilderConfigInput): TypegenMetadataConfig {
const { const { outputs, shouldGenerateArtifacts = defaultShouldGenerateArtifacts(), ...rest } = config
outputs,
shouldGenerateArtifacts = Boolean(!process.env.NODE_ENV || process.env.NODE_ENV !== 'production'),
...rest
} = config
const defaultSDLFilePath = path.join(process.cwd(), 'schema.graphql') function getOutputPaths() {
const defaultSDLFilePath = nodeImports().path.join(process.cwd(), 'schema.graphql')
let typegenFilePath: ConfiguredTypegen | null = null let typegenFilePath: ConfiguredTypegen | null = null
let sdlFilePath: string | null = null let sdlFilePath: string | null = null
@ -53,13 +50,26 @@ export function resolveTypegenConfig(config: BuilderConfigInput): TypegenMetadat
`Provide one to remove this warning.` `Provide one to remove this warning.`
) )
} }
return {
typegenFilePath,
sdlFilePath,
}
}
return { return {
...rest, ...rest,
nexusSchemaImportId: getOwnPackage().name, nexusSchemaImportId: getOwnPackage().name,
outputs: { outputs: {
typegen: shouldGenerateArtifacts ? typegenFilePath : null, typegen: shouldGenerateArtifacts ? getOutputPaths().typegenFilePath : null,
schema: shouldGenerateArtifacts ? sdlFilePath : null, schema: shouldGenerateArtifacts ? getOutputPaths().sdlFilePath : null,
}, },
} }
} }
function defaultShouldGenerateArtifacts() {
return Boolean(
typeof process === 'object' &&
typeof process.cwd === 'function' &&
(!process.env.NODE_ENV || process.env.NODE_ENV !== 'production')
)
}

View File

@ -1,4 +1,3 @@
import * as fs from 'fs'
import { import {
GraphQLEnumType, GraphQLEnumType,
GraphQLInputObjectType, GraphQLInputObjectType,
@ -22,7 +21,6 @@ import {
isWrappingType, isWrappingType,
specifiedScalarTypes, specifiedScalarTypes,
} from 'graphql' } from 'graphql'
import * as Path from 'path'
import { decorateType } from './definitions/decorateType' import { decorateType } from './definitions/decorateType'
import { isNexusMetaType, NexusMetaType, resolveNexusMetaType } from './definitions/nexusMeta' import { isNexusMetaType, NexusMetaType, resolveNexusMetaType } from './definitions/nexusMeta'
import { import {
@ -42,6 +40,7 @@ import {
TypingImport, TypingImport,
withNexusSymbol, withNexusSymbol,
} from './definitions/_types' } from './definitions/_types'
import { nodeImports } from './node'
export const isInterfaceField = (type: GraphQLObjectType, fieldName: string) => { export const isInterfaceField = (type: GraphQLObjectType, fieldName: string) => {
return type.getInterfaces().some((i) => Boolean(i.getFields()[fieldName])) return type.getInterfaces().some((i) => Boolean(i.getFields()[fieldName]))
@ -150,7 +149,7 @@ export function eachObj<T>(obj: Record<string, T>, iter: (val: T, key: string, i
export const isObject = (obj: any): boolean => obj !== null && typeof obj === 'object' export const isObject = (obj: any): boolean => obj !== null && typeof obj === 'object'
export const assertAbsolutePath = (pathName: string, property: string) => { export const assertAbsolutePath = (pathName: string, property: string) => {
if (!Path.isAbsolute(pathName)) { if (!nodeImports().path.isAbsolute(pathName)) {
throw new Error(`Expected path for "${property}" to be an absolute path, saw "${pathName}"`) throw new Error(`Expected path for "${property}" to be an absolute path, saw "${pathName}"`)
} }
return pathName return pathName
@ -221,7 +220,7 @@ export function isPromiseLike(value: any): value is PromiseLike<any> {
export const typeScriptFileExtension = /(\.d)?\.ts$/ export const typeScriptFileExtension = /(\.d)?\.ts$/
function makeRelativePathExplicitlyRelative(path: string) { function makeRelativePathExplicitlyRelative(path: string) {
if (Path.isAbsolute(path)) return path if (nodeImports().path.isAbsolute(path)) return path
if (path.startsWith('./')) return path if (path.startsWith('./')) return path
return `./${path}` return `./${path}`
} }
@ -243,6 +242,7 @@ export function formatPathForModuleImport(path: string) {
} }
export function relativePathTo(absolutePath: string, fromPath: string): string { export function relativePathTo(absolutePath: string, fromPath: string): string {
const Path = nodeImports().path
const filename = Path.basename(absolutePath) const filename = Path.basename(absolutePath)
const relative = Path.relative(Path.dirname(fromPath), Path.dirname(absolutePath)) const relative = Path.relative(Path.dirname(fromPath), Path.dirname(absolutePath))
return formatPathForModuleImport(Path.join(relative, filename)) return formatPathForModuleImport(Path.join(relative, filename))
@ -477,20 +477,18 @@ export function casesHandled(x: never): never {
throw new Error(`A case was not handled for value: "${x}"`) throw new Error(`A case was not handled for value: "${x}"`)
} }
/** Quickly log objects */
export function dump(x: any) {
console.log(require('util').inspect(x, { depth: null }))
}
function isNodeModule(path: string) { function isNodeModule(path: string) {
// Avoid treating absolute windows paths as Node packages e.g. D:/a/b/c // Avoid treating absolute windows paths as Node packages e.g. D:/a/b/c
return !Path.isAbsolute(path) && /^([A-z0-9@])/.test(path) return !nodeImports().path.isAbsolute(path) && /^([A-z0-9@])/.test(path)
} }
export function resolveImportPath(rootType: TypingImport, typeName: string, outputPath: string) { export function resolveImportPath(rootType: TypingImport, typeName: string, outputPath: string) {
const rootTypePath = rootType.module const rootTypePath = rootType.module
if (typeof rootTypePath !== 'string' || (!Path.isAbsolute(rootTypePath) && !isNodeModule(rootTypePath))) { if (
typeof rootTypePath !== 'string' ||
(!nodeImports().path.isAbsolute(rootTypePath) && !isNodeModule(rootTypePath))
) {
throw new Error( throw new Error(
`Expected an absolute path or Node package for the root typing path of the type "${typeName}", saw "${rootTypePath}"` `Expected an absolute path or Node package for the root typing path of the type "${typeName}", saw "${rootTypePath}"`
) )
@ -502,7 +500,7 @@ export function resolveImportPath(rootType: TypingImport, typeName: string, outp
} catch (e) { } catch (e) {
throw new Error(`Module "${rootTypePath}" for the type "${typeName}" does not exist`) throw new Error(`Module "${rootTypePath}" for the type "${typeName}" does not exist`)
} }
} else if (!fs.existsSync(rootTypePath)) { } else if (!nodeImports().fs.existsSync(rootTypePath)) {
throw new Error(`Root typing path "${rootTypePath}" for the type "${typeName}" does not exist`) throw new Error(`Root typing path "${rootTypePath}" for the type "${typeName}" does not exist`)
} }
@ -510,7 +508,7 @@ export function resolveImportPath(rootType: TypingImport, typeName: string, outp
return rootTypePath return rootTypePath
} }
if (Path.isAbsolute(rootTypePath)) { if (nodeImports().path.isAbsolute(rootTypePath)) {
return relativePathTo(rootTypePath, outputPath) return relativePathTo(rootTypePath, outputPath)
} }

16
tests/esm/esm-entry.js Normal file
View File

@ -0,0 +1,16 @@
import { GraphQLSchema } from 'graphql'
import { makeSchema, queryType } from '../../dist'
const schema = makeSchema({
types: [
queryType({
definition(t) {
t.boolean('ok')
},
}),
],
})
if (!(schema instanceof GraphQLSchema)) {
throw new Error('Not a schema')
}

View File

@ -0,0 +1,30 @@
import esbuild from 'esbuild'
import path from 'path'
import vm from 'vm'
import fs from 'fs'
describe('standalone esm', () => {
it('should build the esbuild', async () => {
const out = await esbuild.build({
bundle: true,
format: 'esm',
target: 'esnext',
// minify: true,
mainFields: ['module', 'main'],
external: ['path', 'fs', 'prettier'],
entryPoints: [path.join(__dirname, 'esm-entry.js')],
outdir: path.join(__dirname, 'out'),
outExtension: { '.js': '.mjs' },
metafile: true,
})
const context = vm.createContext()
// @ts-ignore
const outPath = path.join(__dirname, 'out', 'esm-entry.mjs')
fs.writeFileSync(path.join(path.dirname(outPath), 'meta.json'), JSON.stringify(out.metafile))
const script = new vm.Script(fs.readFileSync(outPath, 'utf8'), {
filename: outPath,
})
script.runInNewContext(context)
})
})

View File

@ -26,6 +26,19 @@ import {
import { mockStream } from '../../__helpers' import { mockStream } from '../../__helpers'
import './__typegen' import './__typegen'
export const Node = interfaceType({
name: 'Node',
definition(t) {
t.nonNull.id('id', {
resolve: (source, args, ctx, info) => `${info.parentType.name}:${source.id}`,
sourceType: 'number',
})
},
resolveType(obj: any) {
return obj.__typename
},
})
export const typeDirective = directive({ export const typeDirective = directive({
name: 'TestTypeDirective', name: 'TestTypeDirective',
locations: ['OBJECT', 'INTERFACE', 'ENUM', 'SCALAR'], locations: ['OBJECT', 'INTERFACE', 'ENUM', 'SCALAR'],
@ -116,12 +129,20 @@ export const i2 = objectType({
extensionAdditionFromTypeConfig: true, extensionAdditionFromTypeConfig: true,
}, },
definition(t) { definition(t) {
t.implements(Node)
t.implements('I') t.implements('I')
t.modify('hello', { t.modify('hello', {
extensions: { extensions: {
extensionAdditionFromModifyMethod: true, extensionAdditionFromModifyMethod: true,
}, },
}) })
t.string('composite', {
resolve: (source) => `${source.fieldA} ${source.fieldB}`,
sourceType: [
{ name: 'fieldA', type: 'string' },
{ name: 'fieldB', type: 'string' },
],
})
}, },
}) })
@ -180,8 +201,12 @@ export const Post = objectType({
export const User = objectType({ export const User = objectType({
name: 'User', name: 'User',
definition(t) { definition(t) {
t.string('firstName') t.string('firstName', {
t.string('lastName') sourceType: 'string',
})
t.string('lastName', {
sourceType: 'string',
})
t.connectionField('posts', { t.connectionField('posts', {
type: Post, type: Post,
nodes() { nodes() {
@ -206,8 +231,11 @@ export const User = objectType({
}, },
}, },
}) })
t.string('telephone', {
sourceType: { type: 'string', optional: true },
resolve: (source) => (source.telephone ? `+1 ${source.telephone}` : null),
})
}, },
sourceType: `{ firstName: string, lastName: string }`,
}) })
export const Query = extendType({ export const Query = extendType({

View File

@ -39,12 +39,18 @@ No-Op scalar for testing purposes only
""" """
scalar MyCustomScalar @TestAllDirective scalar MyCustomScalar @TestAllDirective
interface Node {
id: ID!
}
type OfI implements I @TestTypeDirective { type OfI implements I @TestTypeDirective {
hello: String @TestFieldDirective(bool: true) hello: String @TestFieldDirective(bool: true)
} }
type OfI2 implements I { type OfI2 implements I & Node {
composite: String
hello: String @TestFieldDirective(bool: true) hello: String @TestFieldDirective(bool: true)
id: ID!
} }
""" """
@ -156,6 +162,7 @@ type User {
""" """
last: Int last: Int
): PostConnection ): PostConnection
telephone: String
} }
enum UserStatus { enum UserStatus {

View File

@ -89,7 +89,10 @@ export interface NexusGenObjects {
} }
OfI2: { OfI2: {
// root type // root type
fieldA: string
fieldB: string
hello?: string | null // String hello?: string | null // String
id: number
} }
PageInfo: { PageInfo: {
// root type // root type
@ -117,11 +120,17 @@ export interface NexusGenObjects {
} }
Query: {} Query: {}
Subscription: {} Subscription: {}
User: { firstName: string; lastName: string } User: {
// root type
firstName: string
lastName: string
telephone?: string
}
} }
export interface NexusGenInterfaces { export interface NexusGenInterfaces {
I: NexusGenRootTypes['OfI'] | NexusGenRootTypes['OfI2'] I: NexusGenRootTypes['OfI'] | NexusGenRootTypes['OfI2']
Node: NexusGenRootTypes['OfI2']
} }
export interface NexusGenUnions {} export interface NexusGenUnions {}
@ -141,7 +150,9 @@ export interface NexusGenFieldTypes {
} }
OfI2: { OfI2: {
// field return type // field return type
composite: string | null // String
hello: string | null // String hello: string | null // String
id: string // ID!
} }
PageInfo: { PageInfo: {
// field return type // field return type
@ -192,11 +203,16 @@ export interface NexusGenFieldTypes {
firstName: string | null // String firstName: string | null // String
lastName: string | null // String lastName: string | null // String
posts: NexusGenRootTypes['PostConnection'] | null // PostConnection posts: NexusGenRootTypes['PostConnection'] | null // PostConnection
telephone: string | null // String
} }
I: { I: {
// field return type // field return type
hello: string | null // String hello: string | null // String
} }
Node: {
// field return type
id: string // ID!
}
} }
export interface NexusGenFieldTypeNames { export interface NexusGenFieldTypeNames {
@ -210,7 +226,9 @@ export interface NexusGenFieldTypeNames {
} }
OfI2: { OfI2: {
// field return type name // field return type name
composite: 'String'
hello: 'String' hello: 'String'
id: 'ID'
} }
PageInfo: { PageInfo: {
// field return type name // field return type name
@ -261,11 +279,16 @@ export interface NexusGenFieldTypeNames {
firstName: 'String' firstName: 'String'
lastName: 'String' lastName: 'String'
posts: 'PostConnection' posts: 'PostConnection'
telephone: 'String'
} }
I: { I: {
// field return type name // field return type name
hello: 'String' hello: 'String'
} }
Node: {
// field return type name
id: 'ID'
}
} }
export interface NexusGenArgTypes { export interface NexusGenArgTypes {
@ -306,11 +329,12 @@ export interface NexusGenArgTypes {
export interface NexusGenAbstractTypeMembers { export interface NexusGenAbstractTypeMembers {
I: 'OfI' | 'OfI2' I: 'OfI' | 'OfI2'
Node: 'OfI2'
} }
export interface NexusGenTypeInterfaces { export interface NexusGenTypeInterfaces {
OfI: 'I' OfI: 'I'
OfI2: 'I' OfI2: 'I' | 'Node'
} }
export type NexusGenObjectNames = keyof NexusGenObjects export type NexusGenObjectNames = keyof NexusGenObjects
@ -348,7 +372,7 @@ export interface NexusGenDirectiveArgs {
export type NexusGenObjectsUsingAbstractStrategyIsTypeOf = never export type NexusGenObjectsUsingAbstractStrategyIsTypeOf = never
export type NexusGenAbstractsUsingStrategyResolveType = 'I' export type NexusGenAbstractsUsingStrategyResolveType = 'I' | 'Node'
export type NexusGenFeaturesConfig = { export type NexusGenFeaturesConfig = {
abstractTypeStrategies: { abstractTypeStrategies: {

View File

@ -292,6 +292,7 @@ it('extensions are inherited and deeply merged by field modifications', () => {
"foo2": true, "foo2": true,
}, },
"nexus": NexusFieldExtension { "nexus": NexusFieldExtension {
"_type": "NexusFieldExtension",
"config": Object { "config": Object {
"configFor": "outputField", "configFor": "outputField",
"extensions": Object { "extensions": Object {
@ -305,6 +306,7 @@ it('extensions are inherited and deeply merged by field modifications', () => {
"wrapping": undefined, "wrapping": undefined,
}, },
"hasDefinedResolver": false, "hasDefinedResolver": false,
"sourceType": undefined,
}, },
} }
`) `)

126
yarn.lock
View File

@ -2520,6 +2520,132 @@ es6-weak-map@^2.0.1:
es6-iterator "^2.0.3" es6-iterator "^2.0.3"
es6-symbol "^3.1.1" es6-symbol "^3.1.1"
esbuild-android-64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz#7e6394a0e517f738641385aaf553c7e4fb6d1ae3"
integrity sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg==
esbuild-android-arm64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz#6877566be0f82dd5a43030c0007d06ece7f7c02f"
integrity sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g==
esbuild-darwin-64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz#ea3caddb707d88f844b1aa1dea5ff3b0a71ef1fd"
integrity sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA==
esbuild-darwin-arm64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz#4e5eaab54df66cc319b76a2ac0e8af4e6f0d9c2f"
integrity sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA==
esbuild-freebsd-64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz#47b5abc7426eae66861490ffbb380acc67af5b15"
integrity sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA==
esbuild-freebsd-arm64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz#e8c54c8637cd44feed967ea12338b0a4da3a7b11"
integrity sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw==
esbuild-linux-32@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz#229cf3246de2b7937c3ac13fac622d4d7a1344c5"
integrity sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ==
esbuild-linux-64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz#7c0e7226c02c42aacc5656c36977493dc1e96c4f"
integrity sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug==
esbuild-linux-arm64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz#0af1eda474b5c6cc0cace8235b74d0cb8fcf57a7"
integrity sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw==
esbuild-linux-arm@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz#de4d1fa6b77cdcd00e2bb43dd0801e4680f0ab52"
integrity sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw==
esbuild-linux-mips64le@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz#822c1778495f7868e990d4da47ad7281df28fd15"
integrity sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA==
esbuild-linux-ppc64le@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz#55de0a9ec4a48fedfe82a63e083164d001709447"
integrity sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ==
esbuild-linux-riscv64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz#cd2b7381880b2f4b21a5a598fb673492120f18a5"
integrity sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA==
esbuild-linux-s390x@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz#4b319eca2a5c64637fc7397ffbd9671719cdb6bf"
integrity sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g==
esbuild-netbsd-64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz#c27cde8b5cb55dcc227943a18ab078fb98d0adbf"
integrity sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw==
esbuild-openbsd-64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz#af5ab2d1cb41f09064bba9465fc8bf1309150df1"
integrity sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==
esbuild-sunos-64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz#db3ae20526055cf6fd5c4582676233814603ac54"
integrity sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA==
esbuild-windows-32@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz#021ffceb0a3f83078262870da88a912293c57475"
integrity sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg==
esbuild-windows-64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz#a4d3407b580f9faac51f61eec095fa985fb3fee4"
integrity sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA==
esbuild-windows-arm64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz#762c0562127d8b09bfb70a3c816460742dd82880"
integrity sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g==
esbuild@^0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.48.tgz#da5d8d25cd2d940c45ea0cfecdca727f7aee2b85"
integrity sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA==
optionalDependencies:
esbuild-android-64 "0.14.48"
esbuild-android-arm64 "0.14.48"
esbuild-darwin-64 "0.14.48"
esbuild-darwin-arm64 "0.14.48"
esbuild-freebsd-64 "0.14.48"
esbuild-freebsd-arm64 "0.14.48"
esbuild-linux-32 "0.14.48"
esbuild-linux-64 "0.14.48"
esbuild-linux-arm "0.14.48"
esbuild-linux-arm64 "0.14.48"
esbuild-linux-mips64le "0.14.48"
esbuild-linux-ppc64le "0.14.48"
esbuild-linux-riscv64 "0.14.48"
esbuild-linux-s390x "0.14.48"
esbuild-netbsd-64 "0.14.48"
esbuild-openbsd-64 "0.14.48"
esbuild-sunos-64 "0.14.48"
esbuild-windows-32 "0.14.48"
esbuild-windows-64 "0.14.48"
esbuild-windows-arm64 "0.14.48"
escape-goat@^2.0.0: escape-goat@^2.0.0:
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"