Compare commits

...

57 Commits
latest ... main

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
Tim Griesser 9875e90dae
feat: Add Schema Directives to SDL (#952)
Adds directive & addDirective utilities for defining directives emitted in the SDL
2022-05-15 16:59:05 -04:00
Tim Griesser 9a1050792b chore: attempt to fix the dripip workflow, again 2022-05-15 14:56:32 -04:00
Tim Griesser df9cb700a9 chore: update the dripip workflow, bump lint-staged 2022-05-15 14:50:03 -04:00
Tim Griesser 123dc61fac
fix: incorrect logic in backward pagination (#1084) 2022-05-03 15:35:21 -04:00
Tim Griesser 251af9461b fix: update snapshots for change in #1083 2022-05-03 11:38:57 -04:00
Daniel Schwartz b906288c58
chore: change facebook.github.io to relay.dev links (#1083) 2022-05-03 11:24:45 -04:00
Tim Griesser 11d028277e
feat: allow specifying custom directives in makeSchema (#1065) 2022-03-25 10:38:08 -04:00
Jonathan Zinger 509c246e88
Update comment for `shouldGenerateArtifacts` (#1057)
Update comment to reflect the current behavior as per [`src/typegenUtils.ts`](bc12ca0f8e/src/typegenUtils.ts (L11))
2022-03-25 10:28:24 -04:00
Vincent François aaa45204b6
feat: Run both formatTypegen and prettier formatter if given (#1042) 2022-03-25 08:20:32 -04:00
Tim Griesser 7349e3633c
feat: allow specifying custom directives in makeSchema (#1064)
* feat: allow specifying custom directives in makeSchema

* fix for earlier graphql snapshots
2022-03-24 18:48:41 -04:00
Vincent François 892af670a4
feat: Use ReadonlyArray in typings (#1041)
* Use ReadonlArray when generating output types

* Add useReadonlyArrayForInputs config and use it accordingly

* Update tests snapshots

* Move useReadonlyArrayForInputs in ConfiguredTypegen option

* Add tests for useReadonlyArrayForInputs

Co-authored-by: Jason Kuhrt <jasonkuhrt@me.com>
Co-authored-by: Tim Griesser <tgriesser10@gmail.com>
2022-03-24 17:02:17 -04:00
Jason Kuhrt bc12ca0f8e chore: use dripip reusable workflow 2022-03-10 14:02:20 -05:00
Tim Griesser 0f37c3e9d4
docs: Update npm badge 2022-03-05 15:29:59 -05:00
Tim Griesser 6c1530a3d5 v1.3.0 2022-03-05 15:26:42 -05:00
Tim Griesser 92f20dc9e9
chore: add test confirming v16 schema compat (#1054) 2022-03-05 15:25:11 -05:00
Tim Griesser bbc969a5b0
chore: update github workflows (#1053) 2022-03-05 14:12:48 -05:00
Tim Griesser 0d06f26b12
feat: add GraphQL 16 support (#977) 2022-02-17 12:47:40 -05:00
Aniruddh Mukherjee e901bebd51
chore(docs): fix typos (#1005)
Fixed the typos where `draftToPublish` (used in the previous example) were mistakenly written as `postToPublish` which might lead to confusion for some readers.
2021-12-15 09:10:02 -05:00
Riccardo Scalco 87a82a28b1
chore(docs): fix typo 06-chapter-5-persisting-data-via-prisma.mdx (#1007) 2021-12-15 09:09:34 -05:00
Riccardo Scalco 3de7f399c6
chore(docs): fix typo 04-why-nexus.mdx (#1008) 2021-12-15 09:09:02 -05:00
Tana M Berry 45b9d5a926
chore(docs): fix typo 030-neuxs-framework-prisma-users.mdx (#1016) 2021-12-15 09:08:30 -05:00
ChengQing b92545fe4f
chore(docs): fix typo 05-chapter-4-testing-your-api.mdx (#1023)
Fix typo.
2021-12-15 09:08:03 -05:00
ChengQing 4d035019a4
chore(docs): fix typo in 07-chapter-6-testing-with-prisma.mdx (#1024) 2021-12-15 09:07:24 -05:00
Tim Griesser 9ec3442539
fix: Minimum GraphQL v16 support (#1017) 2021-11-18 15:53:18 -05:00
Johan Kim c0e55b53b4
chore(docs): add Example Code (#948) 2021-10-26 21:50:03 -04:00
Johan Kim a7c26ba587
chore(docs): Update Ordering section (#950) 2021-10-26 21:49:26 -04:00
lockedNLevered 703d5595da
chore(docs): Nexus Getting started: missing type in queryType (#995)
queryType is missing type field. TypeScript would throw error and not compile.
2021-10-26 21:48:29 -04:00
Ella Nan 02015ede84
chore(docs): readme update -- fix code sample to include ".ts" in module path (#998) 2021-10-26 21:47:51 -04:00
Dani Guardiola 2934d6d38c
chore(docs): typo fix in docs (#999) 2021-10-26 21:47:19 -04:00
safaure 5e3b837ec0
chore(docs): change package get-port ver in tutorial (#1000)
See https://github.com/sindresorhus/get-port/releases

get-port does not support commonJS anymore.
2021-10-26 21:46:53 -04:00
Timo Heman b24d132d38
docs: change all "npm add" to "npm install" (#991) 2021-09-17 11:19:52 -04:00
Andrew McCallum e5658cadba
docs: Update 061-list-nonNull.mdx (#986)
Fixed syntax in docs where comma was missing
2021-09-07 09:07:05 -04:00
Tim Griesser 333dfb8757
feat: Add mergeSchema, better graphql-js interop (#983)
- Adds a new feature mergeSchema to the makeSchema config, to consume an external schema and merge with the locally defined Nexus types
- Standardizes the consumption of external GraphQLNamedType's so they are converted into Nexus type definitions, simplifying code paths
- Order of resolution goes from local Nexus types -> graphql-js types -> external schema types
- Adds asNexusMethod to all types, allowing for any commonly used types to be used as methods, not just scalars
- Convert methods / properties from protected -> private in Builder to better detect unused code
2021-09-06 09:32:43 -04:00
Tim Griesser 02a73b5d74
refactor: More internal cleanup (#981)
- Add Maybe on resolveType to match GraphQL signature
- Don't create placeholder Query type when renamed
- Internal rename rootTypings -> sourceTypings
2021-09-03 17:00:35 +00:00
Tim Griesser 7e744aa0d3
refactor: Internal type cleanup (#980)
* refactor: Internal type cleanup
* chore: Remove prettier-plugin-jsdoc as its output is non-determinstic
2021-09-03 14:04:28 +00:00
Tim Griesser e65b5a7952
refactor: remove duplicate core schema type checks (#978) 2021-09-02 23:44:37 +00:00
Tim Griesser d4c6260774
feat: ability to rename root types (#976)
Closes #867
2021-09-02 09:38:16 -04:00
Gary Lamp 6de1cb6917
docs: Remove `.ts` extension from import statement (#974) 2021-09-02 09:20:54 -04:00
Tim Griesser 555ae79ded
fix: revert declareInputs default to false (#975) 2021-09-02 13:18:47 +00:00
Tim Griesser a003ff074f
fix: printer imports, follow up from #967 (#970) 2021-08-19 14:56:35 +00:00
Johannes Choo 855a482c54
fix: plugin inputFieldDefTypes (#919) 2021-08-18 14:50:09 -04:00
Tim Griesser 266f1a82ce
fix: add globalHeaders to imports for global def file (#969) 2021-08-17 20:15:49 -04:00
Tim Griesser 380ed9d4ca
fix: correct imports for changes in #967 (#968)
* fix: correct imports for changes in #967
2021-08-17 19:35:56 -04:00
Tim Griesser 5984ee122e
feat: ConfiguredTypegen for splitting global types & configuring input type emission (#967)
* feat: ConfiguredTypegen for splitting globals from other types
* default the declareInputs to true
2021-08-17 15:49:47 -04:00
Tim Griesser a914cc33d1
Revert "fix: #921 wrong typegen for nullable values w/ default (#965)" (#966)
This reverts commit 03b5ffd24a.
2021-08-17 13:50:36 -04:00
Tim Griesser 03b5ffd24a
fix: #921 wrong typegen for nullable values w/ default (#965)
* fix: #921 wrong typegen for nullable values w/ default

* refactor: make the conditional easier to follow
2021-08-04 10:59:50 -04:00
Tim Griesser 4531519e6c fix failing CI types 2021-07-21 12:19:17 -04:00
Tobias Lins 8e0ce1b4a1
chore(docs): improve scalar documentation (#939) 2021-06-25 13:42:06 -04:00
154 changed files with 10014 additions and 4733 deletions

View File

@ -4,26 +4,24 @@ on:
- pull_request
jobs:
graphql-14:
graphql-15:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- uses: actions/setup-node@v1
with:
node-version: 12.x
node-version: 14.x
- name: Install Dependencies
run: yarn --frozen-lockfile || yarn --frozen-lockfile
- name: Check Formatting
run: yarn format:ci
- name: Install GraphQL@14.x
run: yarn add graphql@^14.5.8
run: yarn --frozen-lockfile && yarn format:ci
- name: Install GraphQL@15.x
run: yarn add graphql@^15
- name: Test
run: yarn -s test:ci --testPathIgnorePatterns v15
run: yarn -s test:ci
test:
strategy:
matrix:
node-version: [12.x, 14.x]
node-version: [14.x, 16.x]
os: [macos-latest, ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
@ -40,7 +38,7 @@ jobs:
run: yarn -s test:ci
- name: Upload coverage to Codecov
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:
directory: ./coverage
@ -58,7 +56,7 @@ jobs:
# rm examples/star-wars/star-wars-schema.graphql
# node examples/star-wars/dist/schema.js
# git diff --exit-code
node-version: [12.x]
node-version: [14.x]
os: [macos-latest]
runs-on: ${{ matrix.os }}
steps:

View File

@ -5,24 +5,24 @@ on:
branches: [main]
jobs:
graphql-14:
graphql-15:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 12.x
node-version: 14.x
- name: Install Dependencies
run: yarn --frozen-lockfile || yarn --frozen-lockfile
- name: Install GraphQL@14.x
run: yarn add graphql@^14.5.8
run: yarn --frozen-lockfile && yarn format:ci
- name: Install GraphQL@15.x
run: yarn add graphql@^15
- name: Test
run: yarn -s test:ci --testPathIgnorePatterns v15
run: yarn -s test:ci
test:
strategy:
matrix:
node-version: [12.x, 14.x]
node-version: [14.x, 16.x]
os: [macos-latest, ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
@ -38,7 +38,7 @@ jobs:
- name: Test
run: yarn -s test:ci
- 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
with:
directory: ./coverage
@ -57,7 +57,7 @@ jobs:
# rm examples/star-wars/star-wars-schema.graphql
# node examples/star-wars/dist/schema.js
# git diff --exit-code
node-version: [12.x]
node-version: [14.x]
os: [macos-latest]
runs-on: ${{ matrix.os }}
steps:

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ examples/*/dist
website/static/playground-dist
yarn-error.log
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
obtaining a copy of this software and associated documentation

View File

@ -1,7 +1,7 @@
# Nexus
[![trunk](https://github.com/graphql-nexus/nexus/workflows/trunk/badge.svg)](https://github.com/graphql-nexus/nexus/actions/workflows/trunk.yml)
[![npm version](https://badge.fury.io/js/%40nexus%2Fschema.svg)](https://badge.fury.io/js/%40nexus%2Fschema)
[![npm version](https://badge.fury.io/js/nexus.svg)](https://badge.fury.io/js/nexus)
Declarative, code-first and strongly typed GraphQL schema construction for TypeScript & JavaScript.
@ -74,4 +74,4 @@ You can find the docs for Nexus [here](http://nexusjs.org/).
## 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

@ -18,7 +18,7 @@ Start by creating your project directory, initializing your `package.json`, and
```bash-symbol copy
mkdir nexus-tutorial && cd nexus-tutorial
npm init -y
npm add nexus graphql apollo-server
npm install nexus graphql apollo-server
```
> Note: `nexus` works with any GraphQL compliant server. We'll use `apollo-server` in this tutorial, but you're free to use whichever fits your use-case best.
@ -26,7 +26,7 @@ npm add nexus graphql apollo-server
We'll also need `typescript` and `ts-node-dev` as dev dependencies. `ts-node-dev` will enable you to transpile your TS files on the fly and restart your API on changes.
```bash-symbol copy
npm add --save-dev typescript ts-node-dev
npm install --save-dev typescript ts-node-dev
```
To properly get full advantage of TypeScript, we'll need a `tsconfig.json` file. Create one at the root of your project and copy paste the following
@ -118,7 +118,7 @@ export const server = new ApolloServer({ schema })
```ts copy
// api/index.ts
import { server } from './server.ts'
import { server } from './server'
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`)

View File

@ -25,7 +25,7 @@ During this tutorial, you'll use the [Jest testing framework](https://jestjs.io/
First, install `jest` and accompanying tools.
```bash-symbol copy
npm add --save-dev jest @types/jest ts-jest graphql-request get-port
npm install --save-dev jest @types/jest ts-jest graphql-request get-port@5.1.1
```
Then, configure jest and npm scripts in your `package.json`
@ -88,7 +88,7 @@ mkdir tests && touch tests/Post.test.ts
To ease testing, we'll create a small utility that we'll call `createTestContext`, which is designed for running integration tests.
When run, it will boot your app in the same process as the test suite and expose an interface for your tests to interact with it. Jest runs each test suite in its own process, so if you have have say eight test suites running in parallel that means you'll have eight app processes running too.
When run, it will boot your app in the same process as the test suite and expose an interface for your tests to interact with it. Jest runs each test suite in its own process, so if you have say eight test suites running in parallel that means you'll have eight app processes running too.
Create a `tests/__helpers.ts` module with the following contents.

View File

@ -35,8 +35,8 @@ Now that you know a bit about Prisma, let's get going! Do the following:
like so:
```bash-symbol copy
npm add @prisma/client
npm add --save-dev prisma
npm install @prisma/client
npm install --save-dev prisma
```
Next, add Prisma to your project by creating your [Prisma schema](https://www.prisma.io/docs/concepts/components/prisma-schema/) file with the following command:
@ -135,7 +135,7 @@ Now let's finally ditch our in-memory data! Let's replace it with the Prisma Cli
// api/db.ts
+import { PrismaClient } from '@prisma/client'
export const db = new PrismaClient()
+export const db = new PrismaClient()
-export interface Post {
- id: number
@ -266,15 +266,15 @@ export const PostMutation = extendType({
draftId: nonNull(intArg()),
},
resolve(_root, args, ctx) {
- let postToPublish = ctx.db.posts.find((p) => p.id === args.draftId)
- let draftToPublish = ctx.db.posts.find((p) => p.id === args.draftId)
- if (!postToPublish) {
- if (!draftToPublish) {
- throw new Error('Could not find draft with id ' + args.draftId)
- }
- postToPublish.published = true
- draftToPublish.published = true
- return postToPublish
- return draftToPublish
+ return ctx.db.post.update({
+ where: { id: args.draftId },

View File

@ -26,7 +26,7 @@ To achieve some of the steps described above, we'll tweak our test context.
First, install the `sqlite3` and `nanoid` packages
```bash copy
npm add --save-dev sqlite3 @types/sqlite3
npm install --save-dev sqlite3 @types/sqlite3
```
Then, head to your `tests/__helpers.ts` file to add the following imports and code
@ -220,7 +220,7 @@ function prismaTestContext() {
The `prismaTestContext` is in charge of a couple of things:
1. Connect to an in-memory instance of the SQLite database
2. Pushes the Prisma Schema to the adatabase
2. Pushes the Prisma Schema to the database
3. Generates a new Prisma Client
4. Add an instance of a Prisma Client connected to the schema specifically for the test

View File

@ -63,6 +63,7 @@ const Post = objectType({
const Query = queryType({
definition(t) {
t.list.field('posts', {
type: "Post",
resolve: () => [
{
id: '1',
@ -93,7 +94,7 @@ There are numerous benefits to taking a code-first approach with Nexus:
When building a schema-first GraphQL API, it is common to start out by placing all type definitions and resolvers in a single file. When both the schema and the resolvers live next to one another, it's fairly straightforward to work in both at the same time.
As the application grows, however, it is most often desired to move parts of the schema into their own separate modules and files. It's at this point that working on a GraphQL API becomes a bit more tedious. With this modularization comes the need to switch back and forth between the Schema Definition Language and JavaScript/TypeScript to write the resolvers. Not only does one need to constantly switch between files, they also need to do a context switch mentally to work between the two langauges.
As the application grows, however, it is most often desired to move parts of the schema into their own separate modules and files. It's at this point that working on a GraphQL API becomes a bit more tedious. With this modularization comes the need to switch back and forth between the Schema Definition Language and JavaScript/TypeScript to write the resolvers. Not only does one need to constantly switch between files, they also need to do a context switch mentally to work between the two languages.
With Nexus, our schema and its resolvers are always defined together. Nexus also allows us to write everything in a common language. This allows us to side-step the co-location/context switching issue altogether and helps us to be more productive, even as our applications grow to be quite large.
@ -133,7 +134,7 @@ A downside of the schema-first approach is the need to repeat yourself in schema
### Defining enums
When defining an enum using the schema-first approach, the enum must first be defined in the schema definition languange:
When defining an enum using the schema-first approach, the enum must first be defined in the schema definition language:
```graphql
enum UserRole {

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)
- [mutationField](/api/mutation-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

@ -65,3 +65,14 @@ const SomeObject = objectType({
```
Check the type-definitions or [the examples](https://github.com/graphql-nexus/nexus/tree/main/examples) for a full illustration of the various options for `scalarType`, or feel free to open a PR on the docs to help document!
## Pass scalar to schema generation
It's important to list the scalar in the `types` attribute of `makeSchema`
```ts
const schema = makeSchema({
types: [GQLDate] // Add Scalar to Array
})
```

View File

@ -10,11 +10,31 @@ codeStyle: true
Defines a complex object which can be passed as an input value.
```ts
export const InputType = inputObjectType({
name: 'InputType',
import { extendType, inputObjectType } from 'nexus'
export const CommentInputType = inputObjectType({
name: 'CommentInputType',
definition(t) {
t.nonNull.string('key')
t.int('answer')
t.nonNull.int('userId')
t.nonNull.string('body')
}
})
export const CommentMutation = extendType({
type: 'Mutation',
definition(t) {
t.field('createComment', {
type: 'Comment',
args: { data: CommentInputType },
resolve(_root, args, ctx) {
return ctx.prisma.comment.create({
data: {
user_id: args.userId,
body: args.body,
}
})
}
})
},
})
```

View File

@ -15,7 +15,7 @@ import { queryType, stringArg, list } from 'nexus'
queryType({
definition(t) {
t.field('tags', {
type: list('String') // -> [String]
type: list('String'), // -> [String]
args: {
ids: list(stringArg()) // or list('String') -> [String]
},

View File

@ -4,7 +4,7 @@ title: Relay Connection
## Connection Plugin
The connection plugin provides a new method on the object definition builder, enabling paginated associations between types, following the [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm#sec-Node). It provides simple ways to customize fields available on the `Connection`, `Edges`, or `PageInfo` types.
The connection plugin provides a new method on the object definition builder, enabling paginated associations between types, following the [Relay Connection Specification](https://relay.dev/graphql/connections.htm#sec-Node). It provides simple ways to customize fields available on the `Connection`, `Edges`, or `PageInfo` types.
To install, add the `connectionPlugin` to the `makeSchema.plugins` array, along with any other plugins
you'd like to include:

View File

@ -6,13 +6,13 @@ 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.
> **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
```bash-symbol
npm add nexus-plugin-prisma @prisma/client
npm add -D prisma
npm install nexus-plugin-prisma @prisma/client
npm install -D prisma
```
## Usage

View File

@ -1586,7 +1586,7 @@ queryType({
type Query {
user(where: UserWhereUniqueInput!): User
users(orderBy: UserOrderByInput): [User!]!
users(orderBy: [UserOrderByInput!]): [User!]!
}
type Post {
@ -1598,7 +1598,7 @@ type Post {
type User {
id: Int!
name: String!
posts(orderBy: UserPostsOrderByInput): [Post!]!
posts(orderBy: [UserPostsOrderByInput!]): [Post!]!
}
input UserOrderByInput {
@ -1625,7 +1625,7 @@ enum OrderByArg {
```graphql
query entrypointOrdering {
users(orderBy: { name: asc }) {
users(orderBy: [{ name: asc }]) {
id
name
}
@ -1633,7 +1633,7 @@ query entrypointOrdering {
query relationOrdering {
user(where: { id: 1643 }) {
posts(orderBy: { title: dsc }) {
posts(orderBy: [{ title: desc }]) {
title
body
}

View File

@ -27,7 +27,7 @@ You will need to manage the TypeScript toolchain yourself.
1. Install `typescript`, `ts-node`, and `ts-node-dev`.
```bash-symbol
npm add -D typescript ts-node ts-node-dev
npm install -D typescript ts-node ts-node-dev
```
2. The following applies to VSCode but something like it might apply to other editors as well. You must also make sure your editor is set to use the local version of TypeScript rather than the one the editor ships with. Summon the command pallet `command+shift+p` and then enter and select `typescript: select TypeScript Version...`. Then select `Workspace Version`.
@ -205,13 +205,13 @@ Nexus framework comes bundled with Apollo Server and runs it for you. You will n
1. Install new dependencies
```tsx
npm add express apollo-server-express
npm install express apollo-server-express
```
2. If using TypeScript then Install typings for Express
```tsx
npm add -D @types/express
npm install -D @types/express
```
3. If using TypeScript then you [need to](https://github.com/apollographql/apollo-server/issues/1977#issuecomment-662946590) enable `esModuleInterop` to be able to use Apollo Server
@ -337,7 +337,7 @@ Nexus Framework has some builtin logging functionality. You can approximate it a
1. Install your logger
```tsx
npm add floggy
npm install floggy
```
2. Create your application logger. The logger you export here should be used across your codebase.
@ -386,7 +386,7 @@ You need to explicitly setup all custom scalars yourself. To match what Nexus Fr
1. Install the `graphql-scalars` package
```json
npm add graphql-scalars
npm install graphql-scalars
```
2. Setup the `Json` and `DateTime` scalars
@ -448,7 +448,7 @@ import * as Path from 'path'
Nexus.makeSchema({
contextType: {
module: Path.join(__dirname, './path/to/contextModule'),
module: Path.join(__dirname, './path/to/contextModule.ts'),
alias: 'ContextModule',
export: 'Context'
},
@ -536,13 +536,13 @@ In Nexus Framework there was a testing module for system testing your app. You n
1. Install your test framework
```tsx
npm add jest
npm install jest
```
2. If you are a TypeScript user then install and configure `ts-jest`
```bash
npm add ts-jest
npm install ts-jest
```
We will configure using a `jest.config.js` module in your project root. Do not use a JSON based configuration unless you know that you won't need the dynamic code used in some later steps here.
@ -639,7 +639,7 @@ In Nexus Framework there was a testing module for system testing your app. You n
6. You will need a way to run your app in tests. Here is one way [adapted from the tutorial](https://todo.com).
```tsx
npm add -D graphql-request
npm install -D graphql-request
```
```tsx
@ -688,7 +688,7 @@ Nexus Framework had a CLI for scaffolding new projects. You can approximate this
Nexus Framework has a gradual settings API with features such as automatic mapping of environment variables to settings. You can use the [`setset`](https://github.com/jasonkuhrt/setset) package manually to gain back this functionality.
```tsx
npm add setset
npm install setset
```
```tsx

View File

@ -13,8 +13,8 @@ If you're looking to migrate from the Nexus Framework over to Nexus and you're u
You will need to install the Prisma dependencies yourself now.
```
npm add -D @prisma/cli
npm add @prisma/client
npm install -D @prisma/cli
npm install @prisma/client
```
You must also make sure that you are using the version `0.20` or later of `nexus-plugin-prisma`.
@ -82,7 +82,7 @@ export const schema = makeSchema({
### Configuring Context Type
The framework used to automatically inject and type your context so that an instance of the client would be there for you. We know need to configure that manually. To do so, we'll first create a `context.ts` file where we'll export a type containing the Prisma Client.
The framework used to automatically inject and type your context so that an instance of the client would be there for you. We now need to configure that manually. To do so, we'll first create a `context.ts` file where we'll export a type containing the Prisma Client.
```tsx
// context.ts
@ -128,7 +128,7 @@ If your Prisma Schema is using either the `Json` or `DateTime` type, the framewo
```bash
npm install graphql-scalars
```
```xf
2. Then, add the following configuration property to the Prisma plugin

View File

@ -22,8 +22,8 @@ Check out the [example projects](https://github.com/graphql-nexus/nexus/tree/mai
## Installation
```sh
npm add nexus
npm add graphql # required as a peer dependency
npm install nexus
npm install graphql # required as a peer dependency
```
If you are using TypeScript version `4.1` is suggested. Nexus doesn't have a hard requirement for it yet but may in a future non-breaking release.

View File

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

View File

@ -22,7 +22,7 @@
"apollo-server-testing": "^2.18.1",
"dedent": "^0.7.0",
"fullstack-tutorial": "apollographql/fullstack-tutorial.git",
"graphql": "^15.3.0",
"graphql": "^16.3.0",
"graphql-tools": "^4.0.7",
"isemail": "^3.2.0",
"nexus": "^1.0.0",
@ -39,6 +39,6 @@
"node-fetch": "^2.2.1",
"prettier": "^1.19.1",
"ts-node-dev": "^1.0.0-pre.30",
"typescript": "^3.9"
"typescript": "^4.5.5"
}
}

View File

@ -1,4 +1,4 @@
import { idArg, list, nonNull, nullable, objectType, stringArg } from 'nexus'
import { idArg, list, nonNull, objectType, stringArg } from 'nexus'
export const Mutation = objectType({
name: 'Mutation',

View File

@ -3169,6 +3169,11 @@ graphql@^15.3.0:
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.3.0.tgz#3ad2b0caab0d110e3be4a5a9b2aa281e362b5278"
integrity sha512-GTCJtzJmkFLWRfFJuoo9RWWa/FfamUHgiFosxi/X1Ani4AVWbeyBenZTNX6dM+7WSbbFfTo/25eh0LLkwHMw2w==
graphql@^16.3.0:
version "16.3.0"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.3.0.tgz#a91e24d10babf9e60c706919bb182b53ccdffc05"
integrity sha512-xm+ANmA16BzCT5pLjuXySbQVFwH3oJctUVdy81w1sV0vBU0KgDdBGtxQOUd5zqOBk/JayAFeG8Dlmeq74rjm/A==
growly@^1.2.0, growly@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
@ -6799,10 +6804,10 @@ type-is@~1.6.17, type-is@~1.6.18:
media-typer "0.3.0"
mime-types "~2.1.24"
typescript@^3.9:
version "3.9.7"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
typescript@^4.5.5:
version "4.5.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3"
integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==
uglify-js@^3.1.4:
version "3.4.9"

View File

@ -9,7 +9,7 @@
"dataloader": "tgriesser/dataloader.git#ts-types",
"express": "^4.16.4",
"ghost": "^3.35.3",
"graphql": "^15.3.0",
"graphql": "^16.3.0",
"graphql-scalars": "^1.2.6",
"graphql-tools": "^4.0.7",
"knex": "^0.19.5",
@ -27,6 +27,6 @@
"prettier": "^1.19.1",
"ts-node": "^8.0.2",
"ts-node-dev": "^1.0.0-pre.30",
"typescript": "^3.9"
"typescript": "^4.5.5"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
"dependencies": {
"apollo-server": "^2.18.1",
"githunt-api": "peggyrayzis/GitHunt-API",
"graphql": "^14.5.8",
"graphql": "^16.3.0",
"graphql-tools": "^4.0.7",
"nexus": "^1.0.0"
},
@ -14,6 +14,6 @@
"nodemon": "^1.18.6",
"prettier": "^1.19.1",
"sqlite3": "^4.1.0",
"typescript": "^3.9"
"typescript": "^4.5.5"
}
}

View File

@ -2962,18 +2962,16 @@ graphql-upload@^8.0.2:
dependencies:
iterall "^1.1.0"
graphql@^14.5.8:
version "14.5.8"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-14.5.8.tgz#504f3d3114cb9a0a3f359bbbcf38d9e5bf6a6b3c"
integrity sha512-MMwmi0zlVLQKLdGiMfWkgQD7dY/TUKt4L+zgJ/aR0Howebod3aNgP5JkgvAULiR2HPVZaP2VEElqtdidHweLkg==
dependencies:
iterall "^1.2.2"
graphql@^15.3.0:
version "15.3.0"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.3.0.tgz#3ad2b0caab0d110e3be4a5a9b2aa281e362b5278"
integrity sha512-GTCJtzJmkFLWRfFJuoo9RWWa/FfamUHgiFosxi/X1Ani4AVWbeyBenZTNX6dM+7WSbbFfTo/25eh0LLkwHMw2w==
graphql@^16.3.0:
version "16.3.0"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.3.0.tgz#a91e24d10babf9e60c706919bb182b53ccdffc05"
integrity sha512-xm+ANmA16BzCT5pLjuXySbQVFwH3oJctUVdy81w1sV0vBU0KgDdBGtxQOUd5zqOBk/JayAFeG8Dlmeq74rjm/A==
har-schema@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
@ -3516,7 +3514,7 @@ isstream@~0.1.2:
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
iterall@^1.1.0, iterall@^1.1.3, iterall@^1.2.1, iterall@^1.2.2:
iterall@^1.1.0, iterall@^1.1.3, iterall@^1.2.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.2.2.tgz#92d70deb8028e0c39ff3164fdbf4d8b088130cd7"
integrity sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==
@ -5588,10 +5586,10 @@ type-is@~1.6.14, type-is@~1.6.17, type-is@~1.6.18:
media-typer "0.3.0"
mime-types "~2.1.24"
typescript@^3.9:
version "3.9.7"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
typescript@^4.5.5:
version "4.5.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3"
integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==
uid-safe@~2.1.4:
version "2.1.5"

View File

@ -19,24 +19,24 @@ interface Baz {
type BooleanConnection {
"""
https://facebook.github.io/relay/graphql/connections.htm#sec-Edge-Types
https://relay.dev/graphql/connections.htm#sec-Edge-Types
"""
edges: [BooleanEdge]
"""
https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo
https://relay.dev/graphql/connections.htm#sec-undefined.PageInfo
"""
pageInfo: PageInfo!
}
type BooleanEdge {
"""
https://facebook.github.io/relay/graphql/connections.htm#sec-Cursor
https://relay.dev/graphql/connections.htm#sec-Cursor
"""
cursor: String!
"""
https://facebook.github.io/relay/graphql/connections.htm#sec-Node
https://relay.dev/graphql/connections.htm#sec-Node
"""
node: Boolean
}
@ -49,24 +49,24 @@ scalar Date
type DateConnection {
"""
https://facebook.github.io/relay/graphql/connections.htm#sec-Edge-Types
https://relay.dev/graphql/connections.htm#sec-Edge-Types
"""
edges: [DateEdge]
"""
https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo
https://relay.dev/graphql/connections.htm#sec-undefined.PageInfo
"""
pageInfo: PageInfo!
}
type DateEdge {
"""
https://facebook.github.io/relay/graphql/connections.htm#sec-Cursor
https://relay.dev/graphql/connections.htm#sec-Cursor
"""
cursor: String!
"""
https://facebook.github.io/relay/graphql/connections.htm#sec-Node
https://relay.dev/graphql/connections.htm#sec-Node
"""
node: Date
}
@ -104,7 +104,7 @@ interface Node {
}
"""
PageInfo cursor, as defined in https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo
PageInfo cursor, as defined in https://relay.dev/graphql/connections.htm#sec-undefined.PageInfo
"""
type PageInfo {
"""
@ -306,24 +306,24 @@ type User {
type UserConnection {
"""
https://facebook.github.io/relay/graphql/connections.htm#sec-Edge-Types
https://relay.dev/graphql/connections.htm#sec-Edge-Types
"""
edges: [UserEdge]
"""
https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo
https://relay.dev/graphql/connections.htm#sec-undefined.PageInfo
"""
pageInfo: PageInfo!
}
type UserEdge {
"""
https://facebook.github.io/relay/graphql/connections.htm#sec-Cursor
https://relay.dev/graphql/connections.htm#sec-Cursor
"""
cursor: String!
"""
https://facebook.github.io/relay/graphql/connections.htm#sec-Node
https://relay.dev/graphql/connections.htm#sec-Node
"""
node: User
}

View File

@ -10,7 +10,7 @@
},
"dependencies": {
"apollo-server": "^2.18.1",
"graphql": "^15.3.0",
"graphql": "^16.3.0",
"graphql-query-complexity": "^0.4.1",
"graphql-relay": "^0.6.0",
"graphql-subscriptions": "^1.0.0",
@ -19,7 +19,7 @@
"nexus": "^1.0.0",
"subscriptions-transport-ws": "^0.9.15",
"ts-node": "^8.5.4",
"typescript": "^3.9"
"typescript": "^4.5.5"
},
"devDependencies": {
"@types/graphql-relay": "^0.4.11",

View File

@ -21,7 +21,11 @@ const schema = makeSchema({
types,
outputs: {
schema: path.join(__dirname, '../kitchen-sink-schema.graphql'),
typegen: path.join(__dirname, './kitchen-sink.gen.ts'),
typegen: {
outputPath: path.join(__dirname, './kitchen-sink.gen.ts'),
globalsPath: path.join(__dirname, './kitchen-sink-globals.gen.ts'),
declareInputs: true,
},
},
plugins: [
NodePlugin,

View File

@ -391,9 +391,17 @@ export const MoreQueryFields = extendType({
export const DateScalar = scalarType({
name: 'Date',
serialize: (value) => value.getTime(),
parseValue: (value) => new Date(value),
parseLiteral: (ast) => (ast.kind === 'IntValue' ? new Date(ast.value) : null),
serialize: (value) => (value as Date).toISOString(),
parseValue: (value) => new Date(value as string | number),
parseLiteral: (ast) => {
if (ast.kind === 'IntValue' || ast.kind === 'StringValue') {
const d = new Date(ast.value)
if (!isNaN(d.valueOf())) {
return d
}
}
throw new Error('Invalid date')
},
asNexusMethod: 'date',
sourceType: 'Date',
})

View File

@ -0,0 +1,65 @@
/** This file was generated by Nexus Schema Do not make changes to this file directly */
import type { NexusGenTypes } from './kitchen-sink.gen'
declare global {
interface NexusGenCustomInputMethods<TypeName extends string> {
date<FieldName extends string>(
fieldName: FieldName,
opts?: core.CommonInputFieldConfig<TypeName, FieldName>
): void // "Date";
}
}
declare global {
interface NexusGenCustomOutputMethods<TypeName extends string> {
date<FieldName extends string>(
fieldName: FieldName,
...opts: core.ScalarOutSpread<TypeName, FieldName>
): void // "Date";
/**
* Adds a Relay-style connection to the type, with numerous options for configuration
*
* @see https://nexusjs.org/docs/plugins/connection
*/
connectionField<FieldName extends string>(
fieldName: FieldName,
config: connectionPluginCore.ConnectionFieldConfig<TypeName, FieldName>
): void
}
}
declare global {
interface NexusGen extends NexusGenTypes {}
}
import type { core, connectionPluginCore } from 'nexus'
import type { QueryComplexity } from 'nexus/dist/plugins/queryComplexityPlugin'
import type { FieldAuthorizeResolver } from 'nexus/dist/plugins/fieldAuthorizePlugin'
declare global {
interface NexusGenPluginTypeConfig<TypeName extends string> {
node?: string | core.FieldResolver<TypeName, any>
}
interface NexusGenPluginInputTypeConfig<TypeName extends string> {}
interface NexusGenPluginFieldConfig<TypeName extends string, FieldName extends string> {
/**
* The complexity for an individual field. Return a number or a function that returns a number to specify
* the complexity for this field.
*/
complexity?: QueryComplexity<TypeName, FieldName>
/**
* Authorization for an individual field. Returning "true" or "Promise<true>" means the field can be
* accessed. Returning "false" or "Promise<false>" will respond with a "Not Authorized" error for the
* field. Returning or throwing an error will also prevent the resolver from executing.
*/
authorize?: FieldAuthorizeResolver<TypeName, FieldName>
/**
* The nullability guard can be helpful, but is also a potentially expensive operation for lists. We need
* to iterate the entire list to check for null items to guard against. Set this to true to skip the null
* guard on a specific field if you know there's no potential for unsafe types.
*/
skipNullGuard?: boolean
}
interface NexusGenPluginInputFieldConfig<TypeName extends string, FieldName extends string> {}
interface NexusGenPluginSchemaConfig {}
interface NexusGenPluginArgConfig {}
}

View File

@ -1,61 +1,34 @@
/** This file was generated by Nexus Schema Do not make changes to this file directly */
import { UnusedInterfaceTypeDef } from './kitchen-sink-definitions'
import { core, connectionPluginCore } from 'nexus'
import { QueryComplexity } from 'nexus/dist/plugins/queryComplexityPlugin'
import { FieldAuthorizeResolver } from 'nexus/dist/plugins/fieldAuthorizePlugin'
declare global {
interface NexusGenCustomInputMethods<TypeName extends string> {
date<FieldName extends string>(
fieldName: FieldName,
opts?: core.CommonInputFieldConfig<TypeName, FieldName>
): void // "Date";
}
}
declare global {
interface NexusGenCustomOutputMethods<TypeName extends string> {
date<FieldName extends string>(
fieldName: FieldName,
...opts: core.ScalarOutSpread<TypeName, FieldName>
): void // "Date";
/**
* Adds a Relay-style connection to the type, with numerous options for configuration
*
* @see https://nexusjs.org/docs/plugins/connection
*/
connectionField<FieldName extends string>(
fieldName: FieldName,
config: connectionPluginCore.ConnectionFieldConfig<TypeName, FieldName>
): void
}
import type { UnusedInterfaceTypeDef } from './kitchen-sink-definitions'
import type { core } from 'nexus'
export interface InputType {
answer?: number | null // Int
key: string // String!
nestedInput?: InputType2 | null // InputType2
}
declare global {
interface NexusGen extends NexusGenTypes {}
export interface InputType2 {
answer?: number | null // Int
key: string // String!
someDate: NexusGenScalars['Date'] // Date!
}
export interface NestedType {
veryNested?: string | null // String
}
export interface SomeArg {
arg?: NestedType | null // NestedType
someField?: string | null // String
}
export interface NexusGenInputs {
InputType: {
// input type
answer?: number | null // Int
key: string // String!
nestedInput?: NexusGenInputs['InputType2'] | null // InputType2
}
InputType2: {
// input type
answer?: number | null // Int
key: string // String!
someDate: NexusGenScalars['Date'] // Date!
}
NestedType: {
// input type
veryNested?: string | null // String
}
SomeArg: {
// input type
arg?: NexusGenInputs['NestedType'] | null // NestedType
someField?: string | null // String
}
InputType: InputType
InputType2: InputType2
NestedType: NestedType
SomeArg: SomeArg
}
export interface NexusGenEnums {}
@ -390,100 +363,117 @@ export interface NexusGenFieldTypeNames {
}
}
export interface FooArgsTestArgs {
a: InputType | null // InputType
}
export interface MutationSomeMutationFieldArgs {
id: string // ID!
}
export interface QueryAsArgExampleArgs {
testAsArg: InputType // InputType!
}
export interface QueryBooleanConnectionArgs {
after?: string | null // String
first: number // Int!
}
export interface QueryComplexQueryArgs {
count: number // Int!
}
export interface QueryDeprecatedConnectionArgs {
after?: string | null // String
before?: string | null // String
first?: number | null // Int
last?: number | null // Int
}
export interface QueryGetNumberOrNullArgs {
a: number // Int!
}
export interface QueryGuardedConnectionArgs {
after?: string | null // String
first: number // Int!
}
export interface QueryInlineArgsArgs {
someArg?: SomeArg | null // SomeArg
}
export interface QueryInputAsArgExampleArgs {
testInput?: InputType | null // InputType
testScalar?: string | null // String
}
export interface QueryUserConnectionAdditionalArgsArgs {
after?: string | null // String
first: number // Int!
isEven?: boolean | null // Boolean
}
export interface QueryUserConnectionBackwardOnlyArgs {
before?: string | null // String
last: number // Int!
}
export interface QueryUserConnectionForwardOnlyArgs {
after?: string | null // String
first: number // Int!
}
export interface QueryUsersConnectionNodesArgs {
after?: string | null // String
before?: string | null // String
first?: number | null // Int
last?: number | null // Int
}
export interface QueryUsersConnectionResolveArgs {
after?: string | null // String
before?: string | null // String
first?: number | null // Int
last?: number | null // Int
}
export interface TestObjArgsTestArgs {
a: InputType | null // InputType
}
export interface BarArgsTestArgs {
a: InputType | null // InputType
}
export interface NexusGenArgTypes {
Foo: {
argsTest: {
// args
a: NexusGenInputs['InputType'] | null // InputType
}
argsTest: FooArgsTestArgs
}
Mutation: {
someMutationField: {
// args
id: string // ID!
}
someMutationField: MutationSomeMutationFieldArgs
}
Query: {
asArgExample: {
// args
testAsArg: NexusGenInputs['InputType'] // InputType!
}
booleanConnection: {
// args
after?: string | null // String
first: number // Int!
}
complexQuery: {
// args
count: number // Int!
}
deprecatedConnection: {
// args
after?: string | null // String
before?: string | null // String
first?: number | null // Int
last?: number | null // Int
}
getNumberOrNull: {
// args
a: number // Int!
}
guardedConnection: {
// args
after?: string | null // String
first: number // Int!
}
inlineArgs: {
// args
someArg?: NexusGenInputs['SomeArg'] | null // SomeArg
}
inputAsArgExample: {
// args
testInput?: NexusGenInputs['InputType'] | null // InputType
testScalar?: string | null // String
}
userConnectionAdditionalArgs: {
// args
after?: string | null // String
first: number // Int!
isEven?: boolean | null // Boolean
}
userConnectionBackwardOnly: {
// args
before?: string | null // String
last: number // Int!
}
userConnectionForwardOnly: {
// args
after?: string | null // String
first: number // Int!
}
usersConnectionNodes: {
// args
after?: string | null // String
before?: string | null // String
first?: number | null // Int
last?: number | null // Int
}
usersConnectionResolve: {
// args
after?: string | null // String
before?: string | null // String
first?: number | null // Int
last?: number | null // Int
}
asArgExample: QueryAsArgExampleArgs
booleanConnection: QueryBooleanConnectionArgs
complexQuery: QueryComplexQueryArgs
deprecatedConnection: QueryDeprecatedConnectionArgs
getNumberOrNull: QueryGetNumberOrNullArgs
guardedConnection: QueryGuardedConnectionArgs
inlineArgs: QueryInlineArgsArgs
inputAsArgExample: QueryInputAsArgExampleArgs
userConnectionAdditionalArgs: QueryUserConnectionAdditionalArgsArgs
userConnectionBackwardOnly: QueryUserConnectionBackwardOnlyArgs
userConnectionForwardOnly: QueryUserConnectionForwardOnlyArgs
usersConnectionNodes: QueryUsersConnectionNodesArgs
usersConnectionResolve: QueryUsersConnectionResolveArgs
}
TestObj: {
argsTest: {
// args
a: NexusGenInputs['InputType'] | null // InputType
}
argsTest: TestObjArgsTestArgs
}
Bar: {
argsTest: {
// args
a: NexusGenInputs['InputType'] | null // InputType
}
argsTest: BarArgsTestArgs
}
}
@ -554,99 +544,3 @@ export interface NexusGenTypes {
abstractsUsingStrategyResolveType: NexusGenAbstractsUsingStrategyResolveType
features: NexusGenFeaturesConfig
}
declare global {
interface NexusGenPluginTypeConfig<TypeName extends string> {
node?: string | core.FieldResolver<TypeName, any>
}
interface NexusGenPluginFieldConfig<TypeName extends string, FieldName extends string> {
/**
* The complexity for an individual field. Return a number or a function that returns a number to specify
* the complexity for this field.
*/
complexity?: QueryComplexity<TypeName, FieldName>
/**
* Authorization for an individual field. Returning "true" or "Promise<true>" means the field can be
* accessed. Returning "false" or "Promise<false>" will respond with a "Not Authorized" error for the
* field. Returning or throwing an error will also prevent the resolver from executing.
*/
authorize?: FieldAuthorizeResolver<TypeName, FieldName>
/**
* The nullability guard can be helpful, but is also a potentially expensive operation for lists. We need
* to iterate the entire list to check for null items to guard against. Set this to true to skip the null
* guard on a specific field if you know there's no potential for unsafe types.
*/
skipNullGuard?: boolean
/**
* Whether the type can be null
*
* @default (depends on whether nullability is configured in type or schema)
* @see declarativeWrappingPlugin
*/
nullable?: boolean
/**
* Whether the type is list of values, or just a single value. If list is true, we assume the type is a
* list. If list is an array, we'll assume that it's a list with the depth. The boolean indicates whether
* the type is required (non-null), where true = nonNull, false = nullable.
*
* @see declarativeWrappingPlugin
*/
list?: true | boolean[]
/**
* Whether the type should be non null, `required: true` = `nullable: false`
*
* @default (depends on whether nullability is configured in type or schema)
* @see declarativeWrappingPlugin
*/
required?: boolean
}
interface NexusGenPluginInputFieldConfig<TypeName extends string, FieldName extends string> {
/**
* Whether the type can be null
*
* @default (depends on whether nullability is configured in type or schema)
* @see declarativeWrappingPlugin
*/
nullable?: boolean
/**
* Whether the type is list of values, or just a single value. If list is true, we assume the type is a
* list. If list is an array, we'll assume that it's a list with the depth. The boolean indicates whether
* the type is required (non-null), where true = nonNull, false = nullable.
*
* @see declarativeWrappingPlugin
*/
list?: true | boolean[]
/**
* Whether the type should be non null, `required: true` = `nullable: false`
*
* @default (depends on whether nullability is configured in type or schema)
* @see declarativeWrappingPlugin
*/
required?: boolean
}
interface NexusGenPluginSchemaConfig {}
interface NexusGenPluginArgConfig {
/**
* Whether the type can be null
*
* @default (depends on whether nullability is configured in type or schema)
* @see declarativeWrappingPlugin
*/
nullable?: boolean
/**
* Whether the type is list of values, or just a single value. If list is true, we assume the type is a
* list. If list is an array, we'll assume that it's a list with the depth. The boolean indicates whether
* the type is required (non-null), where true = nonNull, false = nullable.
*
* @see declarativeWrappingPlugin
*/
list?: true | boolean[]
/**
* Whether the type should be non null, `required: true` = `nullable: false`
*
* @default (depends on whether nullability is configured in type or schema)
* @see declarativeWrappingPlugin
*/
required?: boolean
}
}

View File

@ -2140,6 +2140,11 @@ graphql@^15.3.0:
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.3.0.tgz#3ad2b0caab0d110e3be4a5a9b2aa281e362b5278"
integrity sha512-GTCJtzJmkFLWRfFJuoo9RWWa/FfamUHgiFosxi/X1Ani4AVWbeyBenZTNX6dM+7WSbbFfTo/25eh0LLkwHMw2w==
graphql@^16.3.0:
version "16.3.0"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.3.0.tgz#a91e24d10babf9e60c706919bb182b53ccdffc05"
integrity sha512-xm+ANmA16BzCT5pLjuXySbQVFwH3oJctUVdy81w1sV0vBU0KgDdBGtxQOUd5zqOBk/JayAFeG8Dlmeq74rjm/A==
growly@^1.2.0, growly@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
@ -5070,10 +5075,10 @@ type-is@~1.6.16:
media-typer "0.3.0"
mime-types "~2.1.18"
typescript@^3.9:
version "3.9.7"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
typescript@^4.5.5:
version "4.5.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3"
integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==
uglify-js@^3.1.4:
version "3.4.9"

View File

@ -6,7 +6,7 @@
},
"dependencies": {
"apollo-server": "^2.18.1",
"graphql": "^15.3.0",
"graphql": "^16.3.0",
"graphql-tools": "^4.0.7",
"nexus": "^1.0.0",
"ts-node-dev": "^1.0.0-pre.30"
@ -15,6 +15,6 @@
"jest": "^23.6.0",
"prettier": "^1.19.1",
"ts-jest": "^24.1.0",
"typescript": "^3.9"
"typescript": "^4.5.5"
}
}

View File

@ -2097,6 +2097,11 @@ graphql@^15.3.0:
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.3.0.tgz#3ad2b0caab0d110e3be4a5a9b2aa281e362b5278"
integrity sha512-GTCJtzJmkFLWRfFJuoo9RWWa/FfamUHgiFosxi/X1Ani4AVWbeyBenZTNX6dM+7WSbbFfTo/25eh0LLkwHMw2w==
graphql@^16.3.0:
version "16.3.0"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.3.0.tgz#a91e24d10babf9e60c706919bb182b53ccdffc05"
integrity sha512-xm+ANmA16BzCT5pLjuXySbQVFwH3oJctUVdy81w1sV0vBU0KgDdBGtxQOUd5zqOBk/JayAFeG8Dlmeq74rjm/A==
growly@^1.2.0, growly@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
@ -5006,10 +5011,10 @@ type-is@~1.6.16:
media-typer "0.3.0"
mime-types "~2.1.18"
typescript@^3.9:
version "3.9.7"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
typescript@^4.5.5:
version "4.5.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3"
integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==
uglify-js@^3.1.4:
version "3.4.9"

View File

@ -8,11 +8,11 @@
"dependencies": {
"apollo-server": "^2.18.1",
"fs-extra": "^7.0.1",
"graphql": "^15.3.0",
"graphql": "^16.3.0",
"graphql-tools": "^4.0.7",
"nexus": "^1.0.0",
"ts-node-dev": "1.0.0-pre.31",
"typescript": "^3.9"
"typescript": "^4.5.5"
},
"devDependencies": {
"@types/fs-extra": "^5.0.4"

View File

@ -1,4 +1,5 @@
import { objectType, arg, list, nullable } from 'nexus'
import { objectType, arg, list, nullable, core } from 'nexus'
import ts from 'typescript'
import { nodeType, functionLikeDeclaration, hasTypeParameters } from './mixins'
import { filteredNodesList } from './utils'
@ -21,7 +22,7 @@ export const SourceFile = objectType({
t.list.field('statements', {
type: 'Node',
args: nodeSkipSyntax,
resolve: (root, args) => filteredNodesList(args, Array.from(root.statements)),
resolve: (root, args) => filteredNodesList<ts.Statement>(args, Array.from(root.statements)),
})
},
})
@ -156,7 +157,7 @@ export const ClassDeclaration = objectType({
t.list.field('members', {
type: 'Node',
args: nodeSkipSyntax,
resolve: (root, args) => filteredNodesList(args, Array.from(root.members)),
resolve: (root, args) => filteredNodesList<ts.ClassElement>(args, Array.from(root.members)),
})
},
})

View File

@ -1,5 +1,5 @@
import { arg, interfaceType, list, nullable } from 'nexus'
import { JSDoc, SyntaxKind } from 'typescript'
import ts, { JSDoc, SyntaxKind } from 'typescript'
import { allKnownNodes, syntaxKindFilter } from './utils'
const syntaxKindArgs = {
@ -50,7 +50,7 @@ export const Node = interfaceType({
if (!root.modifiers) {
return null
}
return syntaxKindFilter(args, Array.from(root.modifiers))
return syntaxKindFilter<ts.Modifier>(args, Array.from(root.modifiers))
},
})
t.field('parent', { type: 'Node' })
@ -78,7 +78,7 @@ export const JSDocInterface = interfaceType({
resolve(root) {
if ('jsDoc' in root) {
// https://github.com/Microsoft/TypeScript/issues/19856
return ((root as unknown) as { jsDoc: JSDoc[] }).jsDoc
return (root as unknown as { jsDoc: JSDoc[] }).jsDoc
}
return null
},

View File

@ -50,7 +50,7 @@ export const TupleTypeNode = objectType({
name: 'TupleTypeNode',
definition(t) {
nodeType(t)
t.list.field('elementTypes', { type: 'Node' })
t.list.field('elements', { type: 'Node' })
},
})

View File

@ -1,72 +1,69 @@
import { GraphQLSchema, isObjectType, GraphQLResolveInfo } from "graphql";
import ts from "typescript";
import { NexusGenArgTypes } from "../ts-ast-reader-typegen";
import { GraphQLSchema, isObjectType, GraphQLResolveInfo } from 'graphql'
import ts from 'typescript'
import { NexusGenArgTypes } from '../ts-ast-reader-typegen'
export function convertTsEnum(toConvert: any) {
const converted: { [key: string]: number } = {};
const converted: { [key: string]: number } = {}
Object.keys(toConvert).forEach((key) => {
if (/^[_a-zA-Z][_a-zA-Z0-9]*$/.test(key)) {
converted[key] = toConvert[key];
converted[key] = toConvert[key]
}
});
return converted;
})
return converted
}
const knownNodesMap = new WeakMap<GraphQLSchema, Set<string>>();
const knownNodesMap = new WeakMap<GraphQLSchema, Set<string>>()
export function allKnownNodes(schema: GraphQLSchema) {
let knownNodes = knownNodesMap.get(schema);
let knownNodes = knownNodesMap.get(schema)
if (!knownNodes) {
const fields = schema.getTypeMap();
knownNodes = new Set();
const fields = schema.getTypeMap()
knownNodes = new Set()
Object.keys(fields).forEach((key) => {
const field = fields[key];
if (
isObjectType(field) &&
Boolean(field.getInterfaces().find((i) => i.name === "Node"))
) {
knownNodes!.add(field.name);
const field = fields[key]
if (isObjectType(field) && Boolean(field.getInterfaces().find((i) => i.name === 'Node'))) {
knownNodes!.add(field.name)
}
});
knownNodesMap.set(schema, knownNodes);
})
knownNodesMap.set(schema, knownNodes)
}
return knownNodes!;
return knownNodes!
}
export const filteredNodesList = <T extends ts.Node>(
args: NexusGenArgTypes["SourceFile"]["statements"],
args: NexusGenArgTypes['SourceFile']['statements'],
nodes: T[]
) => {
const { skip, only } = args;
): T[] => {
const { skip, only } = args
if ((skip && skip.length) || (only && only.length)) {
return nodes.filter((node: ts.Node) => {
if (skip && skip.length > 0 && skip.indexOf(node.kind) !== -1) {
return;
return
}
if (only && only.length > 0 && only.indexOf(node.kind) === -1) {
return;
return
}
return node;
});
return node
})
}
return nodes;
};
return nodes
}
export const syntaxKindFilter = <T extends { kind: ts.SyntaxKind }>(
args: NexusGenArgTypes["Node"]["modifiers"],
args: NexusGenArgTypes['Node']['modifiers'],
items: T[]
) => {
const { skip, only } = args;
const { skip, only } = args
if ((only && only.length) || (skip && skip.length)) {
return items.filter((item) => {
if (only && only.length && only.indexOf(item.kind) === -1) {
return null;
return null
}
if (skip && skip.length && skip.indexOf(item.kind) !== -1) {
return null;
return null
}
return item;
});
return item
})
}
return items;
};
return items
}

View File

@ -1113,6 +1113,11 @@ graphql@^15.3.0:
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.3.0.tgz#3ad2b0caab0d110e3be4a5a9b2aa281e362b5278"
integrity sha512-GTCJtzJmkFLWRfFJuoo9RWWa/FfamUHgiFosxi/X1Ani4AVWbeyBenZTNX6dM+7WSbbFfTo/25eh0LLkwHMw2w==
graphql@^16.3.0:
version "16.3.0"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.3.0.tgz#a91e24d10babf9e60c706919bb182b53ccdffc05"
integrity sha512-xm+ANmA16BzCT5pLjuXySbQVFwH3oJctUVdy81w1sV0vBU0KgDdBGtxQOUd5zqOBk/JayAFeG8Dlmeq74rjm/A==
growly@^1.2.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
@ -2164,10 +2169,10 @@ type-is@~1.6.16:
media-typer "0.3.0"
mime-types "~2.1.18"
typescript@^3.9:
version "3.9.7"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
typescript@^4.5.5:
version "4.5.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3"
integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==
universalify@^0.1.0:
version "0.1.2"

View File

@ -20,13 +20,13 @@
"@prisma/client": "2.14.0",
"apollo-server-express": "^2.19.1",
"express": "^4.17.1",
"graphql": "^15.3.0",
"graphql": "^16.3.0",
"nexus": "^1.0.0"
},
"devDependencies": {
"@prisma/cli": "^2.14.0",
"prettier": "2.2.1",
"ts-node-dev": "^1.0.0-pre.62",
"typescript": "^4.0.2"
"typescript": "^4.5.5"
}
}

View File

@ -1015,6 +1015,11 @@ graphql@^15.3.0:
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.4.0.tgz#e459dea1150da5a106486ba7276518b5295a4347"
integrity sha512-EB3zgGchcabbsU9cFe1j+yxdzKQKAbGUWRb13DsrsMN1yyfmmIq+2+L5MqVWcDCE4V89R5AyUOi7sMOGxdsYtA==
graphql@^16.3.0:
version "16.3.0"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.3.0.tgz#a91e24d10babf9e60c706919bb182b53ccdffc05"
integrity sha512-xm+ANmA16BzCT5pLjuXySbQVFwH3oJctUVdy81w1sV0vBU0KgDdBGtxQOUd5zqOBk/JayAFeG8Dlmeq74rjm/A==
has-symbols@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
@ -1814,10 +1819,10 @@ type-is@^1.6.16, type-is@~1.6.17, type-is@~1.6.18:
media-typer "0.3.0"
mime-types "~2.1.24"
typescript@^4.0.2:
version "4.1.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7"
integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==
typescript@^4.5.5:
version "4.5.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3"
integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==
unpipe@1.0.0, unpipe@~1.0.0:
version "1.0.0"

View File

@ -13,13 +13,13 @@
"trailingComma": "all"
},
"dependencies": {
"graphql": "^15.3.0",
"graphql": "^16.3.0",
"nexus": "^1.0.0"
},
"devDependencies": {
"@now/node": "^1.0.1",
"@types/node": "^12.11.1",
"ts-node": "^8.4.1",
"typescript": "^3.9"
"typescript": "^4.5.5"
}
}

View File

@ -29,10 +29,10 @@ diff@^4.0.1:
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.1.tgz#0c667cb467ebbb5cea7f14f135cc2dba7780a8ff"
integrity sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==
graphql@^15.3.0:
version "15.3.0"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.3.0.tgz#3ad2b0caab0d110e3be4a5a9b2aa281e362b5278"
integrity sha512-GTCJtzJmkFLWRfFJuoo9RWWa/FfamUHgiFosxi/X1Ani4AVWbeyBenZTNX6dM+7WSbbFfTo/25eh0LLkwHMw2w==
graphql@^16.3.0:
version "16.3.0"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.3.0.tgz#a91e24d10babf9e60c706919bb182b53ccdffc05"
integrity sha512-xm+ANmA16BzCT5pLjuXySbQVFwH3oJctUVdy81w1sV0vBU0KgDdBGtxQOUd5zqOBk/JayAFeG8Dlmeq74rjm/A==
iterall@^1.3.0:
version "1.3.0"
@ -81,10 +81,10 @@ tslib@^2.0.3:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.3.tgz#8e0741ac45fc0c226e58a17bfc3e64b9bc6ca61c"
integrity sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==
typescript@^3.9:
version "3.9.7"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
typescript@^4.5.5:
version "4.5.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3"
integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==
yn@^3.0.0:
version "3.1.1"

View File

@ -1,6 +1,6 @@
{
"name": "nexus",
"version": "0.0.0-dripip",
"version": "1.3.0",
"description": "Scalable, strongly typed GraphQL schema development",
"keywords": [
"graphql",
@ -46,7 +46,6 @@
"release:pr": "dripip pr",
"release:preview": "dripip preview",
"release:stable": "dripip stable",
"pretest": "yarn patch-package",
"test": "yarn test:types && jest --testTimeout 10000",
"test:ci": "yarn test:types && jest --maxWorkers 2 --coverage --testTimeout 10000",
"test:debug": "node --inspect-brk $(yarn bin)/jest -i --watch",
@ -62,12 +61,10 @@
},
"lint-staged": {
"*.{ts,js,graphql,json,css,md}": [
"prettier --write",
"git add"
"prettier --write"
],
"*package.json": [
"sort-package-json",
"git add"
"sort-package-json"
]
},
"dependencies": {
@ -82,29 +79,28 @@
"@types/prettier": "^1.18.3",
"@typescript-eslint/eslint-plugin": "2.7.0",
"dripip": "^0.10.0",
"esbuild": "^0.14.48",
"eslint": "^6.6.0",
"get-port": "^5.1.1",
"graphql": "^15.3.0",
"graphql-relay": "^0.6.0",
"graphql-scalars": "^1.2.6",
"graphql": "^16.3.0",
"graphql-relay": "^0.10.0",
"graphql-scalars": "^1.14.1",
"gulp": "4.0.2",
"husky": "^1.1.2",
"jest": "^26.6.3",
"jest-watch-typeahead": "^0.6.1",
"lint-staged": "^7.3.0",
"patch-package": "6.2.2",
"prettier": "^2.3.1",
"prettier-plugin-jsdoc": "^0.3.23",
"lint-staged": "^12.4.1",
"prettier": "^2.5.1",
"sort-package-json": "^1.22.1",
"ts-jest": "^26.4.4",
"ts-morph": "^8.2.0",
"ts-morph": "^13.0.3",
"ts-node": "^9.0.0",
"tsd": "^0.13.1",
"tslint": "^5.11.0",
"tslint-config-prettier": "^1.15.0",
"typescript": "^4.1.2"
"typescript": "^4.5.5"
},
"peerDependencies": {
"graphql": "^14.5.8 || 15.x"
"graphql": "15.x || 16.x"
}
}

View File

@ -1,13 +0,0 @@
diff --git a/node_modules/prettier-plugin-jsdoc/lib/parser.js b/node_modules/prettier-plugin-jsdoc/lib/parser.js
index 85b9e5d..3b98730 100644
--- a/node_modules/prettier-plugin-jsdoc/lib/parser.js
+++ b/node_modules/prettier-plugin-jsdoc/lib/parser.js
@@ -12,7 +12,7 @@ const stringify_1 = require("./stringify");
/** @link https://prettier.io/docs/en/api.html#custom-parser-api} */
exports.getParser = (parser) => function jsdocParser(text, parsers, options) {
const ast = parser(text, parsers, options);
- if (!options.jsdocParser) {
+ if (!options || !options.jsdocParser) {
return ast;
}
/**

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@
export * from './builder'
export * from './makeSchema'
export * from './definitions/args'
export * from './definitions/directive'
export * from './definitions/decorateType'
export * from './definitions/definitionBlocks'
export * from './definitions/enumType'
@ -28,6 +29,7 @@ export * from './definitions/_types'
export * from './dynamicMethod'
export * from './plugin'
export * from './plugins'
export * from './rebuildType'
export * from './sdlConverter'
export * from './typegenAutoConfig'
export * from './typegenFormatPrettier'

View File

@ -13,6 +13,7 @@ import type {
GraphQLSchema,
GraphQLUnionType,
} from 'graphql'
import type { NexusDirectiveConfig } from '../core'
import type {
NexusFieldExtension,
NexusInputObjectTypeExtension,
@ -25,7 +26,8 @@ import type { RequiredDeeply } from '../typeHelpersInternal'
export type { AbstractTypes }
export type Maybe<T> = T | null
/** Conveniently represents flow's "Maybe" type https://flow.org/en/docs/types/maybe/ */
export type Maybe<T> = null | undefined | T
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
@ -52,6 +54,8 @@ export enum NexusTypes {
PrintedGenTypingImport = 'PrintedGenTypingImport',
Scalar = 'Scalar',
Union = 'Union',
Directive = 'Directive',
DirectiveUse = 'DirectiveUse',
}
export interface DeprecationInfo {
@ -154,8 +158,13 @@ export type NexusGraphQLInterfaceTypeConfig = WithExt<
NexusInterfaceTypeExtension
> & { interfaces: () => GraphQLInterfaceType[] }
export type NexusGraphQLSchema = Omit<GraphQLSchema, 'extensions'> & {
extensions: { nexus: NexusSchemaExtension }
export type NexusGraphQLDirectiveConfig = WithExt<NexusDirectiveConfig, NexusInputObjectTypeExtension>
export interface NexusGraphQLSchema extends GraphQLSchema {
extensions: {
nexus: NexusSchemaExtension
[attributeName: string]: unknown
}
}
export type NexusFeaturesInput = {
@ -175,8 +184,8 @@ export type NexusFeaturesInput = {
* types guide](https://nxs.li/guides/abstract-types).
*
* If you plan on enabling multiple strategies and you've never done so then please [read the guide about
* using multiple strategies](https://nxs.li/guides/abstract-types/using-multiple-strategies) as there are a
* few quirks to be aware of.
* using multiple strategies](https://nxs.li/guides/abstract-types/using-multiple-strategies) as there are
* a few quirks to be aware of.
*
* @default {resolveType: true,
* __typename: false
@ -203,16 +212,16 @@ export type NexusFeaturesInput = {
* the [Discriminant Model Field Strategy](https://nxs.li/guides/abstract-types/discriminant-model-field-strategy).
*
* Warning :: When this strategy is enabled in conjunction with other strategies the
* "abstractTypeRuntimeChecks" feature will automatically be disabled. This is because it is not practical
* at runtime to find out if resolvers will return objects that include the "__typename" field. This
* trade-off can be acceptable since the runtime checks are a redundant safety measure over the static
* typing. So as long as you are not ignoring static errors related to Nexus' abstract type type checks
* then you then you should still have a safe implementation.
* "abstractTypeRuntimeChecks" feature will automatically be disabled. This is because it is not
* practical at runtime to find out if resolvers will return objects that include the "__typename" field.
* This trade-off can be acceptable since the runtime checks are a redundant safety measure over the
* static typing. So as long as you are not ignoring static errors related to Nexus' abstract type type
* checks then you then you should still have a safe implementation.
*
* Furthermore another effect is that statically the other strategies will not appear to be *required*,
* but instead *optional*, while only this one will appear required. However, upon implementing any of the
* other strategies, this one will not longer be required. This quirk is explained in the guide section
* about [using multiple strategies](https://nxs.li/guides/abstract-types/using-multiple-strategies).
* but instead *optional*, while only this one will appear required. However, upon implementing any of
* the other strategies, this one will not longer be required. This quirk is explained in the guide
* section about [using multiple strategies](https://nxs.li/guides/abstract-types/using-multiple-strategies).
*/
__typename?: boolean
}

View File

@ -1,7 +1,8 @@
import type { GraphQLScalarTypeConfig } from 'graphql'
import type { AllInputTypes, GetGen2 } from '../typegenTypeHelpers'
import type { Directives } from './directive'
import type { AllNexusArgsDefs, AllNexusInputTypeDefs } from './wrapping'
import { NexusTypes, withNexusSymbol } from './_types'
import { Maybe, NexusTypes, withNexusSymbol } from './_types'
export type ArgsRecord = Record<string, AllNexusArgsDefs>
@ -39,7 +40,7 @@ export type CommonArgConfig = {
* // ): [Int]
* // }
*/
description?: string
description?: Maybe<string>
/**
* Data that will be added to the arg-level [extensions field on the graphql-js type def
@ -47,6 +48,13 @@ export type CommonArgConfig = {
* graphql-js based tools which rely on looking for special data here.
*/
extensions?: GraphQLScalarTypeConfig<any, any>['extensions']
/**
* A list of directives / directive uses (with args) for the arg definition
*
* @example
* directives: [addDirective('ExampleDirective', { arg: true })]
*/
directives?: Directives
} & NexusGenPluginArgConfig
export interface ScalarArgConfig<T> extends CommonArgConfig {
@ -86,10 +94,10 @@ export interface NexusArgConfig<T extends string> extends NexusAsArgConfig<T> {
*
* Types may be expressed in one of three ways:
*
* 1. As string literals matching the name of a builtin scalar.
* 2. As string literals matching the name of another type. Thanks to [Nexus' reflection
* system](https://nxs.li/guides/reflection) this is typesafe and autocompletable.
* 3. As references to other enums or input object type definitions.
* 1. As string literals matching the name of a builtin scalar. 2. As string literals matching the name of
* another type. Thanks to [Nexus' reflection
* system](https://nxs.li/guides/reflection) this is typesafe and autocompletable. 3. As references to other
* enums or input object type definitions.
*
* Type modifier helpers like list() may also be used and in turn accept one of the three methods listed above.
*
@ -157,7 +165,7 @@ withNexusSymbol(NexusArgDef, NexusTypes.Arg)
* })
*
* @param config Configuration for the argument like its type and description. See jsdoc on each config field
* for details.
* for details.
*/
export function arg<T extends string>(config: NexusArgConfig<T>) {
if (!config.type) {

View File

@ -6,17 +6,13 @@ export interface TypeExtensionConfig {
sourceType?: SourceTypingDef
}
export type NexusTypeExtensions = {
nexus: TypeExtensionConfig
}
export function decorateType<T extends GraphQLNamedType>(type: T, config: TypeExtensionConfig): T {
type.extensions = {
...type.extensions,
nexus: {
asNexusMethod: config.asNexusMethod,
sourceType: config.sourceType,
...Object(type.extensions?.nexus),
...config,
},
}
return type as any
return type
}

View File

@ -9,20 +9,19 @@ import type {
NeedsResolver,
} from '../typegenTypeHelpers'
import type { ArgsRecord } from './args'
import type { Directives } from './directive'
import type { NexusMetaType } from './nexusMeta'
import type { AllNexusInputTypeDefs, AllNexusOutputTypeDefs, NexusWrapKind } from './wrapping'
import type { BaseScalars } from './_types'
import type { BaseScalars, Maybe } from './_types'
export interface CommonFieldConfig {
//todo
/** The description to annotate the GraphQL SDL */
description?: string
//todo
description?: Maybe<string>
/**
* Info about a field deprecation. Formatted as a string and provided with the deprecated directive on
* field/enum types and as a comment on input fields.
*/
deprecation?: string // | DeprecationInfo;
deprecation?: Maybe<string> // | DeprecationInfo;
}
export type CommonOutputFieldConfig<TypeName extends string, FieldName extends string> = CommonFieldConfig & {
@ -75,7 +74,7 @@ export type CommonOutputFieldConfig<TypeName extends string, FieldName extends s
* },
* })
*/
args?: ArgsRecord
args?: Maybe<ArgsRecord>
/**
* Data that will be added to the field-level [extensions field on the graphql-js type def
* instances](https://github.com/graphql/graphql-js/issues/1527) resulting from makeSchema. Useful for some
@ -105,8 +104,43 @@ export type CommonOutputFieldConfig<TypeName extends string, FieldName extends s
* })
*/
extensions?: GraphQLFieldConfig<any, any>['extensions']
/**
* A list of directives / directive uses (with args) for the output field definition
*
* @example
* directives: [addDirective('ExampleDirective', { arg: true })]
*/
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>
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 & {
/** The default value for the field, if any */
default?: GetGen3<'inputTypes', TypeName, FieldName>
@ -116,7 +150,16 @@ export type CommonInputFieldConfig<TypeName extends string, FieldName extends st
* graphql-js based tools which rely on looking for special data here.
*/
extensions?: GraphQLInputFieldConfig['extensions']
} & NexusGenPluginFieldConfig<TypeName, FieldName>
/**
* A list of directives / directive uses (with args) for the input field definition
*
* @example
* directives: [addDirective('ExampleDirective', { arg: true })]
*/
directives?: Directives
} & NexusGenPluginFieldConfig<TypeName, FieldName> &
NexusGenPluginInputFieldConfig<TypeName, FieldName>
export interface OutputScalarConfig<TypeName extends string, FieldName extends string>
extends CommonOutputFieldConfig<TypeName, FieldName> {
/**
@ -127,9 +170,7 @@ export interface OutputScalarConfig<TypeName extends string, FieldName extends s
* Every field has a resolver and they are the basis for resolving queries at runtime. You do not need to
* explicitly implement every resolver however. If the [source typing](https://nxs.li/guides/backing-types) includes:
*
* 1. A field whose name matches this one
* 2. And whose type is compatible
* 3. And is a scalar
* 1. A field whose name matches this one 2. And whose type is compatible 3. And is a scalar
*
* ...then the default resolver will be available, whose behaviour is to simply return that field from the
* received source type.
@ -147,29 +188,29 @@ export interface OutputScalarConfig<TypeName extends string, FieldName extends s
* })
*
* @param source The [source data](https://nxs.li/guides/source-types) for the GraphQL object that this
* field belongs to, unless this is a root field (any field on a [root operation
* type](https://spec.graphql.org/June2018/#sec-Root-Operation-Types): Query, Mutation, Subscription), in
* which case there is no source data and this will be undefined.
* field belongs to, unless this is a root field (any field on a [root operation
* type](https://spec.graphql.org/June2018/#sec-Root-Operation-Types): Query, Mutation, Subscription),
* in which case there is no source data and this will be undefined.
* @param args If you have defined arguments on this field then this parameter will contain any arguments
* passed by the client. If you specified default values for any arguments and the client did not
* explicitly pass *any* value (including null) for those arguments then you will see the defaults here.
* passed by the client. If you specified default values for any arguments and the client did not
* explicitly pass *any* value (including null) for those arguments then you will see the defaults here.
*
* Note that thanks to [Nexus' reflection system](https://nxs.li/guides/reflection) this parameter's type
* will always be type safe.
* Note that thanks to [Nexus' reflection system](https://nxs.li/guides/reflection) this parameter's type
* will always be type safe.
* @param context The context data for this request.
*
* The context data is typically a singleton scoped to the lifecycle of the request. This means created at
* the beginning of a request and then passed to all the resolvers that execute while resolving the
* request. It is often used to store information like the current user making the request. Nexus is not
* responsible for this however. That is typically something you'll do with e.g.
* [Mercurius](https://mercurius.dev) or [Apollo
* Server](https://apollographql.com/docs/apollo-server/api/apollo-server).
* The context data is typically a singleton scoped to the lifecycle of the request. This means created at
* the beginning of a request and then passed to all the resolvers that execute while resolving the
* request. It is often used to store information like the current user making the request. Nexus is
* not responsible for this however. That is typically something you'll do with e.g.
* [Mercurius](https://mercurius.dev) or [Apollo
* Server](https://apollographql.com/docs/apollo-server/api/apollo-server).
*
* Note that the type here will be whatever you have specified for "contextType" in your makeSchema configuration.
* Note that the type here will be whatever you have specified for "contextType" in your makeSchema configuration.
* @param info The GraphQL resolve info.
*
* This is an advanced parameter seldom used. It includes things like the AST of the [GraphQL
* document](https://spec.graphql.org/June2018/#sec-Language.Document) sent by the client.
* This is an advanced parameter seldom used. It includes things like the AST of the [GraphQL
* document](https://spec.graphql.org/June2018/#sec-Language.Document) sent by the client.
*/
resolve?: FieldResolver<TypeName, FieldName>
}
@ -487,17 +528,15 @@ export class OutputDefinitionBlock<TypeName extends string> {
*
* @param name The name of this field. Must conform to the regex pattern: [_A-Za-z][_0-9A-Za-z]*
* @param config The configuration for things like the field's type, its description, its arguments, its
* resolver, and more. See jsdoc on each field within for details.
* resolver, and more. See jsdoc on each field within for details.
*
* This parameter is optional if no resolver is required. No resolver is required if the [source
* typing](https://nxs.li/guides/backing-types):
* This parameter is optional if no resolver is required. No resolver is required if the [source
* typing](https://nxs.li/guides/backing-types):
*
* 1. Has a field whose name matches this one
* 2. And whose type is compatible
* 3. And is a scalar
* 1. Has a field whose name matches this one 2. And whose type is compatible 3. And is a scalar
*
* ...in which case the default resolver will be available whose behaviour is to simply return that field
* from the received source type.
* ...in which case the default resolver will be available whose behaviour is to simply return that field
* from the received source type.
*/
boolean<FieldName extends string>(name: FieldName, ...config: ScalarOutSpread<TypeName, FieldName>) {
this.addScalarField(name, 'Boolean', config)
@ -527,17 +566,15 @@ export class OutputDefinitionBlock<TypeName extends string> {
*
* @param name The name of this field. Must conform to the regex pattern: [_A-Za-z][_0-9A-Za-z]*
* @param config The configuration for things like the field's type, its description, its arguments, its
* resolver, and more. See jsdoc on each field within for details.
* resolver, and more. See jsdoc on each field within for details.
*
* This parameter is optional if no resolver is required. No resolver is required if the [source
* typing](https://nxs.li/guides/backing-types):
* This parameter is optional if no resolver is required. No resolver is required if the [source
* typing](https://nxs.li/guides/backing-types):
*
* 1. Has a field whose name matches this one
* 2. And whose type is compatible
* 3. And is a scalar
* 1. Has a field whose name matches this one 2. And whose type is compatible 3. And is a scalar
*
* ...in which case the default resolver will be available whose behaviour is to simply return that field
* from the received source type.
* ...in which case the default resolver will be available whose behaviour is to simply return that field
* from the received source type.
*/
string<FieldName extends string>(name: FieldName, ...config: ScalarOutSpread<TypeName, FieldName>) {
this.addScalarField(name, 'String', config)
@ -568,17 +605,15 @@ export class OutputDefinitionBlock<TypeName extends string> {
*
* @param name The name of this field. Must conform to the regex pattern: [_A-Za-z][_0-9A-Za-z]*
* @param config The configuration for things like the field's type, its description, its arguments, its
* resolver, and more. See jsdoc on each field within for details.
* resolver, and more. See jsdoc on each field within for details.
*
* This parameter is optional if no resolver is required. No resolver is required if the [source
* typing](https://nxs.li/guides/backing-types):
* This parameter is optional if no resolver is required. No resolver is required if the [source
* typing](https://nxs.li/guides/backing-types):
*
* 1. Has a field whose name matches this one
* 2. And whose type is compatible
* 3. And is a scalar
* 1. Has a field whose name matches this one 2. And whose type is compatible 3. And is a scalar
*
* ...in which case the default resolver will be available whose behaviour is to simply return that field
* from the received source type.
* ...in which case the default resolver will be available whose behaviour is to simply return that field
* from the received source type.
*/
id<FieldName extends string>(name: FieldName, ...config: ScalarOutSpread<TypeName, FieldName>) {
this.addScalarField(name, 'ID', config)
@ -607,17 +642,15 @@ export class OutputDefinitionBlock<TypeName extends string> {
*
* @param name The name of this field. Must conform to the regex pattern: [_A-Za-z][_0-9A-Za-z]*
* @param config The configuration for things like the field's type, its description, its arguments, its
* resolver, and more. See jsdoc on each field within for details.
* resolver, and more. See jsdoc on each field within for details.
*
* This parameter is optional if no resolver is required. No resolver is required if the [source
* typing](https://nxs.li/guides/backing-types):
* This parameter is optional if no resolver is required. No resolver is required if the [source
* typing](https://nxs.li/guides/backing-types):
*
* 1. Has a field whose name matches this one
* 2. And whose type is compatible
* 3. And is a scalar
* 1. Has a field whose name matches this one 2. And whose type is compatible 3. And is a scalar
*
* ...in which case the default resolver will be available whose behaviour is to simply return that field
* from the received source type.
* ...in which case the default resolver will be available whose behaviour is to simply return that field
* from the received source type.
*/
int<FieldName extends string>(name: FieldName, ...config: ScalarOutSpread<TypeName, FieldName>) {
this.addScalarField(name, 'Int', config)
@ -629,8 +662,9 @@ export class OutputDefinitionBlock<TypeName extends string> {
* Define a field whose type is Float.
*
* Float types are [scalars](https://spec.graphql.org/June2018/#sec-Scalars) representing signed
* doubleprecision fractional values as specified by IEEE 754. They are represented in JavaScript using the
* [number primitive type](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number).
* doubleprecision fractional values as specified by IEEE 754. They are represented in JavaScript using
* the [number primitive
* type](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number).
*
* This is a shorthand, equivalent to:
*
@ -646,17 +680,15 @@ export class OutputDefinitionBlock<TypeName extends string> {
*
* @param name The name of this field. Must conform to the regex pattern: [_A-Za-z][_0-9A-Za-z]*
* @param config The configuration for things like the field's type, its description, its arguments, its
* resolver, and more. See jsdoc on each field within for details.
* resolver, and more. See jsdoc on each field within for details.
*
* This parameter is optional if no resolver is required. No resolver is required if the [source
* typing](https://nxs.li/guides/backing-types):
* This parameter is optional if no resolver is required. No resolver is required if the [source
* typing](https://nxs.li/guides/backing-types):
*
* 1. Has a field whose name matches this one
* 2. And whose type is compatible
* 3. And is a scalar
* 1. Has a field whose name matches this one 2. And whose type is compatible 3. And is a scalar
*
* ...in which case the default resolver will be available whose behaviour is to simply return that field
* from the received source type.
* ...in which case the default resolver will be available whose behaviour is to simply return that field
* from the received source type.
*/
float<FieldName extends string>(name: FieldName, ...config: ScalarOutSpread<TypeName, FieldName>) {
this.addScalarField(name, 'Float', config)
@ -685,7 +717,7 @@ export class OutputDefinitionBlock<TypeName extends string> {
*
* @param name The name of this field. Must conform to the regex pattern: [_A-Za-z][_0-9A-Za-z]*
* @param config The configuration for things like the field's type, its description, its arguments, its
* resolver, and more. See jsdoc on each field within for details.
* resolver, and more. See jsdoc on each field within for details.
*/
field<FieldName extends string>(name: FieldName, config: FieldOutConfig<TypeName, FieldName>): void
/**
@ -711,7 +743,7 @@ export class OutputDefinitionBlock<TypeName extends string> {
* })
*
* @param config The configuration for things like the field's type, its description, its arguments, its
* resolver, and more. See jsdoc on each field within for details.
* resolver, and more. See jsdoc on each field within for details.
*/
field<FieldName extends string>(config: FieldOutConfigWithName<TypeName, FieldName>): void
field<FieldName extends string>(

View File

@ -0,0 +1,230 @@
import {
ArgumentNode,
assertValidName,
astFromValue,
ASTKindToNode,
DirectiveNode,
GraphQLDirective,
GraphQLDirectiveConfig,
Kind,
} from 'graphql'
import { GetGen, GetGen2, NexusWrappedSymbol } from '../core'
import type { MaybeReadonlyArray } from '../typeHelpersInternal'
import { mapObj } from '../utils'
import type { ArgsRecord } from './args'
import { isNexusDirective, isNexusDirectiveUse } from './wrapping'
import { Maybe, NexusTypes, withNexusSymbol } from './_types'
export type Directives = MaybeReadonlyArray<NexusDirectiveDef | GraphQLDirective | NexusDirectiveUse>
export const RequestDirectiveLocation = [
/** Request Definitions */
'QUERY',
'MUTATION',
'SUBSCRIPTION',
'FIELD',
'FRAGMENT_DEFINITION',
'FRAGMENT_SPREAD',
'INLINE_FRAGMENT',
'VARIABLE_DEFINITION',
] as const
export const SchemaDirectiveLocation = [
/** Type System Definitions */
'SCHEMA',
'SCALAR',
'OBJECT',
'FIELD_DEFINITION',
'ARGUMENT_DEFINITION',
'INTERFACE',
'UNION',
'ENUM',
'ENUM_VALUE',
'INPUT_OBJECT',
'INPUT_FIELD_DEFINITION',
] as const
export type SchemaDirectiveLocationEnum = typeof SchemaDirectiveLocation[number]
export type RequestDirectiveLocationEnum = typeof RequestDirectiveLocation[number]
export interface NexusDirectiveConfig<DirectiveName extends string = string> {
/** Name of the directive */
name: DirectiveName
/** The description to annotate the GraphQL SDL */
description?: string
/** Valid locations that this directive may be used */
locations: MaybeReadonlyArray<SchemaDirectiveLocationEnum | RequestDirectiveLocationEnum>
/** Whether the directive can be repeated */
isRepeatable?: Maybe<boolean> | undefined
/**
* [GraphQL.org Docs](https://graphql.github.io/learn/schema/#arguments) | [GraphQL 2018
* Spec](https://spec.graphql.org/June2018/#sec-Language.Arguments)
*
* Define arguments for this directive.
*
* All directives in GraphQL can have arguments defined for them. Nexus provides a number of helpers for
* defining arguments. All builtin GraphQL scalar types have helpers named "{scalarName}Arg" such as
* "stringArg" and "intArg". You can also use type modifier helpers "[list](https://nxs.li/docs/api/list)"
* "[nullable](https://nxs.li/docs/api/nullable)" and "[nonNull](https://nxs.li/docs/api/nonNull)". For
* details about nonNull/nullable refer to the [nullability guide](https://nxs.li/guides/nullability).
*
* @example
* export const TestValue = directive({
* name: 'TestValue',
* description: 'Denotes the value used when testing this type',
* args: {
* type: enumType({
* name: 'TestValueType',
* members: ['String', 'Int', 'Float', 'JSON'],
* }),
* value: stringArg(),
* listLength: intArg(),
* },
* locations: ['FIELD_DEFINITION'],
* })
*/
args?: ArgsRecord
/** Data that will be added to the directive extensions field on the graphql-js type def instances */
extensions?: GraphQLDirectiveConfig['extensions']
}
export interface NexusDirectiveDef<DirectiveName extends string = string> {
(...args: MaybeArgsFor<DirectiveName>): NexusDirectiveUse<DirectiveName>
value: NexusDirectiveConfig
[NexusWrappedSymbol]: 'Directive'
}
export class NexusDirectiveUse<DirectiveName extends string = string> {
constructor(
readonly name: DirectiveName,
readonly args: MaybeArgsFor<DirectiveName>[0] | undefined,
readonly config?: NexusDirectiveConfig<DirectiveName>
) {}
}
withNexusSymbol(NexusDirectiveUse, NexusTypes.DirectiveUse)
/** Defines a directive, which can be used positionally when generating the SDL */
export function directive<DirectiveName extends string>(
config: NexusDirectiveConfig<DirectiveName>
): NexusDirectiveDef<DirectiveName> {
assertValidName(config.name)
config = Object.freeze(config)
function addDirective(...args: MaybeArgsFor<DirectiveName>) {
return new NexusDirectiveUse(config.name, args[0], config)
}
addDirective[NexusWrappedSymbol] = NexusTypes.Directive as 'Directive'
addDirective.value = config
return addDirective
}
type MaybeArgsFor<DirectiveName extends string> = GetGen2<'directiveArgs', DirectiveName> extends object
? [GetGen2<'directiveArgs', DirectiveName>]
: []
export function addDirective<DirectiveName extends GetGen<'directives', string>>(
directiveName: DirectiveName,
...args: MaybeArgsFor<DirectiveName>
) {
return new NexusDirectiveUse<DirectiveName>(directiveName, args[0])
}
const DirectiveASTKindMapping = {
SCALAR: Kind.SCALAR_TYPE_DEFINITION, // 'ScalarTypeDefinition',
SCHEMA: Kind.SCHEMA_DEFINITION, // 'SchemaDefinition',
OBJECT: Kind.OBJECT_TYPE_DEFINITION, // 'ObjectTypeDefinition',
FIELD_DEFINITION: Kind.FIELD_DEFINITION, // 'FieldDefinition',
ARGUMENT_DEFINITION: Kind.INPUT_VALUE_DEFINITION, // 'InputValueDefinition',
INTERFACE: Kind.INTERFACE_TYPE_DEFINITION, // 'InterfaceTypeDefinition',
UNION: Kind.UNION_TYPE_DEFINITION, // 'UnionTypeDefinition',
ENUM: Kind.ENUM_TYPE_DEFINITION, // 'EnumTypeDefinition',
ENUM_VALUE: Kind.ENUM_VALUE_DEFINITION, // 'EnumValueDefinition',
INPUT_OBJECT: Kind.INPUT_OBJECT_TYPE_DEFINITION, // 'InputObjectTypeDefinition',
INPUT_FIELD_DEFINITION: Kind.INPUT_VALUE_DEFINITION, // 'InputValueDefinition',
} as const
type DirectiveASTKindMapping = typeof DirectiveASTKindMapping
export type DirectiveASTKinds = keyof DirectiveASTKindMapping
/**
* Creates the ASTNode with the directives
*
* @param
*/
export function maybeAddDirectiveUses<
Kind extends DirectiveASTKinds,
Result extends { astNode: ASTKindToNode[DirectiveASTKindMapping[Kind]] }
>(
kind: Kind,
directiveUses: Directives | undefined,
customDirectives: Record<string, GraphQLDirective>
): Result | undefined {
if (!directiveUses?.length) {
return undefined
}
const seenDirectives = new Set<string>()
return {
astNode: {
kind: DirectiveASTKindMapping[kind],
directives: Array.from(directiveUses).map((d): DirectiveNode => {
const directiveName = isNexusDirective(d) ? d.value.name : d.name
const directiveDef = customDirectives[directiveName]
if (seenDirectives.has(directiveName) && !directiveDef.isRepeatable) {
throw new Error(`Cannot use directive ${directiveName} more than once in a row`)
}
assertValidDirectiveFor(kind, directiveDef)
seenDirectives.add(directiveName)
const args = isNexusDirectiveUse(d) ? directiveArgs(d, directiveDef) : undefined
return {
kind: Kind.DIRECTIVE,
name: {
kind: Kind.NAME,
value: directiveName,
},
arguments: args,
}
}),
},
} as any
}
function assertValidDirectiveFor(
kind: DirectiveASTKinds,
directiveDef: GraphQLDirective & { locations: readonly any[] } // any is a hack to make this work w/ v15 & 16
) {
if (!directiveDef.locations.includes(kind)) {
throw new Error(`Directive ${directiveDef.name} cannot be applied to ${kind}`)
}
}
function directiveArgs(
directiveUse: NexusDirectiveUse,
directiveDef: GraphQLDirective
): ReadonlyArray<ArgumentNode> {
return mapObj(directiveUse.args ?? {}, (val, key) => {
const arg = directiveDef.args.find((a) => a.name === key)
if (!arg) {
throw new Error(`Unknown directive arg ${key}, expected one of ${directiveDef.args.map((a) => a.name)}`)
}
const value = astFromValue(val, arg.type)
if (!value) {
throw new Error(`Unable to get ast for ${key}`)
}
return {
kind: Kind.ARGUMENT,
name: {
kind: Kind.NAME,
value: key,
},
value,
}
})
}

View File

@ -1,6 +1,7 @@
import { assertValidName, GraphQLEnumTypeConfig, GraphQLEnumValueConfig } from 'graphql'
import { arg, NexusArgDef, NexusAsArgConfig } from './args'
import { NexusTypes, SourceTypingDef, withNexusSymbol } from './_types'
import type { Directives } from './directive'
import { Maybe, NexusTypes, SourceTypingDef, withNexusSymbol } from './_types'
type TypeScriptEnumLike = {
[key: number]: string
@ -12,24 +13,31 @@ export interface EnumMemberInfo {
/** The internal representation of the enum */
value?: string | number | object | boolean
/** The description to annotate the GraphQL SDL */
description?: string
description?: Maybe<string>
/**
* Info about a field deprecation. Formatted as a string and provided with the deprecated directive on
* field/enum types and as a comment on input fields.
*/
deprecation?: string // | DeprecationInfo;
deprecation?: Maybe<string> // | DeprecationInfo;
/**
* Custom extensions, as supported in graphql-js
*
* @see https://github.com/graphql/graphql-js/issues/1527
*/
extensions?: GraphQLEnumValueConfig['extensions']
/**
* A list of directives / directive uses (with args) for the enum member definition
*
* @example
* directives: [addDirective('ExampleDirective', { arg: true })]
*/
directives?: Directives
}
export interface NexusEnumTypeConfig<TypeName extends string> {
name: TypeName
/** The description to annotate the GraphQL SDL */
description?: string
description?: Maybe<string>
/** Source type information for this type */
sourceType?: SourceTypingDef
/** All members of the enum, either as an array of strings/definition objects, as an object, or as a TypeScript enum */
@ -43,6 +51,15 @@ export interface NexusEnumTypeConfig<TypeName extends string> {
* @see https://github.com/graphql/graphql-js/issues/1527
*/
extensions?: GraphQLEnumTypeConfig['extensions']
/**
* A list of directives / directive uses (with args) for the enum type definition
*
* @example
* directives: [addDirective('ExampleDirective', { arg: true })]
*/
directives?: Directives
/** Adds this type as a method on the Object/Interface definition blocks */
asNexusMethod?: string
}
export class NexusEnumTypeDef<TypeName extends string> {

View File

@ -1,7 +1,8 @@
import { assertValidName, GraphQLInputObjectTypeConfig } from 'graphql'
import { arg, NexusArgDef, NexusAsArgConfig } from './args'
import type { InputDefinitionBlock } from './definitionBlocks'
import { NexusTypes, NonNullConfig, withNexusSymbol } from './_types'
import type { Directives } from './directive'
import { Maybe, NexusTypes, NonNullConfig, withNexusSymbol } from './_types'
export type NexusInputObjectTypeConfig<TypeName extends string> = {
/** Name of the input object type */
@ -9,7 +10,7 @@ export type NexusInputObjectTypeConfig<TypeName extends string> = {
/** Definition block for the input type */
definition(t: InputDefinitionBlock<TypeName>): void
/** The description to annotate the GraphQL SDL */
description?: string
description?: Maybe<string>
/**
* Configures the nullability for the type, check the documentation's "Getting Started" section to learn
* more about GraphQL Nexus's assumptions and configuration on nullability.
@ -21,6 +22,15 @@ export type NexusInputObjectTypeConfig<TypeName extends string> = {
* @see https://github.com/graphql/graphql-js/issues/1527
*/
extensions?: GraphQLInputObjectTypeConfig['extensions']
/**
* A list of directives / directive uses (with args) for the input object type definition
*
* @example
* directives: [addDirective('ExampleDirective', { arg: true })]
*/
directives?: Directives
/** Adds this type as a method on the Object/Interface definition blocks */
asNexusMethod?: string
} & NexusGenPluginInputTypeConfig<TypeName>
export class NexusInputObjectTypeDef<TypeName extends string> {

View File

@ -2,18 +2,19 @@ import { assertValidName, GraphQLInterfaceTypeConfig } from 'graphql'
import type { FieldResolver, GetGen, InterfaceFieldsFor, ModificationType } from '../typegenTypeHelpers'
import type { ArgsRecord } from './args'
import { OutputDefinitionBlock, OutputDefinitionBuilder } from './definitionBlocks'
import { AbstractTypes, NexusTypes, NonNullConfig, SourceTypingDef, withNexusSymbol } from './_types'
import type { Directives } from './directive'
import { AbstractTypes, Maybe, NexusTypes, NonNullConfig, SourceTypingDef, withNexusSymbol } from './_types'
export type Implemented = GetGen<'interfaceNames'> | NexusInterfaceTypeDef<any>
export interface FieldModification<TypeName extends string, FieldName extends string> {
type?: ModificationType<TypeName, FieldName>
/** The description to annotate the GraphQL SDL */
description?: string
description?: Maybe<string>
/** The resolve method we should be resolving the field with */
resolve?: FieldResolver<TypeName, FieldName>
/** You are allowed to add non-required args when modifying a field */
args?: ArgsRecord
args?: Maybe<ArgsRecord>
/**
* Custom extensions, as supported in graphql-js
*
@ -44,7 +45,7 @@ export type NexusInterfaceTypeConfig<TypeName extends string> = {
*/
nonNullDefaults?: NonNullConfig
/** The description to annotate the GraphQL SDL */
description?: string
description?: Maybe<string>
/** Source type information for this type */
sourceType?: SourceTypingDef
/**
@ -53,6 +54,15 @@ export type NexusInterfaceTypeConfig<TypeName extends string> = {
* @see https://github.com/graphql/graphql-js/issues/1527
*/
extensions?: GraphQLInterfaceTypeConfig<any, any>['extensions']
/**
* A list of directives / directive uses (with args) for the output field definition
*
* @example
* directives: [addDirective('ExampleDirective', { arg: true })]
*/
directives?: Directives
/** Adds this type as a method on the Object/Interface definition blocks */
asNexusMethod?: string
} & AbstractTypes.MaybeTypeDefConfigFieldResolveType<TypeName>
export interface InterfaceDefinitionBuilder<TypeName extends string> extends OutputDefinitionBuilder {

View File

@ -1,11 +1,7 @@
import { isType } from 'graphql'
import { isNexusMeta } from './nexusMeta'
import { AllNamedTypeDefs, isNexusStruct, NexusListableTypes } from './wrapping'
import { isNexusStruct, NexusListableTypes } from './wrapping'
import { NexusTypes, withNexusSymbol } from './_types'
/** List() */
export type NexusListDefConfig<TypeName extends AllNamedTypeDefs> = {
type: TypeName
}
export class NexusListDef<TypeName extends NexusListableTypes> {
// @ts-ignore

View File

@ -1,4 +1,4 @@
import type { FieldOutConfig, OutputDefinitionBlock } from '../core'
import type { FieldOutConfig, OutputDefinitionBlock } from './definitionBlocks'
import { extendType, NexusExtendTypeDef } from './extendType'
export type MutationFieldConfig<FieldName extends string> =
@ -115,7 +115,7 @@ export function mutationField(
* })
*
* @param name The name of the field on the Mutation type. Names are casesensitive and must conform to
* pattern: `[_A-Za-z][_0-9A-Za-z]*`
* pattern: `[_A-Za-z][_0-9A-Za-z]*`
* @param config The same type of configuration you would pass to t.field("...", config)
*/
export function mutationField<FieldName extends string>(

View File

@ -28,7 +28,7 @@ export type NexusMetaBuild = {
export type NexusMeta = NexusMetaType | NexusMetaBuild
export function isNexusMetaBuild(obj: any): obj is NexusMetaBuild {
return obj && typeof ownProp.get(obj, NEXUS_BUILD) === 'function'
return Boolean(obj && typeof ownProp.get(obj, NEXUS_BUILD) === 'function')
}
export function isNexusMetaType(obj: any): obj is NexusMetaType {
@ -36,11 +36,11 @@ export function isNexusMetaType(obj: any): obj is NexusMetaType {
}
export function isNexusMetaTypeProp(obj: any): obj is NexusMetaTypeProp {
return ownProp.has(obj, NEXUS_TYPE) && isNexusStruct(ownProp.get(obj, NEXUS_TYPE))
return Boolean(obj && ownProp.has(obj, NEXUS_TYPE) && isNexusStruct(ownProp.get(obj, NEXUS_TYPE)))
}
export function isNexusMetaTypeFn(obj: any): obj is NexusMetaTypeFn {
return ownProp.has(obj, NEXUS_TYPE) && typeof ownProp.get(obj, NEXUS_TYPE) === 'function'
return Boolean(obj && ownProp.has(obj, NEXUS_TYPE) && typeof ownProp.get(obj, NEXUS_TYPE) === 'function')
}
export function isNexusMeta(obj: any): obj is NexusMetaBuild | NexusMetaTypeFn | NexusMetaType {

View File

@ -1,8 +1,9 @@
import { assertValidName, GraphQLObjectType } from 'graphql'
import type { InterfaceFieldsFor } from '../typegenTypeHelpers'
import { OutputDefinitionBlock, OutputDefinitionBuilder } from './definitionBlocks'
import type { Directives } from './directive'
import type { FieldModification, FieldModificationDef, Implemented } from './interfaceType'
import { AbstractTypes, NexusTypes, NonNullConfig, SourceTypingDef, withNexusSymbol } from './_types'
import { AbstractTypes, Maybe, NexusTypes, NonNullConfig, SourceTypingDef, withNexusSymbol } from './_types'
export interface ObjectDefinitionBuilder extends OutputDefinitionBuilder {
addInterfaces(toAdd: Implemented[]): void
@ -102,7 +103,7 @@ export type NexusObjectTypeConfig<TypeName extends string> = {
* // # ...
* // }
*/
description?: string
description?: Maybe<string>
/**
* [Source Types Guide](https://nxs.li/guides/backing-types)
*
@ -118,8 +119,8 @@ export type NexusObjectTypeConfig<TypeName extends string> = {
*
* @example
* {
* "module": "some-package",
* "export": "User"
* "module": "some-package",
* "export": "User"
* }
*
* @example
@ -162,12 +163,12 @@ export type NexusObjectTypeConfig<TypeName extends string> = {
* Define the fields of your object type.
*
* This method receives a type builder api that you will use to define the fields of your object type
* within. You can leverage conditionals, loops, other functions (that take the builder api as an argument),
* pull in variables from higher scopes, and so on, to help define your fields. However avoid two things:
* within. You can leverage conditionals, loops, other functions (that take the builder api as an
* argument), pull in variables from higher scopes, and so on, to help define your fields. However avoid two things:
*
* 1. Doing asynchronous work when defining fields.
* 2. Triggering side-effects that you would NOT want run at *build* timeas this code will run during build
* to support [Nexus' reflection system](https://nxs.li/guides/reflection).
* 1. Doing asynchronous work when defining fields. 2. Triggering side-effects that you would NOT want run
* at *build* timeas this code will run during build
* to support [Nexus' reflection system](https://nxs.li/guides/reflection).
*
* @example
* objectType({
@ -185,10 +186,19 @@ export type NexusObjectTypeConfig<TypeName extends string> = {
* })
*
* @param t The type builder API for object types. The primary method you'll find is "t.field" but there are
* many convenient shorthands available as well, plus anything plugins have added. Explore each one's
* jsDoc for more detail.
* many convenient shorthands available as well, plus anything plugins have added. Explore each one's
* jsDoc for more detail.
*/
definition(t: ObjectDefinitionBlock<TypeName>): void
/**
* A list of directives / directive uses (with args) for the object type definition
*
* @example
* directives: [addDirective('ExampleDirective', { arg: true })]
*/
directives?: Directives
/** Adds this type as a method on the Object/Interface definition blocks */
asNexusMethod?: string
} & AbstractTypes.MaybeTypeDefConfigFieldIsTypeOf<TypeName> &
NexusGenPluginTypeConfig<TypeName>

View File

@ -1,4 +1,4 @@
import type { FieldOutConfig, OutputDefinitionBlock } from '../core'
import type { FieldOutConfig, OutputDefinitionBlock } from './definitionBlocks'
import { extendType, NexusExtendTypeDef } from './extendType'
export type QueryFieldConfig<FieldName extends string> =
@ -101,7 +101,7 @@ export function queryField(
* })
*
* @param name The name of the field on the Query type. Names are casesensitive and must conform to pattern:
* `[_A-Za-z][_0-9A-Za-z]*`
* `[_A-Za-z][_0-9A-Za-z]*`
* @param config The same type of configuration you would pass to t.field("...", config)
*/
export function queryField<FieldName extends string>(

View File

@ -1,6 +1,8 @@
import { assertValidName, GraphQLScalarType, GraphQLScalarTypeConfig } from 'graphql'
import { assertValidName, GraphQLNamedType, GraphQLScalarTypeConfig } from 'graphql'
import type { AllNexusInputTypeDefs, AllNexusOutputTypeDefs } from '../core'
import { decorateType } from './decorateType'
import { NexusTypes, SourceTypingDef, withNexusSymbol } from './_types'
import type { Directives } from './directive'
import { GraphQLNamedOutputType, Maybe, NexusTypes, SourceTypingDef, withNexusSymbol } from './_types'
export interface ScalarBase
extends Pick<
@ -10,7 +12,7 @@ export interface ScalarBase
export interface ScalarConfig {
/** Any deprecation info for this scalar type */
deprecation?: string // | DeprecationInfo;
deprecation?: Maybe<string> // | DeprecationInfo;
/** Adds this type as a method on the Object/Interface definition blocks */
asNexusMethod?: string
/** Source type information for this type */
@ -21,6 +23,13 @@ export interface ScalarConfig {
* @see https://github.com/graphql/graphql-js/issues/1527
*/
extensions?: GraphQLScalarTypeConfig<any, any>['extensions']
/**
* A list of directives / directive uses (with args) for the scalar type definition
*
* @example
* directives: [addDirective('ExampleDirective', { arg: true })]
*/
directives?: Directives
}
export interface NexusScalarTypeConfig<T extends string> extends ScalarBase, ScalarConfig {
@ -43,13 +52,13 @@ export function scalarType<TypeName extends string>(options: NexusScalarTypeConf
return new NexusScalarTypeDef(options.name, options)
}
export function asNexusMethod<T extends GraphQLScalarType>(
scalar: T,
export function asNexusMethod<T extends GraphQLNamedType>(
namedType: T,
methodName: string,
sourceType?: SourceTypingDef
): T {
return decorateType(scalar, {
): T extends GraphQLNamedOutputType ? AllNexusOutputTypeDefs : AllNexusInputTypeDefs {
return decorateType(namedType, {
asNexusMethod: methodName,
sourceType,
})
}) as any
}

View File

@ -1,7 +1,8 @@
import { assertValidName, GraphQLUnionTypeConfig } from 'graphql'
import type { Directives } from '../core'
import type { GetGen } from '../typegenTypeHelpers'
import type { NexusObjectTypeDef } from './objectType'
import { AbstractTypes, NexusTypes, SourceTypingDef, withNexusSymbol } from './_types'
import { AbstractTypes, Maybe, NexusTypes, SourceTypingDef, withNexusSymbol } from './_types'
export interface UnionDefinitionBuilder {
typeName: string
@ -27,12 +28,12 @@ export type NexusUnionTypeConfig<TypeName extends string> = {
/** Builds the definition for the union */
definition(t: UnionDefinitionBlock): void
/** The description to annotate the GraphQL SDL */
description?: string
description?: Maybe<string>
/**
* Info about a field deprecation. Formatted as a string and provided with the deprecated directive on
* field/enum types and as a comment on input fields.
*/
deprecation?: string // | DeprecationInfo;
deprecation?: Maybe<string> // | DeprecationInfo;
/** Source type information for this type */
sourceType?: SourceTypingDef
/**
@ -41,6 +42,15 @@ export type NexusUnionTypeConfig<TypeName extends string> = {
* @see https://github.com/graphql/graphql-js/issues/1527
*/
extensions?: GraphQLUnionTypeConfig<any, any>['extensions']
/**
* A list of directives / directive uses (with args) for the union type definition
*
* @example
* directives: [addDirective('ExampleDirective', { arg: true })]
*/
directives?: Directives
/** Adds this type as a method on the Object/Interface definition blocks */
asNexusMethod?: string
} & AbstractTypes.MaybeTypeDefConfigFieldResolveType<TypeName>
export class NexusUnionTypeDef<TypeName extends string> {

View File

@ -27,21 +27,30 @@ import type { NexusScalarTypeDef } from './scalarType'
import { isNexusMetaType, NexusMetaType, resolveNexusMetaType } from './nexusMeta'
import type { NexusUnionTypeDef } from './unionType'
import { NexusTypes, NexusWrappedSymbol } from './_types'
import type { NexusDirectiveDef } from './directive'
import type { NexusDirectiveUse } from '../core'
/** Input(named): Nexus only */
export type AllNexusNamedInputTypeDefs<T extends string = any> =
| NexusInputObjectTypeDef<T>
| NexusEnumTypeDef<T>
| NexusScalarTypeDef<T>
/** Input(named): Nexus + GraphQLInput */
export type AllNamedInputTypeDefs<T extends string = any> =
| AllNexusNamedInputTypeDefs<T>
| Exclude<GraphQLInputType, GraphQLList<any> | GraphQLNonNull<any>>
/** Input(all): Nexus + GraphQL */
export type AllNexusInputTypeDefs<T extends string = any> =
| AllNexusNamedInputTypeDefs<T>
| AllNamedInputTypeDefs<T>
| NexusListDef<any>
| NexusNonNullDef<any>
| NexusNullDef<any>
| GraphQLList<any>
| GraphQLNonNull<any>
/** Output(named): Nexus only */
export type AllNexusNamedOutputTypeDefs =
| NexusObjectTypeDef<any>
| NexusInterfaceTypeDef<any>
@ -49,17 +58,25 @@ export type AllNexusNamedOutputTypeDefs =
| NexusEnumTypeDef<any>
| NexusScalarTypeDef<any>
/** Output(all): Nexus only */
export type AllNexusOutputTypeDefs =
| AllNexusNamedOutputTypeDefs
| NexusListDef<any>
| NexusNonNullDef<any>
| NexusNullDef<any>
/** Input + output(named): Nexus only */
export type AllNexusNamedTypeDefs = AllNexusNamedInputTypeDefs | AllNexusNamedOutputTypeDefs
/** Input + output(all): Nexus only */
export type AllNexusTypeDefs = AllNexusOutputTypeDefs | AllNexusInputTypeDefs
/** Input + output(all): Nexus only + Name */
export type AllNamedTypeDefs = AllNexusNamedTypeDefs | GraphQLNamedType
/** All inputs to list(...) */
export type NexusListableTypes =
| GetGen<'allNamedTypes', string>
| AllNamedTypeDefs
| NexusArgDef<any>
| NexusListDef<NexusListableTypes>
@ -68,24 +85,26 @@ export type NexusListableTypes =
| GraphQLType
| NexusMetaType
/** All inputs to nonNull(...) */
export type NexusNonNullableTypes =
| GetGen<'allNamedTypes', string>
| AllNamedTypeDefs
| NexusListDef<NexusListableTypes>
| NexusArgDef<any>
| NexusMetaType
/** All inputs to nullable(...) */
export type NexusNullableTypes =
| GetGen<'allNamedTypes', string>
| AllNamedTypeDefs
| NexusListDef<NexusListableTypes>
| NexusArgDef<any>
| NexusMetaType
export type AllNamedTypeDefs = GetGen<'allNamedTypes', string> | AllNexusNamedTypeDefs
export type AllNexusNamedArgsDefs<T extends AllInputTypes = AllInputTypes> =
| T
| NexusArgDef<T>
| AllNexusNamedInputTypeDefs<T>
| AllNamedInputTypeDefs<T>
| GraphQLInputType
export type AllNexusArgsDefs =
@ -162,6 +181,13 @@ export function isNexusArgDef(obj: any): obj is NexusArgDef<AllInputTypes> {
return isNexusStruct(obj) && obj[NexusWrappedSymbol] === NexusTypes.Arg
}
export function isNexusNamedOuputTypeDef(obj: any): obj is AllNexusNamedOutputTypeDefs {
return isNexusNamedTypeDef(obj) && !isNexusInputObjectTypeDef(obj)
}
export function isNexusNamedInputTypeDef(obj: any): obj is AllNexusNamedInputTypeDefs {
return isNexusNamedTypeDef(obj) && !isNexusObjectTypeDef(obj) && !isNexusInterfaceTypeDef(obj)
}
export function isNexusDynamicOutputProperty<T extends string>(obj: any): obj is DynamicOutputPropertyDef<T> {
return isNexusStruct(obj) && obj[NexusWrappedSymbol] === NexusTypes.DynamicOutputProperty
}
@ -182,6 +208,13 @@ export function isNexusPlugin(obj: any): obj is NexusPlugin {
return isNexusStruct(obj) && obj[NexusWrappedSymbol] === NexusTypes.Plugin
}
export function isNexusDirective(obj: any): obj is NexusDirectiveDef {
return isNexusStruct(obj) && obj[NexusWrappedSymbol] === NexusTypes.Directive
}
export function isNexusDirectiveUse(obj: any): obj is NexusDirectiveUse {
return isNexusStruct(obj) && obj[NexusWrappedSymbol] === NexusTypes.DirectiveUse
}
export type NexusWrapKind = 'NonNull' | 'Null' | 'List'
export type NexusFinalWrapKind = 'NonNull' | 'List'
@ -246,10 +279,10 @@ export function rewrapAsGraphQLType(baseType: GraphQLNamedType, wrapping: NexusF
let finalType: GraphQLType = baseType
wrapping.forEach((wrap) => {
if (wrap === 'List') {
finalType = GraphQLList(finalType)
finalType = new GraphQLList(finalType)
} else if (wrap === 'NonNull') {
if (!isNonNullType(finalType)) {
finalType = GraphQLNonNull(finalType)
finalType = new GraphQLNonNull(finalType)
}
} else {
throw new Unreachable(wrap)

View File

@ -1,10 +1,20 @@
import { defaultFieldResolver, GraphQLNamedType } from 'graphql'
import type { DynamicFieldDefs, SchemaConfig } from './builder'
import type { SourceTypingDef, SourceTypings } from './definitions/_types'
import type { SourceTypings } from './definitions/_types'
import type { NexusOutputFieldConfig } from './definitions/definitionBlocks'
import type { NexusInputObjectTypeConfig } from './definitions/inputObjectType'
import type { NexusInterfaceTypeConfig } from './definitions/interfaceType'
import type { NexusObjectTypeConfig } from './definitions/objectType'
import type { Directives, FieldSourceType, NamedFieldSourceType } from './core'
/** @internal */
export function hasNexusExtension(val: any): val is any {
return Boolean(val)
}
export function isNexusFieldExtension(val: any): val is NexusFieldExtension {
return Boolean(val?._type === 'NexusFieldExtension')
}
export type NexusGraphQLNamedType = GraphQLNamedType & {
extensions?: {
@ -18,13 +28,17 @@ export type NexusTypeExtensions = NexusObjectTypeExtension | NexusInterfaceTypeE
/** Container object living on `fieldDefinition.extensions.nexus` */
export class NexusFieldExtension<TypeName extends string = any, FieldName extends string = any> {
readonly _type = 'NexusFieldExtension' as const
readonly config: Omit<NexusOutputFieldConfig<TypeName, FieldName>, 'resolve'>
/** Whether the user has provided a custom "resolve" function, or whether we're using GraphQL's defaultResolver */
readonly hasDefinedResolver: boolean
readonly sourceType: string | FieldSourceType | NamedFieldSourceType[] | undefined
constructor(config: NexusOutputFieldConfig<TypeName, FieldName>) {
const { resolve, ...rest } = config
this.config = rest
this.hasDefinedResolver = Boolean(resolve && resolve !== defaultFieldResolver)
this.sourceType = rest.sourceType
}
/** Called when there are modifications on the interface fields */
modify(modifications: Partial<NexusOutputFieldConfig<any, any>>) {
@ -34,6 +48,7 @@ export class NexusFieldExtension<TypeName extends string = any, FieldName extend
/** Container object living on `inputObjectType.extensions.nexus` */
export class NexusInputObjectTypeExtension<TypeName extends string = any> {
readonly _type = 'NexusInputObjectTypeExtension' as const
readonly config: Omit<NexusInputObjectTypeConfig<TypeName>, 'definition'>
constructor(config: NexusInputObjectTypeConfig<TypeName>) {
const { definition, ...rest } = config
@ -43,6 +58,7 @@ export class NexusInputObjectTypeExtension<TypeName extends string = any> {
/** Container object living on `objectType.extensions.nexus` */
export class NexusObjectTypeExtension<TypeName extends string = any> {
readonly _type = 'NexusObjectTypeExtension' as const
readonly config: Omit<NexusObjectTypeConfig<TypeName>, 'definition' | 'isTypeOf'>
constructor(config: NexusObjectTypeConfig<TypeName>) {
const { definition, ...rest } = config
@ -52,6 +68,7 @@ export class NexusObjectTypeExtension<TypeName extends string = any> {
/** Container object living on `interfaceType.extensions.nexus` */
export class NexusInterfaceTypeExtension<TypeName extends string = any> {
readonly _type = 'NexusInterfaceTypeExtension' as const
readonly config: Omit<NexusInterfaceTypeConfig<TypeName>, 'definition' | 'resolveType'>
constructor(config: NexusInterfaceTypeConfig<TypeName>) {
const { definition, ...rest } = config
@ -61,7 +78,8 @@ export class NexusInterfaceTypeExtension<TypeName extends string = any> {
export interface NexusSchemaExtensionConfig extends Omit<SchemaConfig, 'types'> {
dynamicFields: DynamicFieldDefs
rootTypings: SourceTypings
sourceTypings: SourceTypings
schemaDirectives?: Directives
}
/**
@ -71,10 +89,3 @@ export interface NexusSchemaExtensionConfig extends Omit<SchemaConfig, 'types'>
export class NexusSchemaExtension {
constructor(readonly config: NexusSchemaExtensionConfig) {}
}
export type NexusScalarExtensions = {
nexus: {
asNexusMethod?: string
sourceType?: SourceTypingDef
}
}

219
src/graphqlInternal.ts Normal file
View File

@ -0,0 +1,219 @@
const MAX_ARRAY_LENGTH = 10
const MAX_RECURSIVE_DEPTH = 2
/** Used to print values in error messages. */
export function inspect(value: unknown): string {
return formatValue(value, [])
}
function formatValue(value: unknown, seenValues: ReadonlyArray<unknown>): string {
switch (typeof value) {
case 'string':
return JSON.stringify(value)
case 'function':
return value.name ? `[function ${value.name}]` : '[function]'
case 'object':
return formatObjectValue(value, seenValues)
default:
return String(value)
}
}
function formatObjectValue(value: object | null, previouslySeenValues: ReadonlyArray<unknown>): string {
if (value === null) {
return 'null'
}
if (previouslySeenValues.includes(value)) {
return '[Circular]'
}
const seenValues = [...previouslySeenValues, value]
if (isJSONable(value)) {
const jsonValue = value.toJSON()
// check for infinite recursion
if (jsonValue !== value) {
return typeof jsonValue === 'string' ? jsonValue : formatValue(jsonValue, seenValues)
}
} else if (Array.isArray(value)) {
return formatArray(value, seenValues)
}
return formatObject(value, seenValues)
}
function isJSONable(value: any): value is { toJSON: () => unknown } {
return typeof value.toJSON === 'function'
}
function formatObject(object: object, seenValues: ReadonlyArray<unknown>): string {
const entries = Object.entries(object)
if (entries.length === 0) {
return '{}'
}
if (seenValues.length > MAX_RECURSIVE_DEPTH) {
return '[' + getObjectTag(object) + ']'
}
const properties = entries.map(([key, value]) => key + ': ' + formatValue(value, seenValues))
return '{ ' + properties.join(', ') + ' }'
}
function formatArray(array: ReadonlyArray<unknown>, seenValues: ReadonlyArray<unknown>): string {
if (array.length === 0) {
return '[]'
}
if (seenValues.length > MAX_RECURSIVE_DEPTH) {
return '[Array]'
}
const len = Math.min(MAX_ARRAY_LENGTH, array.length)
const remaining = array.length - len
const items = []
for (let i = 0; i < len; ++i) {
items.push(formatValue(array[i], seenValues))
}
if (remaining === 1) {
items.push('... 1 more item')
} else if (remaining > 1) {
items.push(`... ${remaining} more items`)
}
return '[' + items.join(', ') + ']'
}
function getObjectTag(object: object): string {
const tag = Object.prototype.toString
.call(object)
.replace(/^\[object /, '')
.replace(/]$/, '')
if (tag === 'Object' && typeof object.constructor === 'function') {
const name = object.constructor.name
if (typeof name === 'string' && name !== '') {
return name
}
}
return tag
}
export function invariant(condition: unknown, message?: string): asserts condition {
const booleanCondition = Boolean(condition)
// istanbul ignore else (See transformation done in './resources/inlineInvariant.js')
if (!booleanCondition) {
throw new Error(message != null ? message : 'Unexpected invariant triggered.')
}
}
/**
* Produces the value of a block string from its parsed raw value, similar to CoffeeScript's block string,
* Python's docstring trim or Ruby's strip_heredoc.
*
* This implements the GraphQL spec's BlockStringValue() static algorithm.
*
* @internal
*/
export function dedentBlockStringValue(rawString: string): string {
// Expand a block string's raw value into independent lines.
const lines = rawString.split(/\r\n|[\n\r]/g)
// Remove common indentation from all lines but first.
const commonIndent = getBlockStringIndentation(rawString)
if (commonIndent !== 0) {
for (let i = 1; i < lines.length; i++) {
lines[i] = lines[i].slice(commonIndent)
}
}
// Remove leading and trailing blank lines.
let startLine = 0
while (startLine < lines.length && isBlank(lines[startLine])) {
++startLine
}
let endLine = lines.length
while (endLine > startLine && isBlank(lines[endLine - 1])) {
--endLine
}
// Return a string of the lines joined with U+000A.
return lines.slice(startLine, endLine).join('\n')
}
function isBlank(str: string): boolean {
for (let i = 0; i < str.length; ++i) {
if (str[i] !== ' ' && str[i] !== '\t') {
return false
}
}
return true
}
/** @internal */
export function getBlockStringIndentation(value: string): number {
let isFirstLine = true
let isEmptyLine = true
let indent = 0
let commonIndent = null
for (let i = 0; i < value.length; ++i) {
switch (value.charCodeAt(i)) {
case 13: // \r
if (value.charCodeAt(i + 1) === 10) {
++i // skip \r\n as one symbol
}
// falls through
case 10: // \n
isFirstLine = false
isEmptyLine = true
indent = 0
break
case 9: // \t
case 32: // <space>
++indent
break
default:
if (isEmptyLine && !isFirstLine && (commonIndent === null || indent < commonIndent)) {
commonIndent = indent
}
isEmptyLine = false
}
}
return commonIndent ?? 0
}
/**
* Print a block string in the indented block form by adding a leading and trailing blank line. However, if a
* block string starts with whitespace and is a single-line, adding a leading blank line would strip that whitespace.
*
* @internal
*/
export function printBlockString(value: string, preferMultipleLines: boolean = false): string {
const isSingleLine = !value.includes('\n')
const hasLeadingSpace = value[0] === ' ' || value[0] === '\t'
const hasTrailingQuote = value[value.length - 1] === '"'
const hasTrailingSlash = value[value.length - 1] === '\\'
const printAsMultipleLines = !isSingleLine || hasTrailingQuote || hasTrailingSlash || preferMultipleLines
let result = ''
// Format a multi-line block quote to account for leading space.
if (printAsMultipleLines && !(isSingleLine && hasLeadingSpace)) {
result += '\n'
}
result += value
if (printAsMultipleLines) {
result += '\n'
}
return '"""' + result.replace(/"""/g, '\\"""') + '"""'
}

View File

@ -4,6 +4,7 @@ import * as core from './core'
// All of the Public API definitions
export { makeSchema } from './makeSchema'
export { arg, booleanArg, floatArg, idArg, intArg, stringArg } from './definitions/args'
export { directive, addDirective } from './definitions/directive'
export { decorateType } from './definitions/decorateType'
export { enumType } from './definitions/enumType'
export { extendInputType } from './definitions/extendInputType'

View File

@ -1,8 +1,16 @@
import { makeSchemaInternal, SchemaConfig } from './builder'
import { GraphQLNamedType, GraphQLSchema, isObjectType, specifiedDirectives } from 'graphql'
import { isNexusObjectTypeDef } from './definitions/wrapping'
import {
AdditionalGraphQLSchemaConfigOptions,
ConfiguredTypegen,
MakeSchemaOptions,
SchemaBuilder,
SchemaConfig,
} from './builder'
import type { NexusGraphQLSchema } from './definitions/_types'
import { TypegenMetadata } from './typegenMetadata'
import { resolveTypegenConfig } from './typegenUtils'
import { assertNoMissingTypes, runAbstractTypeRuntimeChecks } from './utils'
import { assertNoMissingTypes, objValues, runAbstractTypeRuntimeChecks } from './utils'
/**
* Defines the GraphQL schema, by combining the GraphQL types defined by the GraphQL Nexus layer or any
@ -20,10 +28,17 @@ export function makeSchema(config: SchemaConfig): NexusGraphQLSchema {
// in the optional thunk for the typegen config
const typegenPromise = new TypegenMetadata(typegenConfig).generateArtifacts(schema)
if (config.shouldExitAfterGenerateArtifacts) {
let typegenPath = '(not enabled)'
if (typegenConfig.outputs.typegen) {
typegenPath = typegenConfig.outputs.typegen.outputPath
if (typegenConfig.outputs.typegen.globalsPath) {
typegenPath += ` / ${typegenConfig.outputs.typegen.globalsPath}`
}
}
typegenPromise
.then(() => {
console.log(`Generated Artifacts:
TypeScript Types ==> ${typegenConfig.outputs.typegen || '(not enabled)'}
TypeScript Types ==> ${typegenPath}
GraphQL Schema ==> ${typegenConfig.outputs.schema || '(not enabled)'}`)
process.exit(0)
})
@ -58,19 +73,99 @@ export async function generateSchema(config: SchemaConfig): Promise<NexusGraphQL
*/
generateSchema.withArtifacts = async (
config: SchemaConfig,
typeFilePath: string | null = null
typegen: string | null | ConfiguredTypegen = null
): Promise<{
schema: NexusGraphQLSchema
schemaTypes: string
tsTypes: string
globalTypes: string | null
}> => {
const { schema, missingTypes, finalConfig } = makeSchemaInternal(config)
const typegenConfig = resolveTypegenConfig(finalConfig)
const { schemaTypes, tsTypes } = await new TypegenMetadata(typegenConfig).generateArtifactContents(
schema,
typeFilePath
)
const { schemaTypes, tsTypes, globalTypes } = await new TypegenMetadata(
typegenConfig
).generateArtifactContents(schema, typegen)
assertNoMissingTypes(schema, missingTypes)
runAbstractTypeRuntimeChecks(schema, finalConfig.features)
return { schema, schemaTypes, tsTypes }
return { schema, schemaTypes, tsTypes, globalTypes }
}
/** Builds the schema, we may return more than just the schema from this one day. */
export function makeSchemaInternal(config: SchemaConfig) {
const builder = new SchemaBuilder(config)
builder.addTypes(config.types)
builder.addTypes(config.directives)
if (config.schemaRoots) {
builder.addTypes(config.schemaRoots)
}
function getRootType(rootType: 'query' | 'mutation' | 'subscription', defaultType: string) {
const rootTypeVal = config.schemaRoots?.[rootType] ?? defaultType
let returnVal: null | GraphQLNamedType = null
if (typeof rootTypeVal === 'string') {
returnVal = typeMap[rootTypeVal]
} else if (rootTypeVal) {
if (isNexusObjectTypeDef(rootTypeVal)) {
returnVal = typeMap[rootTypeVal.name]
} else if (isObjectType(rootTypeVal)) {
returnVal = typeMap[rootTypeVal.name]
}
}
if (returnVal && !isObjectType(returnVal)) {
throw new Error(`Expected ${rootType} to be a objectType, saw ${returnVal.constructor.name}`)
}
return returnVal
}
const {
finalConfig,
typeMap,
missingTypes,
schemaExtension,
onAfterBuildFns,
customDirectives,
schemaDirectives,
} = builder.getFinalTypeMap()
const schema = new GraphQLSchema({
...extractGraphQLSchemaOptions(config),
query: getRootType('query', 'Query'),
mutation: getRootType('mutation', 'Mutation'),
subscription: getRootType('subscription', 'Subscription'),
types: objValues(typeMap),
extensions: {
...config.extensions,
nexus: schemaExtension,
},
directives: [...specifiedDirectives, ...Object.values(customDirectives)],
...schemaDirectives,
}) as NexusGraphQLSchema
onAfterBuildFns.forEach((fn) => fn(schema))
return { schema, missingTypes, finalConfig }
}
type OmittedVals = Partial<{ [K in keyof MakeSchemaOptions]: never }>
function extractGraphQLSchemaOptions(
config: SchemaConfig
): Partial<AdditionalGraphQLSchemaConfigOptions & OmittedVals> {
const {
formatTypegen,
nonNullDefaults,
mergeSchema,
outputs,
shouldExitAfterGenerateArtifacts,
shouldGenerateArtifacts,
schemaRoots,
sourceTypes,
prettierConfig,
plugins,
customPrintSchemaFn,
features,
contextType,
...graphqlConfigOpts
} = config
return graphqlConfigOpts
}

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

@ -34,7 +34,7 @@ export type CreateFieldResolverInfo<FieldExt = any, TypeExt = any> = {
parentTypeConfig: (
| Omit<NexusGraphQLObjectTypeConfig, 'fields' | 'extensions'>
| (Omit<NexusGraphQLInterfaceTypeConfig, 'fields' | 'extensions'> & {
interfaces: GraphQLInterfaceType[]
interfaces: readonly GraphQLInterfaceType[]
})
) & {
extensions?: Maybe<{ nexus?: { config: TypeExt } }>
@ -51,7 +51,7 @@ export interface PluginConfig {
/** A name for the plugin, useful for errors, etc. */
name: string
/** A description for the plugin */
description?: string
description?: Maybe<string>
/** Any type definitions we want to add to output field definitions */
fieldDefTypes?: StringLike | StringLike[]
/** Any type definitions we want to add to input field definitions */

View File

@ -494,11 +494,11 @@ export const connectionPlugin = (connectionPluginConfig?: ConnectionPluginConfig
definition(t2) {
t2.list.field('edges', {
type: edgeName as any,
description: `https://facebook.github.io/relay/graphql/connections.htm#sec-Edge-Types`,
description: `https://relay.dev/graphql/connections.htm#sec-Edge-Types`,
})
t2.nonNull.field('pageInfo', {
type: 'PageInfo' as any,
description: `https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo`,
description: `https://relay.dev/graphql/connections.htm#sec-undefined.PageInfo`,
})
if (includeNodesField) {
t2.list.field('nodes', {
@ -530,11 +530,11 @@ export const connectionPlugin = (connectionPluginConfig?: ConnectionPluginConfig
definition(t2) {
t2.field('cursor', {
type: cursorType ?? nonNull('String'),
description: 'https://facebook.github.io/relay/graphql/connections.htm#sec-Cursor',
description: 'https://relay.dev/graphql/connections.htm#sec-Cursor',
})
t2.field('node', {
type: targetType,
description: 'https://facebook.github.io/relay/graphql/connections.htm#sec-Node',
description: 'https://relay.dev/graphql/connections.htm#sec-Node',
})
if (pluginExtendEdge) {
eachObj(pluginExtendEdge, (val, key) => {
@ -558,7 +558,7 @@ export const connectionPlugin = (connectionPluginConfig?: ConnectionPluginConfig
objectType({
name: 'PageInfo',
description:
'PageInfo cursor, as defined in https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo',
'PageInfo cursor, as defined in https://relay.dev/graphql/connections.htm#sec-undefined.PageInfo',
definition(t2) {
t2.nonNull.field('hasNextPage', {
type: 'Boolean',
@ -724,10 +724,6 @@ export function makeResolveFn(
formattedArgs.after = decodeCursor(args.after).replace(CURSOR_PREFIX, '')
}
if (args.last && !args.before && cursorFromNode === defaultCursorFromNode) {
throw new Error(`Cannot paginate backward without a "before" cursor by default.`)
}
// Local variable to cache the execution of fetching the nodes,
// which is needed for all fields.
let cachedNodes: MaybePromiseLike<Array<any>>
@ -978,8 +974,10 @@ function iterateNodes(nodes: any[], args: PaginationArgs, cb: (node: any, i: num
}
} else if (typeof args.last === 'number') {
const len = Math.min(args.last, nodes.length)
const startOffset = Math.max(nodes.length - args.last, 0)
for (let i = 0; i < len; i++) {
cb(nodes[i], i)
cb(nodes[i + startOffset], i)
}
} else {
// Only happens if we have a custom validateArgs that ignores first/last
@ -1063,14 +1061,9 @@ function defaultCursorFromNode(
// If we're paginating backward, assume we're working backward from the assumed length
// e.g. [0...20] (last: 5, before: "cursor:20") -> [cursor:15, cursor:16, cursor:17, cursor:18, cursor:19]
if (typeof args.last === 'number') {
if (args.before) {
const offset = parseInt(args.before, 10)
const len = Math.min(nodes.length, args.last)
cursorIndex = offset - len + index
} else {
/* istanbul ignore next */
throw new Error('Unreachable')
}
const offset = args.before ? parseInt(args.before, 10) : nodes.length
const len = Math.min(nodes.length, args.last)
cursorIndex = offset - len + index
}
return `${CURSOR_PREFIX}${cursorIndex}`
}

View File

@ -31,11 +31,9 @@ export interface NullabilityPluginOnGuardedConfig {
type: GraphQLNullableType
}
export type NullFallbackValues = Partial<
{
[K in AllOutputTypes]: (obj: NullabilityPluginFallbackFn) => GetGen2<'rootTypes', K>
}
>
export type NullFallbackValues = Partial<{
[K in AllOutputTypes]: (obj: NullabilityPluginFallbackFn) => GetGen2<'rootTypes', K>
}>
export type NullabilityGuardConfig = {
/** Whether we should guard against non-null values. Defaults to "true" if NODE_ENV === "production", false otherwise. */

View File

@ -0,0 +1,323 @@
/** Conveniently represents flow's "Maybe" type https://flow.org/en/docs/types/maybe/ */
type Maybe<T> = null | undefined | T
import { DirectiveNode, Kind, print } from 'graphql'
import { printBlockString, invariant, inspect } from './graphqlInternal'
import type { GraphQLSchema } from 'graphql'
import type { GraphQLDirective } from 'graphql'
import type {
GraphQLNamedType,
GraphQLArgument,
GraphQLInputField,
GraphQLScalarType,
GraphQLEnumType,
GraphQLObjectType,
GraphQLInterfaceType,
GraphQLUnionType,
GraphQLInputObjectType,
} from 'graphql'
import { isIntrospectionType } from 'graphql'
import { isSpecifiedScalarType } from 'graphql'
import { DEFAULT_DEPRECATION_REASON, isSpecifiedDirective } from 'graphql'
import {
isScalarType,
isObjectType,
isInterfaceType,
isUnionType,
isEnumType,
isInputObjectType,
} from 'graphql'
import { astFromValue } from 'graphql'
export function printSchemaWithDirectives(schema: GraphQLSchema): string {
return printFilteredSchemaWithDirectives(schema, (n) => !isSpecifiedDirective(n), isDefinedType)
}
function isDefinedType(type: GraphQLNamedType): boolean {
return !isSpecifiedScalarType(type) && !isIntrospectionType(type)
}
function printFilteredSchemaWithDirectives(
schema: GraphQLSchema,
directiveFilter: (type: GraphQLDirective) => boolean,
typeFilter: (type: GraphQLNamedType) => boolean
): string {
const directives = schema.getDirectives().filter(directiveFilter)
const types = Object.values(schema.getTypeMap()).filter(typeFilter)
return [
printSchemaDefinition(schema),
...directives.map((directive) => printDirective(directive)),
...types.map((type) => printType(type)),
]
.filter(Boolean)
.join('\n\n')
}
function printSchemaDefinition(
// & description for GraphQL 14 types
schema: GraphQLSchema & { description?: Maybe<string> }
): Maybe<string> {
if (schema.description == null && isSchemaOfCommonNames(schema)) {
return
}
const operationTypes = []
const queryType = schema.getQueryType()
if (queryType) {
operationTypes.push(` query: ${queryType.name}`)
}
const mutationType = schema.getMutationType()
if (mutationType) {
operationTypes.push(` mutation: ${mutationType.name}`)
}
const subscriptionType = schema.getSubscriptionType()
if (subscriptionType) {
operationTypes.push(` subscription: ${subscriptionType.name}`)
}
return printDescription(schema) + `schema {\n${operationTypes.join('\n')}\n}`
}
/**
* GraphQL schema define root types for each type of operation. These types are the same as any other type and
* can be named in any manner, however there is a common naming convention:
*
* ```graphql
* query: Query
* mutation: Mutation
* subscription: Subscription } ```
*
* When using this naming convention, the schema description can be omitted.
* ```
*/
function isSchemaOfCommonNames(schema: GraphQLSchema): boolean {
const queryType = schema.getQueryType()
if (queryType && queryType.name !== 'Query') {
return false
}
const mutationType = schema.getMutationType()
if (mutationType && mutationType.name !== 'Mutation') {
return false
}
const subscriptionType = schema.getSubscriptionType()
if (subscriptionType && subscriptionType.name !== 'Subscription') {
return false
}
return true
}
export function printType(type: GraphQLNamedType): string {
if (isScalarType(type)) {
return printScalar(type)
}
if (isObjectType(type)) {
return printObject(type)
}
if (isInterfaceType(type)) {
return printInterface(type)
}
if (isUnionType(type)) {
return printUnion(type)
}
if (isEnumType(type)) {
return printEnum(type)
}
// istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if (isInputObjectType(type)) {
return printInputObject(type)
}
// istanbul ignore next (Not reachable. All possible types have been considered)
invariant(false, 'Unexpected type: ' + inspect(type))
}
function printScalar(type: GraphQLScalarType): string {
return printDescription(type) + `scalar ${type.name}` + printSpecifiedByURL(type) + printDirectives(type)
}
function printImplementedInterfaces(
// & getInterfaces added for GraphQL 14 types
type: (GraphQLObjectType | GraphQLInterfaceType) & { getInterfaces?: () => readonly GraphQLInterfaceType[] }
): string {
const interfaces = type.getInterfaces?.()
return interfaces?.length ? ' implements ' + interfaces.map((i) => i.name).join(' & ') : ''
}
function printObject(type: GraphQLObjectType): string {
return (
printDescription(type) +
`type ${type.name}` +
printImplementedInterfaces(type) +
printDirectives(type) +
printFields(type)
)
}
function printInterface(type: GraphQLInterfaceType): string {
return (
printDescription(type) +
`interface ${type.name}` +
printImplementedInterfaces(type) +
printDirectives(type) +
printFields(type)
)
}
function printUnion(type: GraphQLUnionType): string {
const types = type.getTypes()
const possibleTypes = types.length ? ' = ' + types.join(' | ') : ''
return printDescription(type) + 'union ' + type.name + printDirectives(type) + possibleTypes
}
function printEnum(type: GraphQLEnumType): string {
const values = type
.getValues()
.map(
(value, i) =>
printDescription(value, ' ', !i) +
' ' +
value.name +
printDeprecated(value.deprecationReason) +
printDirectives(value)
)
return printDescription(type) + `enum ${type.name}` + printDirectives(type) + printBlock(values)
}
function printInputObject(type: GraphQLInputObjectType): string {
const fields = Object.values(type.getFields()).map(
(f, i) => printDescription(f, ' ', !i) + ' ' + printInputValue(f)
)
return printDescription(type) + `input ${type.name}` + printDirectives(type) + printBlock(fields)
}
function printFields(type: GraphQLObjectType | GraphQLInterfaceType): string {
const fields = Object.values(type.getFields()).map(
(f, i) =>
printDescription(f, ' ', !i) +
' ' +
f.name +
printArgs(f.args, ' ') +
': ' +
String(f.type) +
printDeprecated(f.deprecationReason) +
printDirectives(f)
)
return printBlock(fields)
}
function printBlock(items: ReadonlyArray<string>): string {
return items.length !== 0 ? ' {\n' + items.join('\n') + '\n}' : ''
}
function printArgs(args: ReadonlyArray<GraphQLArgument>, indentation: string = ''): string {
if (args.length === 0) {
return ''
}
// If every arg does not have a description, print them on one line.
if (args.every((arg) => !arg.description)) {
return '(' + args.map(printInputValue).join(', ') + ')'
}
return (
'(\n' +
args
.map(
(arg, i) => printDescription(arg, ' ' + indentation, !i) + ' ' + indentation + printInputValue(arg)
)
.join('\n') +
'\n' +
indentation +
')'
)
}
function printInputValue(arg: GraphQLInputField & { deprecationReason?: Maybe<string> }): string {
const defaultAST = astFromValue(arg.defaultValue, arg.type)
let argDecl = arg.name + ': ' + String(arg.type)
if (defaultAST) {
argDecl += ` = ${print(defaultAST)}`
}
return argDecl + printDeprecated(arg.deprecationReason) + printDirectives(arg)
}
function printDirective(directive: GraphQLDirective): string {
return (
printDescription(directive) +
'directive @' +
directive.name +
printArgs(directive.args) +
(directive.isRepeatable ? ' repeatable' : '') +
' on ' +
directive.locations.join(' | ')
)
}
function printDeprecated(reason: Maybe<string>): string {
if (reason == null) {
return ''
}
if (reason !== DEFAULT_DEPRECATION_REASON) {
const astValue = print({ kind: Kind.STRING, value: reason })
return ` @deprecated(reason: ${astValue})`
}
return ' @deprecated'
}
function printSpecifiedByURL(
// https://github.com/graphql/graphql-js/issues/3156
scalar: GraphQLScalarType & { specifiedByURL?: Maybe<string>; specifiedByUrl?: Maybe<string> }
): string {
const specifiedByURL = scalar.specifiedByURL ?? scalar.specifiedByUrl
if (specifiedByURL == null) {
return ''
}
const astValue = print({ kind: Kind.STRING, value: specifiedByURL })
return ` @specifiedBy(url: ${astValue})`
}
function printDescription(
def: { readonly description?: Maybe<string> },
indentation: string = '',
firstInBlock: boolean = true
): string {
const { description } = def
if (description == null) {
return ''
}
const preferMultipleLines = description.length > 70
const blockString = printBlockString(description, preferMultipleLines)
const prefix = indentation && !firstInBlock ? '\n' + indentation : indentation
return prefix + blockString.replace(/\n/g, '\n' + indentation) + '\n'
}
function printDirectives(value: { astNode?: Maybe<{ readonly directives?: ReadonlyArray<DirectiveNode> }> }) {
const directives = value.astNode?.directives
if (!directives?.length) {
return ''
}
return ' ' + directives.map(printDirectiveUse).join(' ')
}
function printDirectiveUse(node: DirectiveNode) {
return `@${node.name.value}` + printDirectiveArgs(node)
}
function printDirectiveArgs(node: DirectiveNode) {
if (!node.arguments?.length) {
return ''
}
return `(${node.arguments.map((a) => `${a.name.value}: ${print(a.value)}`).join(', ')})`
}

232
src/rebuildType.ts Normal file
View File

@ -0,0 +1,232 @@
import {
GraphQLEnumType,
GraphQLFieldConfigArgumentMap,
GraphQLFieldConfigMap,
GraphQLInputFieldConfigMap,
GraphQLInputObjectType,
GraphQLInterfaceType,
GraphQLNamedType,
GraphQLObjectType,
GraphQLScalarType,
GraphQLUnionType,
isEnumType,
isInputObjectType,
isInterfaceType,
isObjectType,
isScalarType,
isUnionType,
defaultTypeResolver,
} from 'graphql'
import type { MergeSchemaConfig } from './builder'
import { arg, ArgsRecord } from './definitions/args'
import type { InputDefinitionBlock } from './definitions/definitionBlocks'
import { enumType } from './definitions/enumType'
import { inputObjectType } from './definitions/inputObjectType'
import { InterfaceDefinitionBlock, interfaceType } from './definitions/interfaceType'
import { ObjectDefinitionBlock, objectType } from './definitions/objectType'
import { scalarType } from './definitions/scalarType'
import { unionType } from './definitions/unionType'
import { AllNexusArgsDefs, applyNexusWrapping, unwrapGraphQLDef } from './definitions/wrapping'
import type { Maybe, SourceTypingDef } from './definitions/_types'
import type { GetGen } from './typegenTypeHelpers'
import { graphql15InterfaceConfig, Unreachable } from './utils'
export interface RebuildConfig extends Omit<MergeSchemaConfig, 'schema'> {
captureLeafType?: (type: GraphQLNamedType) => void
asNexusMethod?: string
sourceType?: SourceTypingDef
}
export function rebuildNamedType(type: GraphQLNamedType, config: RebuildConfig) {
if (isObjectType(type)) {
return rebuildObjectType(type, config)
} else if (isInputObjectType(type)) {
return rebuildInputObjectType(type, config)
} else if (isInterfaceType(type)) {
return rebuildInterfaceType(type, config)
} else if (isUnionType(type)) {
return rebuildUnionType(type, config)
} else if (isScalarType(type)) {
return rebuildScalarType(type, config)
} else if (isEnumType(type)) {
return rebuildEnumType(type, config)
}
throw new Unreachable(type)
}
export function rebuildInputObjectType(type: GraphQLInputObjectType, config: RebuildConfig) {
const { name, fields, description, extensions } = type.toConfig()
return inputObjectType({
name,
description,
definition: (t) => {
rebuildInputDefinition(name, t, fields, config)
},
extensions,
nonNullDefaults: {
output: false,
input: false,
},
})
}
export function rebuildUnionType(type: GraphQLUnionType, config: RebuildConfig) {
const { name, types, description, resolveType, extensions } = type.toConfig()
return unionType({
name,
description,
// @ts-ignore - todo, see why this is the case
resolveType: resolveType ?? defaultTypeResolver,
definition(t) {
t.members(
...types.map((o) => {
config.captureLeafType?.(o)
return o.name as GetGen<'objectNames'>
})
)
},
extensions,
})
}
export function rebuildScalarType(type: GraphQLScalarType, config: RebuildConfig) {
return scalarType({
...type.toConfig(),
sourceType: config.sourceType,
asNexusMethod: config.asNexusMethod,
})
}
export function rebuildEnumType(type: GraphQLEnumType, { sourceType, asNexusMethod }: RebuildConfig) {
const { name, values, ...config } = type.toConfig()
return enumType({
name,
...config,
members: Object.entries(values).map(([valueName, config]) => {
return {
name: valueName,
deprecation: config.deprecationReason,
...config,
}
}),
sourceType,
asNexusMethod,
})
}
export function rebuildInterfaceType(type: GraphQLInterfaceType, config: RebuildConfig) {
const { name, fields, description, interfaces, extensions, resolveType } = graphql15InterfaceConfig(
type.toConfig()
)
return interfaceType({
name,
description,
// @ts-ignore - todo, see why this is the case
resolveType: resolveType ?? defaultTypeResolver,
definition: (t) => {
rebuildOutputDefinition(name, t, fields, interfaces, config)
},
nonNullDefaults: {
output: false,
input: false,
},
extensions,
sourceType: config.sourceType,
asNexusMethod: config.asNexusMethod,
})
}
export function rebuildObjectType(type: GraphQLObjectType, config: RebuildConfig) {
const { name, fields, interfaces, description, extensions } = type.toConfig()
return objectType({
name,
description,
definition: (t) => {
rebuildOutputDefinition(name, t, fields, interfaces, config)
},
nonNullDefaults: {
output: false,
input: false,
},
extensions,
sourceType: config.sourceType,
asNexusMethod: config.asNexusMethod,
})
}
export function rebuildOutputDefinition(
typeName: string,
t: ObjectDefinitionBlock<string> | InterfaceDefinitionBlock<string>,
fields: GraphQLFieldConfigMap<any, any>,
interfaces: ReadonlyArray<GraphQLInterfaceType>,
config: RebuildConfig
) {
t.implements(
...interfaces.map((i) => {
config.captureLeafType?.(i)
return i.name as GetGen<'interfaceNames'>
})
)
for (const [fieldName, fieldConfig] of Object.entries(fields)) {
if (config.skipFields?.[typeName] && config.skipFields?.[typeName].includes(fieldName)) {
continue
}
const { namedType, wrapping } = unwrapGraphQLDef(fieldConfig.type)
config.captureLeafType?.(namedType)
t.field(fieldName, {
type: applyNexusWrapping(namedType.name, wrapping),
description: fieldConfig.description,
deprecation: fieldConfig.deprecationReason,
extensions: fieldConfig.extensions,
args: rebuildArgs(typeName, fieldName, fieldConfig.args ?? {}, config),
resolve: fieldConfig.resolve,
})
}
}
export function rebuildInputDefinition(
typeName: string,
t: InputDefinitionBlock<string>,
fields: GraphQLInputFieldConfigMap,
config: RebuildConfig
) {
for (const [fieldName, fieldConfig] of Object.entries(fields)) {
if (config.skipFields?.[typeName] && config.skipFields?.[typeName].includes(fieldName)) {
continue
}
const { namedType, wrapping } = unwrapGraphQLDef(fieldConfig.type)
config.captureLeafType?.(namedType)
t.field(fieldName, {
type: applyNexusWrapping(namedType.name, wrapping),
description: fieldConfig.description,
default: fieldConfig.defaultValue,
extensions: fieldConfig.extensions,
})
}
}
export function rebuildArgs(
typeName: string,
fieldName: string,
argMap: Maybe<GraphQLFieldConfigArgumentMap>,
config: RebuildConfig
): Maybe<ArgsRecord> {
if (!argMap) {
return null
}
const rebuiltArgs: Record<string, AllNexusArgsDefs> = {}
for (const [argName, argConfig] of Object.entries(argMap)) {
if (config.skipArgs?.[typeName]?.[fieldName]) {
continue
}
const { namedType, wrapping } = unwrapGraphQLDef(argConfig.type)
config.captureLeafType?.(namedType)
rebuiltArgs[argName] = arg({
type: applyNexusWrapping(namedType.name, wrapping),
default: argConfig.defaultValue,
description: argConfig.description,
extensions: argConfig.extensions,
})
}
return rebuiltArgs
}

View File

@ -56,3 +56,5 @@ type DoRequireDeeply<T> = {
export type MaybePromiseLike<T> = T | PromiseLike<T>
export type UnwrapPromise<R> = R extends PromiseLike<infer U> ? U : R
export type MaybeReadonlyArray<T> = Array<T> | ReadonlyArray<T>

View File

@ -1,4 +1,5 @@
import type { GraphQLResolveInfo } from 'graphql'
import type { Maybe } from './definitions/_types'
import type {
AbstractTypeResolver,
GetGen,
@ -63,7 +64,7 @@ export type IsTypeOfHandler<TypeName extends string> = (
* Get an object with the `isTypeOf` field if applicable for the given object Type.
*
* @remarks
* Intersect the result of this with other things to build up the final options for a type def.
* Intersect the result of this with other things to build up the final options for a type def.
*/
export type MaybeTypeDefConfigFieldIsTypeOf<TypeName extends string> =
// is isTypeOf strategy disabled ?
@ -121,24 +122,24 @@ export type MaybeTypeDefConfigFieldIsTypeOf<TypeName extends string> =
* })
*
* @param source The [source data](https://nxs.li/guides/source-types) for the GraphQL objects that
* are members of the abstract types that this type is a member of. For example for some type A in
* two union types whose members are A,B.C and A,D,E respectively then isTypeOf method for A would
* receive source data from A, B, C, D, & E at runtime.
* are members of the abstract types that this type is a member of. For example for some type A
* in two union types whose members are A,B.C and A,D,E respectively then isTypeOf method for A
* would receive source data from A, B, C, D, & E at runtime.
* @param context The context data for this request.
*
* The context data is typically a singleton scoped to the lifecycle of the request. This means
* created at the beginning of a request and then passed to all the resolvers that execute while
* resolving the request. It is often used to store information like the current user making the
* request. Nexus is not responsible for this however. That is typically something you'll do with
* e.g. [Mercurius](https://mercurius.dev) or [Apollo
* Server](https://apollographql.com/docs/apollo-server/api/apollo-server).
* The context data is typically a singleton scoped to the lifecycle of the request. This means
* created at the beginning of a request and then passed to all the resolvers that execute while
* resolving the request. It is often used to store information like the current user making the
* request. Nexus is not responsible for this however. That is typically something you'll do with
* e.g. [Mercurius](https://mercurius.dev) or [Apollo
* Server](https://apollographql.com/docs/apollo-server/api/apollo-server).
*
* Note that the type here will be whatever you have specified for "contextType" in your makeSchema
* configuration.
* Note that the type here will be whatever you have specified for "contextType" in your makeSchema
* configuration.
* @param info The GraphQL resolve info.
*
* This is an advanced parameter seldom used. It includes things like the AST of the [GraphQL
* document](https://spec.graphql.org/June2018/#sec-Language.Document) sent by the client.
* This is an advanced parameter seldom used. It includes things like the AST of the [GraphQL
* document](https://spec.graphql.org/June2018/#sec-Language.Document) sent by the client.
* @returns A boolean indicating if the received source data is of this type or not.
*/
isTypeOf?: IsTypeOfHandler<TypeName>
@ -200,24 +201,24 @@ export type MaybeTypeDefConfigFieldIsTypeOf<TypeName extends string> =
* })
*
* @param source The [source data](https://nxs.li/guides/source-types) for the GraphQL objects that
* are members of the abstract types that this type is a member of. For example for some type A in
* two union types whose members are A,B.C and A,D,E respectively then isTypeOf method for A would
* receive source data from A, B, C, D, & E at runtime.
* are members of the abstract types that this type is a member of. For example for some type A
* in two union types whose members are A,B.C and A,D,E respectively then isTypeOf method for A
* would receive source data from A, B, C, D, & E at runtime.
* @param context The context data for this request.
*
* The context data is typically a singleton scoped to the lifecycle of the request. This means
* created at the beginning of a request and then passed to all the resolvers that execute while
* resolving the request. It is often used to store information like the current user making the
* request. Nexus is not responsible for this however. That is typically something you'll do with
* e.g. [Mercurius](https://mercurius.dev) or [Apollo
* Server](https://apollographql.com/docs/apollo-server/api/apollo-server).
* The context data is typically a singleton scoped to the lifecycle of the request. This means
* created at the beginning of a request and then passed to all the resolvers that execute while
* resolving the request. It is often used to store information like the current user making the
* request. Nexus is not responsible for this however. That is typically something you'll do with
* e.g. [Mercurius](https://mercurius.dev) or [Apollo
* Server](https://apollographql.com/docs/apollo-server/api/apollo-server).
*
* Note that the type here will be whatever you have specified for "contextType" in your makeSchema
* configuration.
* Note that the type here will be whatever you have specified for "contextType" in your makeSchema
* configuration.
* @param info The GraphQL resolve info.
*
* This is an advanced parameter seldom used. It includes things like the AST of the [GraphQL
* document](https://spec.graphql.org/June2018/#sec-Language.Document) sent by the client.
* This is an advanced parameter seldom used. It includes things like the AST of the [GraphQL
* document](https://spec.graphql.org/June2018/#sec-Language.Document) sent by the client.
* @returns A boolean indicating if the received source data is of this type or not.
*/
isTypeOf?: IsTypeOfHandler<TypeName>
@ -278,24 +279,24 @@ export type MaybeTypeDefConfigFieldIsTypeOf<TypeName extends string> =
* })
*
* @param source The [source data](https://nxs.li/guides/source-types) for the GraphQL objects that
* are members of the abstract types that this type is a member of. For example for some type A in
* two union types whose members are A,B.C and A,D,E respectively then isTypeOf method for A would
* receive source data from A, B, C, D, & E at runtime.
* are members of the abstract types that this type is a member of. For example for some type A
* in two union types whose members are A,B.C and A,D,E respectively then isTypeOf method for A
* would receive source data from A, B, C, D, & E at runtime.
* @param context The context data for this request.
*
* The context data is typically a singleton scoped to the lifecycle of the request. This means
* created at the beginning of a request and then passed to all the resolvers that execute while
* resolving the request. It is often used to store information like the current user making the
* request. Nexus is not responsible for this however. That is typically something you'll do with
* e.g. [Mercurius](https://mercurius.dev) or [Apollo
* Server](https://apollographql.com/docs/apollo-server/api/apollo-server).
* The context data is typically a singleton scoped to the lifecycle of the request. This means
* created at the beginning of a request and then passed to all the resolvers that execute while
* resolving the request. It is often used to store information like the current user making the
* request. Nexus is not responsible for this however. That is typically something you'll do with
* e.g. [Mercurius](https://mercurius.dev) or [Apollo
* Server](https://apollographql.com/docs/apollo-server/api/apollo-server).
*
* Note that the type here will be whatever you have specified for "contextType" in your makeSchema
* configuration.
* Note that the type here will be whatever you have specified for "contextType" in your makeSchema
* configuration.
* @param info The GraphQL resolve info.
*
* This is an advanced parameter seldom used. It includes things like the AST of the [GraphQL
* document](https://spec.graphql.org/June2018/#sec-Language.Document) sent by the client.
* This is an advanced parameter seldom used. It includes things like the AST of the [GraphQL
* document](https://spec.graphql.org/June2018/#sec-Language.Document) sent by the client.
* @returns A boolean indicating if the received source data is of this type or not.
*/
isTypeOf?: IsTypeOfHandler<TypeName>
@ -346,24 +347,24 @@ export type MaybeTypeDefConfigFieldIsTypeOf<TypeName extends string> =
* })
*
* @param source The [source data](https://nxs.li/guides/source-types) for the GraphQL objects that
* are members of the abstract types that this type is a member of. For example for some type A in
* two union types whose members are A,B.C and A,D,E respectively then isTypeOf method for A would
* receive source data from A, B, C, D, & E at runtime.
* are members of the abstract types that this type is a member of. For example for some type A
* in two union types whose members are A,B.C and A,D,E respectively then isTypeOf method for A
* would receive source data from A, B, C, D, & E at runtime.
* @param context The context data for this request.
*
* The context data is typically a singleton scoped to the lifecycle of the request. This means
* created at the beginning of a request and then passed to all the resolvers that execute while
* resolving the request. It is often used to store information like the current user making the
* request. Nexus is not responsible for this however. That is typically something you'll do with
* e.g. [Mercurius](https://mercurius.dev) or [Apollo
* Server](https://apollographql.com/docs/apollo-server/api/apollo-server).
* The context data is typically a singleton scoped to the lifecycle of the request. This means
* created at the beginning of a request and then passed to all the resolvers that execute while
* resolving the request. It is often used to store information like the current user making the
* request. Nexus is not responsible for this however. That is typically something you'll do with
* e.g. [Mercurius](https://mercurius.dev) or [Apollo
* Server](https://apollographql.com/docs/apollo-server/api/apollo-server).
*
* Note that the type here will be whatever you have specified for "contextType" in your makeSchema
* configuration.
* Note that the type here will be whatever you have specified for "contextType" in your makeSchema
* configuration.
* @param info The GraphQL resolve info.
*
* This is an advanced parameter seldom used. It includes things like the AST of the [GraphQL
* document](https://spec.graphql.org/June2018/#sec-Language.Document) sent by the client.
* This is an advanced parameter seldom used. It includes things like the AST of the [GraphQL
* document](https://spec.graphql.org/June2018/#sec-Language.Document) sent by the client.
* @returns A boolean indicating if the received source data is of this type or not.
*/
isTypeOf: IsTypeOfHandler<TypeName>
@ -373,7 +374,7 @@ export type MaybeTypeDefConfigFieldIsTypeOf<TypeName extends string> =
* Get an object with the `resolveType` field if applicable for the given abstract Type.
*
* @remarks
* Intersect the result of this with other things to build up the final options for a type def.
* Intersect the result of this with other things to build up the final options for a type def.
*/
export type MaybeTypeDefConfigFieldResolveType<TypeName extends string> = IsFeatureEnabled2<
'abstractTypeStrategies',
@ -389,7 +390,7 @@ export type MaybeTypeDefConfigFieldResolveType<TypeName extends string> = IsFeat
* implementation will first look for __typename, then fallback to calling `isTypeOf` on each
* implementing Object type.
*/
resolveType?: AbstractTypeResolver<TypeName>
resolveType?: Maybe<AbstractTypeResolver<TypeName>>
} // Make resolveType optional when __typename strategy is enabled
: IsFeatureEnabled2<'abstractTypeStrategies', '__typename'> extends true
? {
@ -400,7 +401,7 @@ export type MaybeTypeDefConfigFieldResolveType<TypeName extends string> = IsFeat
* implementation will first look for __typename, then fallback to calling `isTypeOf` on each
* implementing Object type.
*/
resolveType?: AbstractTypeResolver<TypeName>
resolveType?: Maybe<AbstractTypeResolver<TypeName>>
}
: {
/**

View File

@ -1,8 +1,8 @@
import { GraphQLNamedType, GraphQLSchema, isOutputType } from 'graphql'
import * as path from 'path'
import type { TypegenInfo } from './builder'
import type { TypingImport } from './definitions/_types'
import { TYPEGEN_HEADER } from './lang'
import { nodeImports } from './node'
import { getOwnPackage, log, objValues, relativePathTo, typeScriptFileExtension } from './utils'
/** 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(
options.modules.map(async (source) => {
// Keeping all of this in here so if we don't have any sources
// 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
if (path.isAbsolute(pathOrModule) && path.extname(pathOrModule) !== '.ts') {
return console.warn(
@ -154,7 +150,7 @@ export function typegenAutoConfig(options: SourceTypesConfigOptions, contextType
if (path.extname(resolvedPath) !== '.ts') {
resolvedPath = findTypingForFile(resolvedPath, pathOrModule)
}
fileContents = await readFile(resolvedPath, 'utf-8')
fileContents = String(await nodeImports().fs.promises.readFile(resolvedPath, 'utf-8'))
} catch (e) {
if (e instanceof Error && e.message.indexOf('Cannot find module') !== -1) {
console.error(`GraphQL Nexus: Unable to find file or module ${pathOrModule}, skipping`)
@ -194,7 +190,7 @@ export function typegenAutoConfig(options: SourceTypesConfigOptions, contextType
const builtinScalars = new Set(Object.keys(SCALAR_TYPES))
Object.keys(typeMap).forEach((typeName) => {
if (typeName.indexOf('__') === 0) {
if (typeName.startsWith('__')) {
return
}
if (typesToIgnore.has(typeName)) {
@ -277,7 +273,7 @@ export function typegenAutoConfig(options: SourceTypesConfigOptions, contextType
function findTypingForFile(absolutePath: string, pathOrModule: string) {
// First try to find the "d.ts" adjacent to the file
try {
const typeDefPath = absolutePath.replace(path.extname(absolutePath), '.d.ts')
const typeDefPath = absolutePath.replace(nodeImports().path.extname(absolutePath), '.d.ts')
require.resolve(typeDefPath)
return typeDefPath
} catch (e) {

View File

@ -1,5 +1,5 @@
import * as path from 'path'
import type * as Prettier from 'prettier'
import { nodeImports } from './node'
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
const path = nodeImports().path
if (typeof prettierConfig === 'string') {
/* istanbul ignore if */
if (!path.isAbsolute(prettierConfig)) {

View File

@ -1,10 +1,12 @@
import { GraphQLSchema, lexicographicSortSchema, printSchema } from 'graphql'
import * as path from 'path'
import { GraphQLSchema, lexicographicSortSchema } from 'graphql'
import type { BuilderConfigInput, TypegenInfo } from './builder'
import type { ConfiguredTypegen } from './core'
import type { NexusGraphQLSchema } from './definitions/_types'
import { SDL_HEADER, TYPEGEN_HEADER } from './lang'
import { nodeImports } from './node'
import { printSchemaWithDirectives } from './printSchemaWithDirectives'
import { typegenAutoConfig } from './typegenAutoConfig'
import { TypegenFormatFn, typegenFormatPrettier } from './typegenFormatPrettier'
import { typegenFormatPrettier } from './typegenFormatPrettier'
import { TypegenPrinter } from './typegenPrinter'
export interface TypegenMetadataConfig
@ -12,7 +14,7 @@ export interface TypegenMetadataConfig
nexusSchemaImportId?: string
outputs: {
schema: null | string
typegen: null | string
typegen: null | ConfiguredTypegen
}
}
@ -26,26 +28,42 @@ export class TypegenMetadata {
/** Generates the artifacts of the build based on what we know about the schema and how it was defined. */
async generateArtifacts(schema: NexusGraphQLSchema) {
const sortedSchema = this.sortSchema(schema)
if (this.config.outputs.schema || this.config.outputs.typegen) {
const { schemaTypes, tsTypes } = await this.generateArtifactContents(
sortedSchema,
this.config.outputs.typegen
)
const { typegen } = this.config.outputs
if (this.config.outputs.schema || typegen) {
const { schemaTypes, tsTypes, globalTypes } = await this.generateArtifactContents(sortedSchema, typegen)
if (this.config.outputs.schema) {
await this.writeFile('schema', schemaTypes, this.config.outputs.schema)
}
if (this.config.outputs.typegen) {
await this.writeFile('types', tsTypes, this.config.outputs.typegen)
if (typegen) {
if (typeof typegen === 'string') {
await this.writeFile('types', tsTypes, typegen)
} else {
await this.writeFile('types', tsTypes, typegen.outputPath)
if (typeof typegen.globalsPath === 'string') {
await this.writeFile('types', globalTypes ?? '', typegen.globalsPath)
}
}
}
}
}
async generateArtifactContents(schema: NexusGraphQLSchema, typeFilePath: string | null) {
const [schemaTypes, tsTypes] = await Promise.all([
this.generateSchemaFile(schema),
typeFilePath ? this.generateTypesFile(schema, typeFilePath) : '',
])
return { schemaTypes, tsTypes }
async generateArtifactContents(schema: NexusGraphQLSchema, typegen: string | null | ConfiguredTypegen) {
const result = {
schemaTypes: this.generateSchemaFile(schema),
tsTypes: '',
globalTypes: null as null | string,
}
if (!typegen) {
return result
}
if (typeof typegen === 'string') {
result.tsTypes = await this.generateTypesFile(schema, typegen)
} else {
const generateResult = await this.generateConfiguredTypes(schema, typegen)
result.tsTypes = generateResult.tsTypes
result.globalTypes = generateResult.globalTypes
}
return result
}
sortSchema(schema: NexusGraphQLSchema) {
@ -57,31 +75,26 @@ export class TypegenMetadata {
}
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(
new Error(`Expected an absolute path to output the Nexus ${type}, saw ${filePath}`)
)
}
const fs = require('fs') as typeof import('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),
]
let formatTypegen: TypegenFormatFn | null = null
if (typeof this.config.formatTypegen === 'function') {
formatTypegen = this.config.formatTypegen
} else if (this.config.prettierConfig) {
formatTypegen = typegenFormatPrettier(this.config.prettierConfig)
}
const content = typeof formatTypegen === 'function' ? await formatTypegen(output, type) : output
const [toSave, existing] = await Promise.all([content, readFile(filePath, 'utf8').catch(() => '')])
const fs = nodeImports().fs
const formattedOutput =
typeof this.config.formatTypegen === 'function' ? await this.config.formatTypegen(output, type) : output
const content = this.config.prettierConfig
? await typegenFormatPrettier(this.config.prettierConfig)(formattedOutput, type)
: formattedOutput
const [toSave, existing] = await Promise.all([
content,
fs.promises.readFile(filePath, 'utf8').catch(() => ''),
])
if (toSave !== existing) {
const dirPath = path.dirname(filePath)
const dirPath = nodeImports().path.dirname(filePath)
try {
await mkdir(dirPath, { recursive: true })
await fs.promises.mkdir(dirPath, { recursive: true })
} catch (e) {
if (e.code !== 'EEXIST') {
throw e
@ -91,14 +104,14 @@ export class TypegenMetadata {
// apparently. See issue motivating this logic here:
// https://github.com/graphql-nexus/schema/issues/247.
try {
await removeFile(filePath)
await fs.promises.unlink(filePath)
} catch (e) {
/* istanbul ignore next */
if (e.code !== 'ENOENT' && e.code !== 'ENOTDIR') {
throw e
}
}
return writeFile(filePath, toSave)
return fs.promises.writeFile(filePath, toSave)
}
}
@ -106,7 +119,7 @@ export class TypegenMetadata {
generateSchemaFile(schema: GraphQLSchema): string {
let printedSchema = this.config.customPrintSchemaFn
? this.config.customPrintSchemaFn(schema)
: printSchema(schema)
: printSchemaWithDirectives(schema)
return [SDL_HEADER, printedSchema].join('\n\n')
}
@ -115,11 +128,34 @@ export class TypegenMetadata {
const typegenInfo = await this.getTypegenInfo(schema, typegenPath)
return new TypegenPrinter(schema, {
declareInputs: false,
useReadonlyArrayForInputs: false,
...typegenInfo,
typegenPath,
}).print()
}
/** Generates the type definitions */
async generateConfiguredTypes(schema: NexusGraphQLSchema, typegen: ConfiguredTypegen) {
const {
outputPath: typegenPath,
globalsPath,
globalsHeaders,
declareInputs = false,
useReadonlyArrayForInputs = false,
} = typegen
const typegenInfo = await this.getTypegenInfo(schema, typegenPath)
return new TypegenPrinter(schema, {
...typegenInfo,
typegenPath,
globalsPath,
globalsHeaders,
declareInputs,
useReadonlyArrayForInputs,
}).printConfigured()
}
async getTypegenInfo(schema: GraphQLSchema, typegenPath?: string): Promise<TypegenInfo> {
if ('typegenConfig' in this.config) {
throw new Error(
@ -130,7 +166,7 @@ export class TypegenMetadata {
if (this.config.sourceTypes) {
return typegenAutoConfig(this.config.sourceTypes, this.config.contextType)(
schema,
typegenPath || this.config.outputs.typegen || ''
typegenPath || this.config.outputs.typegen?.outputPath || ''
)
}

View File

@ -18,13 +18,17 @@ import {
isNonNullType,
isObjectType,
isScalarType,
isSpecifiedDirective,
isSpecifiedScalarType,
isUnionType,
} from 'graphql'
import type { TypegenInfo } from './builder'
import { SchemaDirectiveLocation } from './definitions/directive'
import { isNexusPrintedGenTyping, isNexusPrintedGenTypingImport } from './definitions/wrapping'
import type { NexusGraphQLSchema } from './definitions/_types'
import { TYPEGEN_HEADER } from './lang'
import type { StringLike } from './plugin'
import { hasNexusExtension, isNexusFieldExtension } from './extensions'
import {
eachObj,
getOwnPackage,
@ -34,6 +38,7 @@ import {
mapObj,
mapValues,
PrintedGenTypingImport,
relativePathTo,
resolveImportPath,
} from './utils'
@ -52,23 +57,26 @@ type RootTypeMapping = Record<string, string | Record<string, [string, string]>>
interface TypegenInfoWithFile extends TypegenInfo {
typegenPath: string
globalsPath?: string
globalsHeaders?: string[]
declareInputs?: boolean
useReadonlyArrayForInputs?: boolean
}
/**
* We track and output a few main things:
*
* 1. "root" types, or the values that fill the first argument for a given object type
* 2. "arg" types, the values that are arguments to output fields.
* 3. "return" types, the values returned from the resolvers... usually just list/nullable variations on the
* "root" types for other types
* 4. The names of all types, grouped by type.
* 1. "root" types, or the values that fill the first argument for a given object type 2. "arg" types, the
* values that are arguments to output fields. 3. "return" types, the values returned from the resolvers...
* usually just list/nullable variations on the
* "root" types for other types 4. The names of all types, grouped by type.
*
* - Non-scalar types will get a dedicated "Root" type associated with it
*/
export class TypegenPrinter {
groupedTypes: GroupedTypes
printImports: Record<string, Record<string, boolean | string>>
hasDiscriminatedTypes: boolean
private groupedTypes: GroupedTypes
private printImports: Record<string, Record<string, boolean | string>>
private hasDiscriminatedTypes: boolean
constructor(protected schema: NexusGraphQLSchema, protected typegenInfo: TypegenInfoWithFile) {
this.groupedTypes = groupTypes(schema)
@ -77,7 +85,33 @@ export class TypegenPrinter {
}
print() {
const body = [
const body = [this.printCommon(), this.printPlugins()].join('\n\n')
return [this.printHeaders(), body].join('\n\n')
}
printConfigured() {
if (this.typegenInfo.globalsPath) {
const plugins = this.printPlugins()
const globalTypes = [this.printHeadersGlobal(), this.printDynamicImport(true), plugins].join('\n\n')
// Reset printImports for the imports needed in the types
this.printImports = {}
const common = this.printCommon()
const tsTypes = [this.printHeadersCommon(), common].join('\n\n')
return {
tsTypes,
globalTypes,
}
}
return {
tsTypes: this.print(),
globalTypes: null,
}
}
private printCommon() {
return [
this.printInputTypeMap(),
this.printEnumTypeMap(),
this.printScalarTypeMap(),
@ -97,35 +131,98 @@ export class TypegenPrinter {
this.printTypeNames('interface', 'NexusGenInterfaceNames', 'NexusGenInterfaces'),
this.printTypeNames('scalar', 'NexusGenScalarNames', 'NexusGenScalars'),
this.printTypeNames('union', 'NexusGenUnionNames', 'NexusGenUnions'),
this.printDirectives(),
this.printIsTypeOfObjectTypeNames('NexusGenObjectsUsingAbstractStrategyIsTypeOf'),
this.printResolveTypeAbstractTypes('NexusGenAbstractsUsingStrategyResolveType'),
this.printFeaturesConfig('NexusGenFeaturesConfig'),
this.printGenTypeMap(),
this.printPlugins(),
].join('\n\n')
return [this.printHeaders(), body].join('\n\n')
}
printHeaders() {
const fieldDefs = [
this.printDynamicInputFieldDefinitions(),
this.printDynamicOutputFieldDefinitions(),
this.printDynamicOutputPropertyDefinitions(),
]
private printHeaders() {
return [this.printHeadersCommon(), this.printHeadersGlobal()].join('\n')
}
private printHeadersCommon() {
return [
this.typegenInfo.headers.join('\n'),
this.typegenInfo.imports.join('\n'),
this.printDynamicImport(),
...fieldDefs,
GLOBAL_DECLARATION,
].join('\n')
}
printGenTypeMap() {
private printDirectives() {
const customDirectives = this.schema.getDirectives().filter((d) => !isSpecifiedDirective(d))
const schemaDirectiveArgs: Record<string, readonly GraphQLArgument[] | undefined> = {}
// Gather the mappings between directives, locations, etc.
customDirectives.forEach((d) => {
d.locations.forEach((l) => {
if (SchemaDirectiveLocation.includes(l as any)) {
schemaDirectiveArgs[d.name] = d.args ?? undefined
}
})
})
const directiveNames = Object.keys(schemaDirectiveArgs)
.map((i) => JSON.stringify(i))
.join(' | ')
const toPrint: string[] = [`export type NexusGenDirectives = ${directiveNames || 'never'}`]
// Print the mappings of the directive names -> args
// NexusGenDirectiveArgs
let directiveArgs = [`export interface NexusGenDirectiveArgs {`]
eachObj(schemaDirectiveArgs, (val, key) => {
if (val) {
directiveArgs.push(` ${key}: {`)
val.forEach((arg) => {
const [sep, rep] = this.normalizeArg(arg)
directiveArgs.push(` ${arg.name}${sep}${rep}`)
})
directiveArgs.push(` }`)
} else {
directiveArgs.push(` ${key}: never`)
}
})
directiveArgs.push('}')
toPrint.push(directiveArgs.join('\n'))
return toPrint.join('\n\n')
}
private printHeadersGlobal() {
const headers = [
this.printDynamicInputFieldDefinitions(),
this.printDynamicOutputFieldDefinitions(),
this.printDynamicOutputPropertyDefinitions(),
GLOBAL_DECLARATION,
]
if (this.typegenInfo.globalsPath) {
headers.unshift(
`import type { NexusGenTypes } from '${relativePathTo(
this.typegenInfo.typegenPath,
this.typegenInfo.globalsPath ?? ''
)}'`
)
headers.unshift(...(this.typegenInfo.globalsHeaders ?? []))
headers.unshift(TYPEGEN_HEADER)
}
return headers.join('\n')
}
private printGenTypeMap() {
return [`export interface NexusGenTypes {`]
.concat([
` context: ${this.printContext()};`,
` inputTypes: NexusGenInputs;`,
` directives: NexusGenDirectives;`,
` directiveArgs: NexusGenDirectiveArgs;`,
` rootTypes: NexusGenRootTypes;`,
` inputTypeShapes: NexusGenInputs & NexusGenEnums & NexusGenScalars;`,
` argTypes: NexusGenArgTypes;`,
@ -152,11 +249,8 @@ export class TypegenPrinter {
.join('\n')
}
printDynamicImport() {
const {
rootTypings,
dynamicFields: { dynamicInputFields, dynamicOutputFields },
} = this.schema.extensions.nexus.config
private printDynamicImport(forGlobal = false) {
const { sourceTypings } = this.schema.extensions.nexus.config
const { contextTypeImport } = this.typegenInfo
const imports: string[] = []
const importMap: Record<string, Set<string>> = {}
@ -164,38 +258,33 @@ export class TypegenPrinter {
const nexusSchemaImportId = this.typegenInfo.nexusSchemaImportId ?? getOwnPackage().name
if (!this.printImports[nexusSchemaImportId]) {
if (
[dynamicInputFields, dynamicOutputFields].some((o) => Object.keys(o).length > 0) ||
this.hasDiscriminatedTypes === true
) {
this.printImports[nexusSchemaImportId] = {
core: true,
}
}
this.maybeAddCoreImport(forGlobal)
}
if (contextTypeImport) {
const importPath = resolveImportPath(contextTypeImport, 'context', outputPath)
importMap[importPath] = importMap[importPath] || new Set()
importMap[importPath].add(
contextTypeImport.alias
? `${contextTypeImport.export} as ${contextTypeImport.alias}`
: contextTypeImport.export
)
}
eachObj(rootTypings, (rootType, typeName) => {
if (typeof rootType !== 'string') {
const importPath = resolveImportPath(rootType, typeName, outputPath)
if (!forGlobal) {
if (contextTypeImport) {
const importPath = resolveImportPath(contextTypeImport, 'context', outputPath)
importMap[importPath] = importMap[importPath] || new Set()
importMap[importPath].add(
rootType.alias ? `${rootType.export} as ${rootType.alias}` : rootType.export
contextTypeImport.alias
? `${contextTypeImport.export} as ${contextTypeImport.alias}`
: contextTypeImport.export
)
}
})
eachObj(importMap, (val, key) => {
imports.push(`import type { ${Array.from(val).join(', ')} } from ${JSON.stringify(key)}`)
})
eachObj(sourceTypings, (rootType, typeName) => {
if (typeof rootType !== 'string') {
const importPath = resolveImportPath(rootType, typeName, outputPath)
importMap[importPath] = importMap[importPath] || new Set()
importMap[importPath].add(
rootType.alias ? `${rootType.export} as ${rootType.alias}` : rootType.export
)
}
})
eachObj(importMap, (val, key) => {
imports.push(`import type { ${Array.from(val).join(', ')} } from ${JSON.stringify(key)}`)
})
}
eachObj(this.printImports, (val, key) => {
const { default: def, ...rest } = val
const idents = []
@ -214,7 +303,29 @@ export class TypegenPrinter {
return imports.join('\n')
}
printDynamicInputFieldDefinitions() {
private maybeAddCoreImport(forGlobal = false) {
const nexusSchemaImportId = this.typegenInfo.nexusSchemaImportId ?? getOwnPackage().name
const {
dynamicFields: { dynamicInputFields, dynamicOutputFields },
} = this.schema.extensions.nexus.config
let shouldAdd = false
const hasDynamicFields = [dynamicInputFields, dynamicOutputFields].some((o) => Object.keys(o).length > 0)
if (!this.typegenInfo.globalsPath) {
shouldAdd = hasDynamicFields || this.hasDiscriminatedTypes
} else {
shouldAdd = forGlobal ? hasDynamicFields : this.hasDiscriminatedTypes
}
if (shouldAdd) {
this.printImports[nexusSchemaImportId] = {
core: true,
}
}
}
private printDynamicInputFieldDefinitions() {
const { dynamicInputFields } = this.schema.extensions.nexus.config.dynamicFields
// If there is nothing custom... exit
if (!Object.keys(dynamicInputFields).length) {
@ -242,7 +353,7 @@ export class TypegenPrinter {
.join('\n')
}
printDynamicOutputFieldDefinitions() {
private printDynamicOutputFieldDefinitions() {
const { dynamicOutputFields } = this.schema.extensions.nexus.config.dynamicFields
// If there is nothing custom... exit
if (!Object.keys(dynamicOutputFields).length) {
@ -270,7 +381,7 @@ export class TypegenPrinter {
.join('\n')
}
prependDoc(typeDef: string, typeDescription?: string | null) {
private prependDoc(typeDef: string, typeDescription?: string | null) {
let outStr = ''
if (typeDescription) {
let parts = typeDescription.split('\n').map((f) => f.trimLeft())
@ -285,7 +396,7 @@ export class TypegenPrinter {
return `${outStr}${typeDef}`
}
printDynamicOutputPropertyDefinitions() {
private printDynamicOutputPropertyDefinitions() {
const { dynamicOutputProperties } = this.schema.extensions.nexus.config.dynamicFields
// If there is nothing custom... exit
if (!Object.keys(dynamicOutputProperties).length) {
@ -304,9 +415,9 @@ export class TypegenPrinter {
.join('\n')
}
printInheritedFieldMap() {
private printInheritedFieldMap() {
const hasInterfaces: (
| (GraphQLInterfaceType & { getInterfaces(): GraphQLInterfaceType[] })
| (GraphQLInterfaceType & { getInterfaces(): ReadonlyArray<GraphQLInterfaceType> })
| GraphQLObjectType
)[] = []
const withInterfaces = hasInterfaces
@ -329,37 +440,15 @@ export class TypegenPrinter {
.join('\n')
}
printContext() {
private printContext() {
return this.typegenInfo.contextTypeImport?.alias || this.typegenInfo.contextTypeImport?.export || 'any'
}
buildResolveSourceTypeMap() {
const sourceMap: TypeMapping = {}
const abstractTypes: (GraphQLInterfaceType | GraphQLUnionType)[] = []
abstractTypes
.concat(this.groupedTypes.union)
.concat(this.groupedTypes.interface)
.forEach((type) => {
if (isInterfaceType(type)) {
const possibleNames = this.schema.getPossibleTypes(type).map((t) => t.name)
if (possibleNames.length > 0) {
sourceMap[type.name] = possibleNames.map((val) => `NexusGenRootTypes['${val}']`).join(' | ')
}
} else {
sourceMap[type.name] = type
.getTypes()
.map((t) => `NexusGenRootTypes['${t.name}']`)
.join(' | ')
}
})
return sourceMap
}
printAbstractTypeMembers() {
private printAbstractTypeMembers() {
return this.printTypeInterface('NexusGenAbstractTypeMembers', this.buildAbstractTypeMembers())
}
buildAbstractTypeMembers() {
private buildAbstractTypeMembers() {
const sourceMap: TypeMapping = {}
const abstractTypes: (GraphQLInterfaceType | GraphQLUnionType)[] = []
abstractTypes
@ -381,13 +470,13 @@ export class TypegenPrinter {
return sourceMap
}
printTypeNames(name: keyof GroupedTypes, exportName: string, source: string) {
private printTypeNames(name: keyof GroupedTypes, exportName: string, source: string) {
const obj = this.groupedTypes[name] as GraphQLNamedType[]
const typeDef = obj.length === 0 ? 'never' : `keyof ${source}`
return `export type ${exportName} = ${typeDef};`
}
printIsTypeOfObjectTypeNames(exportName: string) {
private printIsTypeOfObjectTypeNames(exportName: string) {
const objectTypes = this.groupedTypes.object.filter((o) => o.isTypeOf !== undefined)
const typeDef =
objectTypes.length === 0
@ -399,7 +488,7 @@ export class TypegenPrinter {
return `export type ${exportName} = ${typeDef};`
}
printResolveTypeAbstractTypes(exportName: string) {
private printResolveTypeAbstractTypes(exportName: string) {
const abstractTypes = [...this.groupedTypes.interface, ...this.groupedTypes.union].filter(
(o) => o.resolveType !== undefined
)
@ -414,7 +503,7 @@ export class TypegenPrinter {
return `export type ${exportName} = ${typeDef};`
}
printFeaturesConfig(exportName: string) {
private printFeaturesConfig(exportName: string) {
const abstractTypes = this.schema.extensions.nexus.config.features?.abstractTypeStrategies ?? {}
const unionProps = renderObject(mapValues(abstractTypes, (val) => val ?? false))
@ -424,7 +513,7 @@ export class TypegenPrinter {
.join('\n')
}
buildEnumTypeMap() {
private buildEnumTypeMap() {
const enumMap: TypeMapping = {}
this.groupedTypes.enum.forEach((e) => {
const sourceType = this.resolveSourceType(e.name)
@ -438,7 +527,7 @@ export class TypegenPrinter {
return enumMap
}
buildInputTypeMap() {
private buildInputTypeMap() {
const inputObjMap: TypeFieldMapping = {}
this.groupedTypes.input.forEach((input) => {
eachObj(input.getFields(), (field) => {
@ -449,7 +538,7 @@ export class TypegenPrinter {
return inputObjMap
}
buildScalarTypeMap() {
private buildScalarTypeMap() {
const scalarMap: TypeMapping = {}
this.groupedTypes.scalar.forEach((e) => {
if (isSpecifiedScalarType(e)) {
@ -466,19 +555,37 @@ export class TypegenPrinter {
return scalarMap
}
printInputTypeMap() {
return this.printTypeFieldInterface('NexusGenInputs', this.buildInputTypeMap(), 'input type')
private printInputTypeMap() {
const inputTypeMap = this.buildInputTypeMap()
if (this.typegenInfo.declareInputs) {
const declaredInputs: string[] = mapObj(inputTypeMap, (fields, inputName) =>
this.printNamedObj(inputName, fields)
)
return [...declaredInputs, this.printNamedMap('NexusGenInputs', inputTypeMap)].join('\n\n')
}
return this.printTypeFieldInterface('NexusGenInputs', inputTypeMap, 'input type')
}
printEnumTypeMap() {
return this.printTypeInterface('NexusGenEnums', this.buildEnumTypeMap())
private printEnumTypeMap() {
const enumTypeMap = this.buildEnumTypeMap()
if (this.typegenInfo.declareInputs) {
return [
...mapObj(enumTypeMap, (val, name) => `export type ${name} = ${val}`),
this.printNamedMap('NexusGenEnums', enumTypeMap),
].join('\n\n')
}
return this.printTypeInterface('NexusGenEnums', enumTypeMap)
}
printScalarTypeMap() {
private printScalarTypeMap() {
return this.printTypeInterface('NexusGenScalars', this.buildScalarTypeMap())
}
shouldDiscriminateType(
private shouldDiscriminateType(
abstractType: GraphQLAbstractType,
objectType: GraphQLObjectType
): 'required' | 'optional' | false {
@ -497,7 +604,7 @@ export class TypegenPrinter {
return 'required'
}
maybeDiscriminate(abstractType: GraphQLAbstractType, objectType: GraphQLObjectType) {
private maybeDiscriminate(abstractType: GraphQLAbstractType, objectType: GraphQLObjectType) {
const requiredOrOptional = this.shouldDiscriminateType(abstractType, objectType)
if (requiredOrOptional === false) {
@ -509,7 +616,7 @@ export class TypegenPrinter {
return `core.Discriminate<'${objectType.name}', '${requiredOrOptional}'>`
}
buildRootTypeMap(hasFields: Array<GraphQLInterfaceType | GraphQLObjectType | GraphQLUnionType>) {
private buildRootTypeMap(hasFields: Array<GraphQLInterfaceType | GraphQLObjectType | GraphQLUnionType>) {
const rootTypeMap: RootTypeMapping = {}
hasFields.forEach((type) => {
const rootTyping = this.resolveSourceType(type.name)
@ -534,8 +641,17 @@ export class TypegenPrinter {
} else {
eachObj(type.getFields(), (field) => {
const obj = (rootTypeMap[type.name] = rootTypeMap[type.name] || {})
if (!this.hasResolver(field, type)) {
if (typeof obj !== 'string') {
const fieldSourceType = this.fieldSourceType(field, type)
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] = [
this.argSeparator(field.type as GraphQLInputType, false),
this.printOutputType(field.type),
@ -548,44 +664,55 @@ export class TypegenPrinter {
return rootTypeMap
}
resolveSourceType(typeName: string): string | undefined {
const rootTyping = this.schema.extensions.nexus.config.rootTypings[typeName]
private resolveSourceType(typeName: string): string | undefined {
const rootTyping = this.schema.extensions.nexus.config.sourceTypings[typeName]
if (rootTyping) {
return typeof rootTyping === 'string' ? rootTyping : rootTyping.export
}
return (this.typegenInfo.sourceTypeMap as any)[typeName]
}
hasResolver(
private fieldSourceType(
field: GraphQLField<any, any>,
// Used in test mocking
_type: GraphQLObjectType
) {
if (field.extensions && field.extensions.nexus) {
if (field.extensions && isNexusFieldExtension(field.extensions.nexus)) {
return field.extensions.nexus.sourceType
}
return undefined
}
private hasResolver(
field: GraphQLField<any, any>,
// Used in test mocking
_type: GraphQLObjectType
) {
if (field.extensions && hasNexusExtension(field.extensions.nexus)) {
return field.extensions.nexus.hasDefinedResolver
}
return Boolean(field.resolve)
}
printObjectTypeMap() {
private printObjectTypeMap() {
return this.printRootTypeFieldInterface(
'NexusGenObjects',
this.buildRootTypeMap(this.groupedTypes.object)
)
}
printInterfaceTypeMap() {
private printInterfaceTypeMap() {
return this.printRootTypeFieldInterface(
'NexusGenInterfaces',
this.buildRootTypeMap(this.groupedTypes.interface)
)
}
printUnionTypeMap() {
private printUnionTypeMap() {
return this.printRootTypeFieldInterface('NexusGenUnions', this.buildRootTypeMap(this.groupedTypes.union))
}
printRootTypeDef() {
private printRootTypeDef() {
const toJoin: string[] = []
if (this.groupedTypes.interface.length) {
toJoin.push('NexusGenInterfaces')
@ -599,7 +726,7 @@ export class TypegenPrinter {
return `export type NexusGenRootTypes = ${toJoin.join(' & ')}`
}
printAllTypesMap() {
private printAllTypesMap() {
const toJoin: string[] = ['NexusGenRootTypes']
if (this.groupedTypes.scalar.length) {
toJoin.push('NexusGenScalars')
@ -610,7 +737,7 @@ export class TypegenPrinter {
return `export type NexusGenAllTypes = ${toJoin.join(' & ')}`
}
buildArgTypeMap() {
private buildArgTypeMap() {
const argTypeMap: Record<string, TypeFieldMapping> = {}
const hasFields: (GraphQLInterfaceType | GraphQLObjectType)[] = []
hasFields
@ -630,11 +757,38 @@ export class TypegenPrinter {
return argTypeMap
}
printArgTypeMap() {
return this.printArgTypeFieldInterface(this.buildArgTypeMap())
private printArgTypeMap() {
const argTypeMap = this.buildArgTypeMap()
if (this.typegenInfo.declareInputs) {
const declaredArgs: string[] = []
eachObj(argTypeMap, (fields, typeName) => {
eachObj(fields, (args, fieldName) => {
declaredArgs.push(this.printNamedObj(this.getArgsName(typeName, fieldName), args))
})
})
return [...declaredArgs, this.printArgTypeFieldInterface(argTypeMap)].join('\n\n')
}
return this.printArgTypeFieldInterface(argTypeMap)
}
buildReturnTypeMap() {
private getArgsName(typeName: string, fieldName: string) {
return `${typeName}${fieldName.slice(0, 1).toUpperCase().concat(fieldName.slice(1))}Args`
}
private printNamedObj(name: string, obj: Record<string, [string, string]>) {
return [
`export interface ${name} {`,
...mapObj(obj, (val, key) => ` ${key}${val[0]} ${val[1]}`),
`}`,
].join('\n')
}
private printNamedMap(name: string, obj: Record<string, any>) {
return [`export interface ${name} {`, ...mapObj(obj, (val, key) => ` ${key}: ${key}`), `}`].join('\n')
}
private buildReturnTypeMap() {
const returnTypeMap: TypeFieldMapping = {}
const hasFields: (GraphQLInterfaceType | GraphQLObjectType)[] = []
hasFields
@ -649,7 +803,7 @@ export class TypegenPrinter {
return returnTypeMap
}
buildReturnTypeNamesMap() {
private buildReturnTypeNamesMap() {
const returnTypeMap: TypeFieldMapping = {}
const hasFields: (GraphQLInterfaceType | GraphQLObjectType)[] = []
hasFields
@ -664,26 +818,26 @@ export class TypegenPrinter {
return returnTypeMap
}
printOutputType(type: GraphQLOutputType) {
private printOutputType(type: GraphQLOutputType) {
const returnType = this.typeToArr(type)
function combine(item: any[]): string {
if (item.length === 1) {
if (Array.isArray(item[0])) {
const toPrint = combine(item[0])
return toPrint.indexOf('null') === -1 ? `${toPrint}[]` : `Array<${toPrint}>`
return `ReadonlyArray<${toPrint}>`
}
return item[0]
}
if (Array.isArray(item[1])) {
const toPrint = combine(item[1])
return toPrint.indexOf('null') === -1 ? `${toPrint}[] | null` : `Array<${toPrint}> | null`
return `ReadonlyArray<${toPrint}> | null`
}
return `${item[1]} | null`
}
return `${combine(returnType)}; // ${type}`
}
typeToArr(type: GraphQLOutputType): any[] {
private typeToArr(type: GraphQLOutputType): any[] {
const typing = []
if (isNonNullType(type)) {
type = type.ofType
@ -695,18 +849,22 @@ export class TypegenPrinter {
} else if (isScalarType(type)) {
typing.push(this.printScalar(type))
} else if (isEnumType(type)) {
typing.push(`NexusGenEnums['${type.name}']`)
if (this.typegenInfo.declareInputs) {
typing.push(type.name)
} else {
typing.push(`NexusGenEnums['${type.name}']`)
}
} else if (isObjectType(type) || isInterfaceType(type) || isUnionType(type)) {
typing.push(`NexusGenRootTypes['${type.name}']`)
}
return typing
}
printFieldTypesMap() {
private printFieldTypesMap() {
return this.printTypeFieldInterface('NexusGenFieldTypes', this.buildReturnTypeMap(), 'field return type')
}
printFieldTypeNamesMap() {
private printFieldTypeNamesMap() {
return this.printTypeFieldInterface(
'NexusGenFieldTypeNames',
this.buildReturnTypeNamesMap(),
@ -714,11 +872,11 @@ export class TypegenPrinter {
)
}
normalizeArg(arg: GraphQLInputField | GraphQLArgument): [string, string] {
private normalizeArg(arg: GraphQLInputField | GraphQLArgument): [string, string] {
return [this.argSeparator(arg.type, Boolean(arg.defaultValue)), this.argTypeRepresentation(arg.type)]
}
argSeparator(type: GraphQLInputType, hasDefaultValue: boolean) {
private argSeparator(type: GraphQLInputType, hasDefaultValue: boolean) {
if (hasDefaultValue || isNonNullType(type)) {
return ':'
}
@ -726,18 +884,25 @@ export class TypegenPrinter {
return '?:'
}
argTypeRepresentation(arg: GraphQLInputType): string {
private argTypeRepresentation(arg: GraphQLInputType): string {
const argType = this.argTypeArr(arg)
const useReadonlyArrayForInputs = !!this.typegenInfo.useReadonlyArrayForInputs
function combine(item: any[]): string {
if (item.length === 1) {
if (Array.isArray(item[0])) {
const toPrint = combine(item[0])
if (useReadonlyArrayForInputs) {
return `ReadonlyArray<${toPrint}>`
}
return toPrint.indexOf('null') === -1 ? `${toPrint}[]` : `Array<${toPrint}>`
}
return item[0]
}
if (Array.isArray(item[1])) {
const toPrint = combine(item[1])
if (useReadonlyArrayForInputs) {
return `ReadonlyArray<${toPrint}> | null`
}
return toPrint.indexOf('null') === -1 ? `${toPrint}[] | null` : `Array<${toPrint}> | null`
}
return `${item[1]} | null`
@ -745,7 +910,7 @@ export class TypegenPrinter {
return `${combine(argType)}; // ${arg}`
}
argTypeArr(arg: GraphQLInputType): any[] {
private argTypeArr(arg: GraphQLInputType): any[] {
const typing = []
if (isNonNullType(arg)) {
arg = arg.ofType
@ -757,21 +922,29 @@ export class TypegenPrinter {
} else if (isScalarType(arg)) {
typing.push(this.printScalar(arg))
} else if (isEnumType(arg)) {
typing.push(`NexusGenEnums['${arg.name}']`)
if (this.typegenInfo.declareInputs) {
typing.push(arg.name)
} else {
typing.push(`NexusGenEnums['${arg.name}']`)
}
} else if (isInputObjectType(arg)) {
typing.push(`NexusGenInputs['${arg.name}']`)
if (this.typegenInfo.declareInputs) {
typing.push(arg.name)
} else {
typing.push(`NexusGenInputs['${arg.name}']`)
}
}
return typing
}
printTypeInterface(interfaceName: string, typeMapping: TypeMapping) {
private printTypeInterface(interfaceName: string, typeMapping: TypeMapping) {
return [`export interface ${interfaceName} {`]
.concat(mapObj(typeMapping, (val, key) => ` ${key}: ${val}`))
.concat('}')
.join('\n')
}
printRootTypeFieldInterface(interfaceName: string, typeMapping: RootTypeMapping) {
private printRootTypeFieldInterface(interfaceName: string, typeMapping: RootTypeMapping) {
return [`export interface ${interfaceName} {`]
.concat(
mapObj(typeMapping, (val, key) => {
@ -788,18 +961,26 @@ export class TypegenPrinter {
.join('\n')
}
printTypeFieldInterface(interfaceName: string, typeMapping: TypeFieldMapping, source: string) {
private printTypeFieldInterface(interfaceName: string, typeMapping: TypeFieldMapping, source: string) {
return [`export interface ${interfaceName} {`]
.concat(mapObj(typeMapping, this.printObj(' ', source)))
.concat('}')
.join('\n')
}
printArgTypeFieldInterface(typeMapping: Record<string, TypeFieldMapping>) {
private printArgTypeFieldInterface(typeMapping: Record<string, TypeFieldMapping>) {
return [`export interface NexusGenArgTypes {`]
.concat(
mapObj(typeMapping, (val, key) => {
return [` ${key}: {`]
mapObj(typeMapping, (val, typeName) => {
if (this.typegenInfo.declareInputs) {
return [` ${typeName}: {`]
.concat(
mapObj(val, (_, fieldName) => ` ${fieldName}: ${this.getArgsName(typeName, fieldName)}`)
)
.concat(' }')
.join('\n')
}
return [` ${typeName}: {`]
.concat(mapObj(val, this.printObj(' ', 'args')))
.concat(' }')
.join('\n')
@ -809,25 +990,26 @@ export class TypegenPrinter {
.join('\n')
}
printObj = (space: string, source: string) => (val: Record<string, [string, string]>, key: string) => {
return [`${space}${key}: { // ${source}`]
.concat(
mapObj(val, (v2, k2) => {
return `${space} ${k2}${v2[0]} ${v2[1]}`
})
)
.concat(`${space}}`)
.join('\n')
}
private printObj =
(space: string, source: string) => (val: Record<string, [string, string]>, key: string) => {
return [`${space}${key}: { // ${source}`]
.concat(
mapObj(val, (v2, k2) => {
return `${space} ${k2}${v2[0]} ${v2[1]}`
})
)
.concat(`${space}}`)
.join('\n')
}
printScalar(type: GraphQLScalarType) {
private printScalar(type: GraphQLScalarType) {
if (isSpecifiedScalarType(type)) {
return this.resolveSourceType(type.name) ?? SpecifiedScalars[type.name as SpecifiedScalarNames]
}
return `NexusGenScalars['${type.name}']`
}
printPlugins() {
private printPlugins() {
const pluginFieldExt: string[] = [
` interface NexusGenPluginFieldConfig<TypeName extends string, FieldName extends string> {`,
]
@ -876,7 +1058,7 @@ export class TypegenPrinter {
].join('\n')
}
printType(strLike: StringLike | StringLike[]): string {
private printType(strLike: StringLike | StringLike[]): string {
if (Array.isArray(strLike)) {
return strLike.map((s) => this.printType(s)).join('\n')
}
@ -893,7 +1075,7 @@ export class TypegenPrinter {
return strLike
}
addImport(i: PrintedGenTypingImport) {
private addImport(i: PrintedGenTypingImport) {
/* istanbul ignore if */
if (!isNexusPrintedGenTypingImport(i)) {
console.warn(`Expected printedGenTypingImport, saw ${i}`)

View File

@ -155,6 +155,8 @@ export type GenTypesShapeKeys =
| 'inputTypes'
| 'rootTypes'
| 'inputTypeShapes'
| 'directives'
| 'directiveArgs'
| 'argTypes'
| 'fieldTypes'
| 'fieldTypeNames'
@ -179,7 +181,7 @@ export type GenTypesShapeKeys =
export type GenTypesShape = Record<GenTypesShapeKeys, any>
export type GetGen<K extends GenTypesShapeKeys, Fallback = any> = NexusGen extends infer GenTypes
? GenTypes extends GenTypesShape
? K extends keyof GenTypes
? GenTypes[K]
: Fallback
: Fallback
@ -202,10 +204,8 @@ export type GetGen3<
: Fallback
export type HasGen<K extends GenTypesShapeKeys> = NexusGen extends infer GenTypes
? GenTypes extends GenTypesShape
? K extends keyof GenTypes
? true
: false
? K extends keyof GenTypes
? true
: false
: false
@ -213,11 +213,9 @@ export type HasGen2<
K extends GenTypesShapeKeys,
K2 extends Extract<keyof GenTypesShape[K], string>
> = NexusGen extends infer GenTypes
? GenTypes extends GenTypesShape
? K extends keyof GenTypes
? K2 extends keyof GenTypes[K]
? true
: false
? K extends keyof GenTypes
? K2 extends keyof GenTypes[K]
? true
: false
: false
: false
@ -227,12 +225,10 @@ export type HasGen3<
K2 extends Extract<keyof GenTypesShape[K], string>,
K3 extends Extract<keyof GenTypesShape[K][K2], string>
> = NexusGen extends infer GenTypes
? GenTypes extends GenTypesShape
? K extends keyof GenTypes
? K2 extends keyof GenTypes[K]
? K3 extends keyof GenTypes[K][K2]
? true
: false
? K extends keyof GenTypes
? K2 extends keyof GenTypes[K]
? K3 extends keyof GenTypes[K][K2]
? true
: false
: false
: false

View File

@ -1,51 +1,75 @@
import * as path from 'path'
import type { BuilderConfigInput } from './builder'
import type { ConfiguredTypegen } from './core'
import { nodeImports } from './node'
import type { TypegenMetadataConfig } from './typegenMetadata'
import { assertAbsolutePath, getOwnPackage, isProductionStage } from './utils'
/** Normalizes the builder config into the config we need for typegen */
export function resolveTypegenConfig(config: BuilderConfigInput): TypegenMetadataConfig {
const {
outputs,
shouldGenerateArtifacts = Boolean(!process.env.NODE_ENV || process.env.NODE_ENV !== 'production'),
...rest
} = config
const { outputs, shouldGenerateArtifacts = defaultShouldGenerateArtifacts(), ...rest } = config
const defaultSDLFilePath = path.join(process.cwd(), 'schema.graphql')
function getOutputPaths() {
const defaultSDLFilePath = nodeImports().path.join(process.cwd(), 'schema.graphql')
let typegenFilePath: string | null = null
let sdlFilePath: string | null = null
let typegenFilePath: ConfiguredTypegen | null = null
let sdlFilePath: string | null = null
if (outputs === undefined) {
if (isProductionStage()) {
if (outputs === undefined) {
if (isProductionStage()) {
sdlFilePath = defaultSDLFilePath
}
} else if (outputs === true) {
sdlFilePath = defaultSDLFilePath
} else if (typeof outputs === 'object') {
if (outputs.schema === true) {
sdlFilePath = defaultSDLFilePath
} else if (typeof outputs.schema === 'string') {
sdlFilePath = assertAbsolutePath(outputs.schema, 'outputs.schema')
} else if (outputs.schema === undefined && isProductionStage()) {
}
// handle typegen configuration
if (typeof outputs.typegen === 'string') {
typegenFilePath = {
outputPath: assertAbsolutePath(outputs.typegen, 'outputs.typegen'),
}
} else if (typeof outputs.typegen === 'object') {
typegenFilePath = {
...outputs.typegen,
outputPath: assertAbsolutePath(outputs.typegen.outputPath, 'outputs.typegen.outputPath'),
} as ConfiguredTypegen
if (outputs.typegen.globalsPath) {
typegenFilePath.globalsPath = assertAbsolutePath(
outputs.typegen.globalsPath,
'outputs.typegen.globalsPath'
)
}
}
} else if (outputs !== false) {
console.warn(
`You should specify a configuration value for outputs in Nexus' makeSchema. ` +
`Provide one to remove this warning.`
)
}
} else if (outputs === true) {
sdlFilePath = defaultSDLFilePath
} else if (typeof outputs === 'object') {
if (outputs.schema === true) {
sdlFilePath = defaultSDLFilePath
} else if (typeof outputs.schema === 'string') {
sdlFilePath = assertAbsolutePath(outputs.schema, 'outputs.schema')
} else if (outputs.schema === undefined && isProductionStage()) {
return {
typegenFilePath,
sdlFilePath,
}
// handle typegen configuration
if (typeof outputs.typegen === 'string') {
typegenFilePath = assertAbsolutePath(outputs.typegen, 'outputs.typegen')
}
} else if (outputs !== false) {
console.warn(
`You should specify a configuration value for outputs in Nexus' makeSchema. ` +
`Provide one to remove this warning.`
)
}
return {
...rest,
nexusSchemaImportId: getOwnPackage().name,
outputs: {
typegen: shouldGenerateArtifacts ? typegenFilePath : null,
schema: shouldGenerateArtifacts ? sdlFilePath : null,
typegen: shouldGenerateArtifacts ? getOutputPaths().typegenFilePath : 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 {
GraphQLEnumType,
GraphQLInputObjectType,
@ -22,7 +21,6 @@ import {
isWrappingType,
specifiedScalarTypes,
} from 'graphql'
import * as Path from 'path'
import { decorateType } from './definitions/decorateType'
import { isNexusMetaType, NexusMetaType, resolveNexusMetaType } from './definitions/nexusMeta'
import {
@ -31,9 +29,10 @@ import {
AllNexusTypeDefs,
isNexusWrappingType,
isNexusArgDef,
AllNexusNamedInputTypeDefs,
AllNamedInputTypeDefs,
} from './definitions/wrapping'
import {
Maybe,
MissingType,
NexusFeatures,
NexusGraphQLSchema,
@ -41,6 +40,7 @@ import {
TypingImport,
withNexusSymbol,
} from './definitions/_types'
import { nodeImports } from './node'
export const isInterfaceField = (type: GraphQLObjectType, fieldName: string) => {
return type.getInterfaces().some((i) => Boolean(i.getFields()[fieldName]))
@ -149,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 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}"`)
}
return pathName
@ -177,7 +177,7 @@ export function groupTypes(schema: GraphQLSchema) {
Object.keys(schemaTypeMap)
.sort()
.forEach((typeName) => {
if (typeName.indexOf('__') === 0) {
if (typeName.startsWith('__')) {
return
}
const type = schema.getType(typeName)
@ -220,7 +220,7 @@ export function isPromiseLike(value: any): value is PromiseLike<any> {
export const typeScriptFileExtension = /(\.d)?\.ts$/
function makeRelativePathExplicitlyRelative(path: string) {
if (Path.isAbsolute(path)) return path
if (nodeImports().path.isAbsolute(path)) return path
if (path.startsWith('./')) return path
return `./${path}`
}
@ -233,7 +233,7 @@ function nixifyPathSlashes(path: string): string {
* Format a path so it is suitable to be used as a module import.
*
* - Implicitly relative is made explicitly relative - TypeScript file extension is stripped - Windows slashes
* converted into *nix slashes
* converted into *nix slashes
*
* Do not pass Node module IDs here as they will be treated as relative paths e.g. "react" "@types/react" etc.
*/
@ -242,6 +242,7 @@ export function formatPathForModuleImport(path: string) {
}
export function relativePathTo(absolutePath: string, fromPath: string): string {
const Path = nodeImports().path
const filename = Path.basename(absolutePath)
const relative = Path.relative(Path.dirname(fromPath), Path.dirname(absolutePath))
return formatPathForModuleImport(Path.join(relative, filename))
@ -266,7 +267,7 @@ export interface PrintedGenTypingConfig {
name: string
optional: boolean
type: string
description?: string
description?: Maybe<string>
imports?: PrintedGenTypingImport[]
}
@ -476,20 +477,18 @@ export function casesHandled(x: never): never {
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) {
// 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) {
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(
`Expected an absolute path or Node package for the root typing path of the type "${typeName}", saw "${rootTypePath}"`
)
@ -501,7 +500,7 @@ export function resolveImportPath(rootType: TypingImport, typeName: string, outp
} catch (e) {
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`)
}
@ -509,7 +508,7 @@ export function resolveImportPath(rootType: TypingImport, typeName: string, outp
return rootTypePath
}
if (Path.isAbsolute(rootTypePath)) {
if (nodeImports().path.isAbsolute(rootTypePath)) {
return relativePathTo(rootTypePath, outputPath)
}
@ -517,7 +516,7 @@ export function resolveImportPath(rootType: TypingImport, typeName: string, outp
}
/** Given the right hand side of an arg definition, returns the underlying "named type" for us to add to the builder */
export function getArgNamedType(argDef: AllNexusArgsDefs | string): AllNexusNamedInputTypeDefs | string {
export function getArgNamedType(argDef: AllNexusArgsDefs | string): AllNamedInputTypeDefs | string {
let finalValue = argDef
if (typeof finalValue === 'string') {
return finalValue
@ -552,7 +551,7 @@ export function getNexusNamedType(
namedType = resolveNexusMetaType(namedType)
}
}
return namedType
return namedType as AllNexusNamedTypeDefs | GraphQLNamedType | string
}
/** Assertion utility with nexus-aware feedback for users. */
@ -597,12 +596,20 @@ export function graphql15InterfaceConfig<T extends GraphQLInterfaceTypeConfig<an
}
export function graphql15InterfaceType<T extends GraphQLInterfaceType>(
type: T & { getInterfaces?: () => GraphQLInterfaceType[] }
): T & { getInterfaces(): GraphQLInterfaceType[] } {
type: T & { getInterfaces?: () => ReadonlyArray<GraphQLInterfaceType> }
): T & { getInterfaces(): ReadonlyArray<GraphQLInterfaceType> } {
if (typeof type.getInterfaces !== 'function') {
type.getInterfaces = () => []
}
return type as T & { getInterfaces(): GraphQLInterfaceType[] }
return type as T & { getInterfaces(): ReadonlyArray<GraphQLInterfaceType> }
}
/** @internal */
export function unpack<T extends object>(val: T | (() => T)): T {
if (val instanceof Function) {
return val()
}
return val
}
/**
@ -627,3 +634,10 @@ export const ownProp = {
return Object.getOwnPropertyDescriptor(obj, key)?.value
},
}
export function result<T>(val: T | (() => T)): T {
if (val instanceof Function) {
return val()
}
return val as T
}

View File

@ -3,7 +3,7 @@ import { join, relative } from 'path'
import { core } from '../../src'
import type { BuilderConfigInput } from '../../src/core'
const { generateSchema, typegenFormatPrettier } = core
const { generateSchema } = core
type HookSettings = {
rootDir: string
@ -29,12 +29,8 @@ export async function generateTypegen(settings: HookSettings) {
},
shouldGenerateArtifacts: true,
plugins: plugins || [],
async formatTypegen(source, type) {
const prettierConfigPath = require.resolve('../../.prettierrc')
const content = await typegenFormatPrettier(prettierConfigPath)(source, type)
return content.replace("'nexus'", `'${importPath}'`)
},
prettierConfig: require.resolve('../../.prettierrc'),
formatTypegen: (content) => content.replace('from "nexus"', `from '${importPath}'`),
features: {
abstractTypeStrategies: {
resolveType: true,

View File

@ -90,6 +90,11 @@ export type NexusGenScalarNames = keyof NexusGenScalars;
export type NexusGenUnionNames = never;
export type NexusGenDirectives = never
export interface NexusGenDirectiveArgs {
}
export type NexusGenObjectsUsingAbstractStrategyIsTypeOf = never;
export type NexusGenAbstractsUsingStrategyResolveType = never;
@ -105,6 +110,8 @@ export type NexusGenFeaturesConfig = {
export interface NexusGenTypes {
context: any;
inputTypes: NexusGenInputs;
directives: NexusGenDirectives;
directiveArgs: NexusGenDirectiveArgs;
rootTypes: NexusGenRootTypes;
inputTypeShapes: NexusGenInputs & NexusGenEnums & NexusGenScalars;
argTypes: NexusGenArgTypes;

View File

@ -0,0 +1,155 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`builder can replace the Mutation root type with an alternate type 1`] = `
"schema {
query: Query
mutation: RootMutation
}
type Mutation {
ok: String
}
type Query {
ok: Boolean!
}
type RootMutation {
name: String
}"
`;
exports[`builder can replace the Query root type with an alternate type 1`] = `
"schema {
query: RootQuery
}
type Query {
ok: String
}
type RootQuery {
name: String
}"
`;
exports[`builder can replace the Subscription root type with an alternate type 1`] = `
"schema {
query: Query
subscription: RootSubscription
}
type Query {
ok: Boolean!
}
type RootSubscription {
name: String
}
type Subscription {
ok: String
}"
`;
exports[`builder does not add a placeholder Query type when an alternate queryRoot has been defined 1`] = `
"schema {
query: RootQuery
}
type RootQuery {
name: String
}"
`;
exports[`builder.mergeSchema Merges Mutation & Query types by default: merged mutation 1`] = `
"type Mutation {
externalMutation(a: String): String
localMutation: String
}"
`;
exports[`builder.mergeSchema Merges Mutation & Query types by default: merged query 1`] = `
"type Query {
externalFn(a: String): String
localFn: String
}"
`;
exports[`builder.mergeSchema Merges Mutation & Query types by default: unmerged mutation 1`] = `
"type Mutation {
localMutation: String
}"
`;
exports[`builder.mergeSchema Merges Mutation & Query types by default: unmerged query 1`] = `
"type Query {
localFn: String
}"
`;
exports[`builder.mergeSchema can merge with an externally created schema 1`] = `
"type Author implements Node {
books: [Book]
\\"\\"\\"A Node ID is globally unique\\"\\"\\"
id: ID!
}
type Book implements Node {
id: ID!
name: String
}
interface ExternalNode {
id: ID!
}
type InternalType {
fieldName: String
}
interface Node {
\\"\\"\\"A Node ID is globally unique\\"\\"\\"
id: ID!
}
type Query {
internalNodesByIds(ids: [ID!]!, internal: String!): [Node]!
node(id: ID!): Node
someBook: Book
userByUuids(uuid: UUID): User
}
scalar UUID
type User implements ExternalNode & Node {
id: ID!
name: String
}"
`;
exports[`builder.mergeSchema can merge with local types: merged 1`] = `
"type User implements Node & ExternalNode {
id: ID!
name: String
localName: String
}"
`;
exports[`builder.mergeSchema can merge with local types: unmerged 1`] = `
"type User {
localName: String
}"
`;
exports[`graphql-js interop extend types works with GraphQLNamedType (#88) 1`] = `
"type Query {
viewer: Viewer
}
type Viewer {
name: String
age: Int
}"
`;

View File

@ -1,5 +1,25 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`enumType can alias as a nexus method 1`] = `
"enum ABC {
one
three
two
}
input Input {
inAbc: ABC
}
type Out {
outAbc: ABC
}
type Query {
ok: Boolean!
}"
`;
exports[`extendInputType should allow extending input objects 1`] = `
"input InputTest {
hello: String

View File

@ -1,13 +1,20 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`makeSchema directives can specify custom directives 1`] = `
"directive @customDirective(code: Int = 42) on FRAGMENT_DEFINITION
type Query {
ok: Boolean!
}"
`;
exports[`makeSchema shouldExitAfterGenerateArtifacts accepts a customPrintSchemaFn 1`] = `
"### This file was generated by Nexus Schema
### Do not make changes to this file directly
type Query {
# Example boolean field
\\"\\"\\"Example boolean field\\"\\"\\"
ok: Boolean
}
"
}"
`;

View File

@ -4,30 +4,26 @@ exports[`nonNullDefaults false/false on schema 1`] = `
"type Query {
stringList: [String]
test(test: Int): Boolean
}
"
}"
`;
exports[`nonNullDefaults false/false on type 1`] = `
"type Query {
stringList: [String]
test(test: Int): Boolean
}
"
}"
`;
exports[`nonNullDefaults true/true on schema 1`] = `
"type Query {
stringList: [String!]!
test(test: Int!): Boolean!
}
"
}"
`;
exports[`nonNullDefaults true/true on type 1`] = `
"type Query {
stringList: [String!]!
test(test: Int!): Boolean!
}
"
}"
`;

View File

@ -31,8 +31,7 @@ exports[`plugin has an onAddOutputField / onAddInputField / onAddArg option, whi
input SomeType {
inputField: [Boolean]
}
"
}"
`;
exports[`plugin has an onMissingType, which will be called in order when we encounter a missing type 1`] = `
@ -57,8 +56,7 @@ type UserConnection {
type UserEdge {
cursor: String
node: User
}
"
}"
`;
exports[`plugin is applied to the resolver for every field in the schema 1`] = `

View File

@ -7,33 +7,29 @@ exports[`onInstall plugins does not have access to inline types 1`] = `
type Query {
bar(inline: Inline): String
}
"
}"
`;
exports[`onInstall plugins does not see fallback ok-query 1`] = `
"type Query {
ok: Boolean!
}
"
}"
`;
exports[`onInstall plugins has access to top-level types 1`] = `
"type foo {
bar: String
}
type Query {
"type Query {
ok: Boolean!
}
"
type foo {
bar: String
}"
`;
exports[`onInstall plugins may contribute types 1`] = `
"type Query {
something: String
}
"
}"
`;
exports[`runtime config validation checks name is not empty 1`] = `"Plugin \\"\\" is giving an invalid value for property name: empty string"`;

View File

@ -55,9 +55,9 @@ exports[`typegenPrinter should not print roots for fields with resolvers 1`] = `
Mutation: {};
Post: { // root type
author: NexusGenRootTypes['User']; // User!
geo: number[][]; // [[Float!]!]!
geo: ReadonlyArray<ReadonlyArray<number>>; // [[Float!]!]!
id: string; // ID!
messyGeo?: Array<number[] | null> | null; // [[Float!]]
messyGeo?: ReadonlyArray<ReadonlyArray<number> | null> | null; // [[Float!]]
uuid: NexusGenScalars['UUID']; // UUID!
}
Query: {};
@ -75,7 +75,7 @@ exports[`typegenPrinter should not print roots for fields with resolvers 2`] = `
exports[`typegenPrinter should print a interface type map 1`] = `
"export interface NexusGenInterfaces {
Node: core.Discriminate<'Post', 'required'> | core.Discriminate<'User', 'required'>;
Node: core.Discriminate<'Post', 'optional'> | core.Discriminate<'User', 'optional'>;
}"
`;
@ -84,9 +84,9 @@ exports[`typegenPrinter should print a object type map 1`] = `
Mutation: {};
Post: { // root type
author: NexusGenRootTypes['User']; // User!
geo: number[][]; // [[Float!]!]!
geo: ReadonlyArray<ReadonlyArray<number>>; // [[Float!]!]!
id: string; // ID!
messyGeo?: Array<number[] | null> | null; // [[Float!]]
messyGeo?: ReadonlyArray<ReadonlyArray<number> | null> | null; // [[Float!]]
uuid: NexusGenScalars['UUID']; // UUID!
}
Query: {};
@ -96,7 +96,7 @@ exports[`typegenPrinter should print a object type map 1`] = `
name: string; // String!
outEnum?: NexusGenEnums['SomeEnum'] | null; // SomeEnum
phone?: string | null; // String
posts: NexusGenRootTypes['Post'][]; // [Post!]!
posts: ReadonlyArray<NexusGenRootTypes['Post']>; // [Post!]!
}
}"
`;
@ -106,17 +106,17 @@ exports[`typegenPrinter should print a return type map 1`] = `
Mutation: { // field return type
createPost: NexusGenRootTypes['Post']; // Post!
registerClick: NexusGenRootTypes['Query']; // Query!
someList: Array<string | null>; // [String]!
someList: ReadonlyArray<string | null>; // [String]!
}
Post: { // field return type
author: NexusGenRootTypes['User']; // User!
geo: number[][]; // [[Float!]!]!
geo: ReadonlyArray<ReadonlyArray<number>>; // [[Float!]!]!
id: string; // ID!
messyGeo: Array<number[] | null> | null; // [[Float!]]
messyGeo: ReadonlyArray<ReadonlyArray<number> | null> | null; // [[Float!]]
uuid: NexusGenScalars['UUID']; // UUID!
}
Query: { // field return type
posts: NexusGenRootTypes['Post'][]; // [Post!]!
posts: ReadonlyArray<NexusGenRootTypes['Post']>; // [Post!]!
unionField: NexusGenRootTypes['ExampleUnion']; // ExampleUnion!
user: NexusGenRootTypes['User']; // User!
}
@ -126,7 +126,7 @@ exports[`typegenPrinter should print a return type map 1`] = `
name: string; // String!
outEnum: NexusGenEnums['SomeEnum'] | null; // SomeEnum
phone: string | null; // String
posts: NexusGenRootTypes['Post'][]; // [Post!]!
posts: ReadonlyArray<NexusGenRootTypes['Post']>; // [Post!]!
}
Node: { // field return type
id: string; // ID!
@ -138,7 +138,7 @@ exports[`typegenPrinter should print a root type map 1`] = `"export type NexusGe
exports[`typegenPrinter should print a union type map 1`] = `
"export interface NexusGenUnions {
ExampleUnion: core.Discriminate<'Post', 'required'> | core.Discriminate<'User', 'required'>;
ExampleUnion: core.Discriminate<'Post', 'optional'> | core.Discriminate<'User', 'optional'>;
}"
`;
@ -189,9 +189,9 @@ export interface NexusGenObjects {
Mutation: {};
Post: { // root type
author: NexusGenRootTypes['User']; // User!
geo: number[][]; // [[Float!]!]!
geo: ReadonlyArray<ReadonlyArray<number>>; // [[Float!]!]!
id: string; // ID!
messyGeo?: Array<number[] | null> | null; // [[Float!]]
messyGeo?: ReadonlyArray<ReadonlyArray<number> | null> | null; // [[Float!]]
uuid: NexusGenScalars['UUID']; // UUID!
}
Query: {};
@ -201,16 +201,16 @@ export interface NexusGenObjects {
name: string; // String!
outEnum?: NexusGenEnums['SomeEnum'] | null; // SomeEnum
phone?: string | null; // String
posts: NexusGenRootTypes['Post'][]; // [Post!]!
posts: ReadonlyArray<NexusGenRootTypes['Post']>; // [Post!]!
}
}
export interface NexusGenInterfaces {
Node: core.Discriminate<'Post', 'required'> | core.Discriminate<'User', 'required'>;
Node: core.Discriminate<'Post', 'optional'> | core.Discriminate<'User', 'optional'>;
}
export interface NexusGenUnions {
ExampleUnion: core.Discriminate<'Post', 'required'> | core.Discriminate<'User', 'required'>;
ExampleUnion: core.Discriminate<'Post', 'optional'> | core.Discriminate<'User', 'optional'>;
}
export type NexusGenRootTypes = NexusGenInterfaces & NexusGenObjects & NexusGenUnions
@ -221,17 +221,17 @@ export interface NexusGenFieldTypes {
Mutation: { // field return type
createPost: NexusGenRootTypes['Post']; // Post!
registerClick: NexusGenRootTypes['Query']; // Query!
someList: Array<string | null>; // [String]!
someList: ReadonlyArray<string | null>; // [String]!
}
Post: { // field return type
author: NexusGenRootTypes['User']; // User!
geo: number[][]; // [[Float!]!]!
geo: ReadonlyArray<ReadonlyArray<number>>; // [[Float!]!]!
id: string; // ID!
messyGeo: Array<number[] | null> | null; // [[Float!]]
messyGeo: ReadonlyArray<ReadonlyArray<number> | null> | null; // [[Float!]]
uuid: NexusGenScalars['UUID']; // UUID!
}
Query: { // field return type
posts: NexusGenRootTypes['Post'][]; // [Post!]!
posts: ReadonlyArray<NexusGenRootTypes['Post']>; // [Post!]!
unionField: NexusGenRootTypes['ExampleUnion']; // ExampleUnion!
user: NexusGenRootTypes['User']; // User!
}
@ -241,7 +241,7 @@ export interface NexusGenFieldTypes {
name: string; // String!
outEnum: NexusGenEnums['SomeEnum'] | null; // SomeEnum
phone: string | null; // String
posts: NexusGenRootTypes['Post'][]; // [Post!]!
posts: ReadonlyArray<NexusGenRootTypes['Post']>; // [Post!]!
}
Node: { // field return type
id: string; // ID!
@ -328,9 +328,16 @@ export type NexusGenScalarNames = keyof NexusGenScalars;
export type NexusGenUnionNames = keyof NexusGenUnions;
export type NexusGenDirectives = \\"TestFieldDirective\\"
export interface NexusGenDirectiveArgs {
TestFieldDirective: {
}
}
export type NexusGenObjectsUsingAbstractStrategyIsTypeOf = never;
export type NexusGenAbstractsUsingStrategyResolveType = never;
export type NexusGenAbstractsUsingStrategyResolveType = \\"ExampleUnion\\" | \\"Node\\";
export type NexusGenFeaturesConfig = {
abstractTypeStrategies: {
@ -343,6 +350,8 @@ export type NexusGenFeaturesConfig = {
export interface NexusGenTypes {
context: TestContext;
inputTypes: NexusGenInputs;
directives: NexusGenDirectives;
directiveArgs: NexusGenDirectiveArgs;
rootTypes: NexusGenRootTypes;
inputTypeShapes: NexusGenInputs & NexusGenEnums & NexusGenScalars;
argTypes: NexusGenArgTypes;

View File

@ -0,0 +1,801 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`typegenPrinter: globals should print the full output 1`] = `
Object {
"globalTypes": "/**
* This file was generated by Nexus Schema
* Do not make changes to this file directly
*/
import type { NexusGenTypes } from './types.gen'
declare global {
interface NexusGen extends NexusGenTypes {}
}
declare global {
interface NexusGenPluginTypeConfig<TypeName extends string> {
}
interface NexusGenPluginInputTypeConfig<TypeName extends string> {
}
interface NexusGenPluginFieldConfig<TypeName extends string, FieldName extends string> {
}
interface NexusGenPluginInputFieldConfig<TypeName extends string, FieldName extends string> {
}
interface NexusGenPluginSchemaConfig {
}
interface NexusGenPluginArgConfig {
}
}",
"tsTypes": "/**
* This file was generated by Nexus Schema
* Do not make changes to this file directly
*/
import type { TestContext } from \\"./../__helpers/index\\"
import type { core } from \\"nexus\\"
export interface CreatePostInput {
author: string; // ID!
geo: Array<Array<number | null>>; // [[Float]!]!
name: string; // String!
}
export interface PostFilters {
order: OrderEnum; // OrderEnum!
search: string | null; // String
}
export interface NexusGenInputs {
CreatePostInput: CreatePostInput
PostFilters: PostFilters
}
export type OrderEnum = \\"ASC\\" | \\"DESC\\"
export type SomeEnum = \\"A\\" | \\"B\\"
export interface NexusGenEnums {
OrderEnum: OrderEnum
SomeEnum: SomeEnum
}
export interface NexusGenScalars {
String: string
Int: number
Float: number
Boolean: boolean
ID: string
UUID: string
}
export interface NexusGenObjects {
Mutation: {};
Post: { // root type
author: NexusGenRootTypes['User']; // User!
geo: ReadonlyArray<ReadonlyArray<number>>; // [[Float!]!]!
id: string; // ID!
messyGeo?: ReadonlyArray<ReadonlyArray<number> | null> | null; // [[Float!]]
uuid: NexusGenScalars['UUID']; // UUID!
}
Query: {};
User: { // root type
email: string; // String!
id: string; // ID!
name: string; // String!
outEnum?: SomeEnum | null; // SomeEnum
phone?: string | null; // String
posts: ReadonlyArray<NexusGenRootTypes['Post']>; // [Post!]!
}
}
export interface NexusGenInterfaces {
Node: core.Discriminate<'Post', 'optional'> | core.Discriminate<'User', 'optional'>;
}
export interface NexusGenUnions {
ExampleUnion: core.Discriminate<'Post', 'optional'> | core.Discriminate<'User', 'optional'>;
}
export type NexusGenRootTypes = NexusGenInterfaces & NexusGenObjects & NexusGenUnions
export type NexusGenAllTypes = NexusGenRootTypes & NexusGenScalars & NexusGenEnums
export interface NexusGenFieldTypes {
Mutation: { // field return type
createPost: NexusGenRootTypes['Post']; // Post!
registerClick: NexusGenRootTypes['Query']; // Query!
someList: ReadonlyArray<string | null>; // [String]!
}
Post: { // field return type
author: NexusGenRootTypes['User']; // User!
geo: ReadonlyArray<ReadonlyArray<number>>; // [[Float!]!]!
id: string; // ID!
messyGeo: ReadonlyArray<ReadonlyArray<number> | null> | null; // [[Float!]]
uuid: NexusGenScalars['UUID']; // UUID!
}
Query: { // field return type
posts: ReadonlyArray<NexusGenRootTypes['Post']>; // [Post!]!
unionField: NexusGenRootTypes['ExampleUnion']; // ExampleUnion!
user: NexusGenRootTypes['User']; // User!
}
User: { // field return type
email: string; // String!
id: string; // ID!
name: string; // String!
outEnum: SomeEnum | null; // SomeEnum
phone: string | null; // String
posts: ReadonlyArray<NexusGenRootTypes['Post']>; // [Post!]!
}
Node: { // field return type
id: string; // ID!
}
}
export interface NexusGenFieldTypeNames {
Mutation: { // field return type name
createPost: 'Post'
registerClick: 'Query'
someList: 'String'
}
Post: { // field return type name
author: 'User'
geo: 'Float'
id: 'ID'
messyGeo: 'Float'
uuid: 'UUID'
}
Query: { // field return type name
posts: 'Post'
unionField: 'ExampleUnion'
user: 'User'
}
User: { // field return type name
email: 'String'
id: 'ID'
name: 'String'
outEnum: 'SomeEnum'
phone: 'String'
posts: 'Post'
}
Node: { // field return type name
id: 'ID'
}
}
export interface MutationCreatePostArgs {
input: CreatePostInput; // CreatePostInput!
}
export interface MutationRegisterClickArgs {
uuid?: NexusGenScalars['UUID'] | null; // UUID
}
export interface MutationSomeListArgs {
items: Array<string | null>; // [String]!
}
export interface QueryPostsArgs {
filters: PostFilters; // PostFilters!
}
export interface UserNameArgs {
prefix?: string | null; // String
}
export interface UserPostsArgs {
filters?: PostFilters | null; // PostFilters
}
export interface NexusGenArgTypes {
Mutation: {
createPost: MutationCreatePostArgs
registerClick: MutationRegisterClickArgs
someList: MutationSomeListArgs
}
Query: {
posts: QueryPostsArgs
}
User: {
name: UserNameArgs
posts: UserPostsArgs
}
}
export interface NexusGenAbstractTypeMembers {
ExampleUnion: \\"Post\\" | \\"User\\"
Node: \\"Post\\" | \\"User\\"
}
export interface NexusGenTypeInterfaces {
Post: \\"Node\\"
User: \\"Node\\"
}
export type NexusGenObjectNames = keyof NexusGenObjects;
export type NexusGenInputNames = keyof NexusGenInputs;
export type NexusGenEnumNames = keyof NexusGenEnums;
export type NexusGenInterfaceNames = keyof NexusGenInterfaces;
export type NexusGenScalarNames = keyof NexusGenScalars;
export type NexusGenUnionNames = keyof NexusGenUnions;
export type NexusGenDirectives = \\"TestFieldDirective\\"
export interface NexusGenDirectiveArgs {
TestFieldDirective: {
}
}
export type NexusGenObjectsUsingAbstractStrategyIsTypeOf = never;
export type NexusGenAbstractsUsingStrategyResolveType = \\"ExampleUnion\\" | \\"Node\\";
export type NexusGenFeaturesConfig = {
abstractTypeStrategies: {
__typename: true
isTypeOf: false
resolveType: false
}
}
export interface NexusGenTypes {
context: TestContext;
inputTypes: NexusGenInputs;
directives: NexusGenDirectives;
directiveArgs: NexusGenDirectiveArgs;
rootTypes: NexusGenRootTypes;
inputTypeShapes: NexusGenInputs & NexusGenEnums & NexusGenScalars;
argTypes: NexusGenArgTypes;
fieldTypes: NexusGenFieldTypes;
fieldTypeNames: NexusGenFieldTypeNames;
allTypes: NexusGenAllTypes;
typeInterfaces: NexusGenTypeInterfaces;
objectNames: NexusGenObjectNames;
inputNames: NexusGenInputNames;
enumNames: NexusGenEnumNames;
interfaceNames: NexusGenInterfaceNames;
scalarNames: NexusGenScalarNames;
unionNames: NexusGenUnionNames;
allInputTypes: NexusGenTypes['inputNames'] | NexusGenTypes['enumNames'] | NexusGenTypes['scalarNames'];
allOutputTypes: NexusGenTypes['objectNames'] | NexusGenTypes['enumNames'] | NexusGenTypes['unionNames'] | NexusGenTypes['interfaceNames'] | NexusGenTypes['scalarNames'];
allNamedTypes: NexusGenTypes['allInputTypes'] | NexusGenTypes['allOutputTypes']
abstractTypes: NexusGenTypes['interfaceNames'] | NexusGenTypes['unionNames'];
abstractTypeMembers: NexusGenAbstractTypeMembers;
objectsUsingAbstractStrategyIsTypeOf: NexusGenObjectsUsingAbstractStrategyIsTypeOf;
abstractsUsingStrategyResolveType: NexusGenAbstractsUsingStrategyResolveType;
features: NexusGenFeaturesConfig;
}",
}
`;
exports[`typegenPrinter: no input changes should print the full output, with inputs 1`] = `
"/**
* This file was generated by Nexus Schema
* Do not make changes to this file directly
*/
import type { core } from \\"nexus\\"
export interface NexusGenInputs {
CreatePostInput: { // input type
name: string; // String!
author: string; // ID!
geo: Array<Array<number | null>>; // [[Float]!]!
}
PostFilters: { // input type
order: NexusGenEnums['OrderEnum']; // OrderEnum!
search: string | null; // String
}
}
export interface NexusGenEnums {
OrderEnum: \\"ASC\\" | \\"DESC\\"
SomeEnum: \\"A\\" | \\"B\\"
}
export interface NexusGenScalars {
String: string
Int: number
Float: number
Boolean: boolean
ID: string
UUID: any
}
export interface NexusGenObjects {
Mutation: {};
Post: { // root type
id: string; // ID!
uuid: NexusGenScalars['UUID']; // UUID!
author: NexusGenRootTypes['User']; // User!
geo: ReadonlyArray<ReadonlyArray<number>>; // [[Float!]!]!
messyGeo?: ReadonlyArray<ReadonlyArray<number> | null> | null; // [[Float!]]
}
Query: {};
User: { // root type
id: string; // ID!
name: string; // String!
email: string; // String!
phone?: string | null; // String
posts: ReadonlyArray<NexusGenRootTypes['Post']>; // [Post!]!
outEnum?: NexusGenEnums['SomeEnum'] | null; // SomeEnum
}
}
export interface NexusGenInterfaces {
Node: core.Discriminate<'User', 'optional'> | core.Discriminate<'Post', 'optional'>;
}
export interface NexusGenUnions {
ExampleUnion: core.Discriminate<'Post', 'optional'> | core.Discriminate<'User', 'optional'>;
}
export type NexusGenRootTypes = NexusGenInterfaces & NexusGenObjects & NexusGenUnions
export type NexusGenAllTypes = NexusGenRootTypes & NexusGenScalars & NexusGenEnums
export interface NexusGenFieldTypes {
Mutation: { // field return type
someList: ReadonlyArray<string | null>; // [String]!
createPost: NexusGenRootTypes['Post']; // Post!
registerClick: NexusGenRootTypes['Query']; // Query!
}
Post: { // field return type
id: string; // ID!
uuid: NexusGenScalars['UUID']; // UUID!
author: NexusGenRootTypes['User']; // User!
geo: ReadonlyArray<ReadonlyArray<number>>; // [[Float!]!]!
messyGeo: ReadonlyArray<ReadonlyArray<number> | null> | null; // [[Float!]]
}
Query: { // field return type
user: NexusGenRootTypes['User']; // User!
posts: ReadonlyArray<NexusGenRootTypes['Post']>; // [Post!]!
unionField: NexusGenRootTypes['ExampleUnion']; // ExampleUnion!
}
User: { // field return type
id: string; // ID!
name: string; // String!
email: string; // String!
phone: string | null; // String
posts: ReadonlyArray<NexusGenRootTypes['Post']>; // [Post!]!
outEnum: NexusGenEnums['SomeEnum'] | null; // SomeEnum
}
Node: { // field return type
id: string; // ID!
}
}
export interface NexusGenFieldTypeNames {
Mutation: { // field return type name
someList: 'String'
createPost: 'Post'
registerClick: 'Query'
}
Post: { // field return type name
id: 'ID'
uuid: 'UUID'
author: 'User'
geo: 'Float'
messyGeo: 'Float'
}
Query: { // field return type name
user: 'User'
posts: 'Post'
unionField: 'ExampleUnion'
}
User: { // field return type name
id: 'ID'
name: 'String'
email: 'String'
phone: 'String'
posts: 'Post'
outEnum: 'SomeEnum'
}
Node: { // field return type name
id: 'ID'
}
}
export interface NexusGenArgTypes {
Mutation: {
someList: { // args
items: Array<string | null>; // [String]!
}
createPost: { // args
input: NexusGenInputs['CreatePostInput']; // CreatePostInput!
}
registerClick: { // args
uuid?: NexusGenScalars['UUID'] | null; // UUID
}
}
Query: {
posts: { // args
filters: NexusGenInputs['PostFilters']; // PostFilters!
}
}
User: {
name: { // args
prefix?: string | null; // String
}
posts: { // args
filters?: NexusGenInputs['PostFilters'] | null; // PostFilters
}
}
}
export interface NexusGenAbstractTypeMembers {
ExampleUnion: \\"Post\\" | \\"User\\"
Node: \\"User\\" | \\"Post\\"
}
export interface NexusGenTypeInterfaces {
Post: \\"Node\\"
User: \\"Node\\"
}
export type NexusGenObjectNames = keyof NexusGenObjects;
export type NexusGenInputNames = keyof NexusGenInputs;
export type NexusGenEnumNames = keyof NexusGenEnums;
export type NexusGenInterfaceNames = keyof NexusGenInterfaces;
export type NexusGenScalarNames = keyof NexusGenScalars;
export type NexusGenUnionNames = keyof NexusGenUnions;
export type NexusGenDirectives = \\"TestFieldDirective\\"
export interface NexusGenDirectiveArgs {
TestFieldDirective: {
}
}
export type NexusGenObjectsUsingAbstractStrategyIsTypeOf = never;
export type NexusGenAbstractsUsingStrategyResolveType = \\"ExampleUnion\\" | \\"Node\\";
export type NexusGenFeaturesConfig = {
abstractTypeStrategies: {
__typename: true
isTypeOf: false
resolveType: false
}
}
export interface NexusGenTypes {
context: any;
inputTypes: NexusGenInputs;
directives: NexusGenDirectives;
directiveArgs: NexusGenDirectiveArgs;
rootTypes: NexusGenRootTypes;
inputTypeShapes: NexusGenInputs & NexusGenEnums & NexusGenScalars;
argTypes: NexusGenArgTypes;
fieldTypes: NexusGenFieldTypes;
fieldTypeNames: NexusGenFieldTypeNames;
allTypes: NexusGenAllTypes;
typeInterfaces: NexusGenTypeInterfaces;
objectNames: NexusGenObjectNames;
inputNames: NexusGenInputNames;
enumNames: NexusGenEnumNames;
interfaceNames: NexusGenInterfaceNames;
scalarNames: NexusGenScalarNames;
unionNames: NexusGenUnionNames;
allInputTypes: NexusGenTypes['inputNames'] | NexusGenTypes['enumNames'] | NexusGenTypes['scalarNames'];
allOutputTypes: NexusGenTypes['objectNames'] | NexusGenTypes['enumNames'] | NexusGenTypes['unionNames'] | NexusGenTypes['interfaceNames'] | NexusGenTypes['scalarNames'];
allNamedTypes: NexusGenTypes['allInputTypes'] | NexusGenTypes['allOutputTypes']
abstractTypes: NexusGenTypes['interfaceNames'] | NexusGenTypes['unionNames'];
abstractTypeMembers: NexusGenAbstractTypeMembers;
objectsUsingAbstractStrategyIsTypeOf: NexusGenObjectsUsingAbstractStrategyIsTypeOf;
abstractsUsingStrategyResolveType: NexusGenAbstractsUsingStrategyResolveType;
features: NexusGenFeaturesConfig;
}"
`;
exports[`typegenPrinter: no input changes should print the full output, with inputs 2`] = `
"/**
* This file was generated by Nexus Schema
* Do not make changes to this file directly
*/
import type { NexusGenTypes } from './types.gen'
declare global {
interface NexusGen extends NexusGenTypes {}
}
declare global {
interface NexusGenPluginTypeConfig<TypeName extends string> {
}
interface NexusGenPluginInputTypeConfig<TypeName extends string> {
}
interface NexusGenPluginFieldConfig<TypeName extends string, FieldName extends string> {
}
interface NexusGenPluginInputFieldConfig<TypeName extends string, FieldName extends string> {
}
interface NexusGenPluginSchemaConfig {
}
interface NexusGenPluginArgConfig {
}
}"
`;
exports[`typegenPrinter: useReadonlyArrayForInputs should print the full output using ReadonlyArray in input types 1`] = `
Object {
"globalTypes": "/**
* This file was generated by Nexus Schema
* Do not make changes to this file directly
*/
import type { NexusGenTypes } from './types-useReadonlyArrayForInputs.gen'
declare global {
interface NexusGen extends NexusGenTypes {}
}
declare global {
interface NexusGenPluginTypeConfig<TypeName extends string> {
}
interface NexusGenPluginInputTypeConfig<TypeName extends string> {
}
interface NexusGenPluginFieldConfig<TypeName extends string, FieldName extends string> {
}
interface NexusGenPluginInputFieldConfig<TypeName extends string, FieldName extends string> {
}
interface NexusGenPluginSchemaConfig {
}
interface NexusGenPluginArgConfig {
}
}",
"tsTypes": "/**
* This file was generated by Nexus Schema
* Do not make changes to this file directly
*/
import type { TestContext } from \\"./../__helpers/index\\"
import type { core } from \\"nexus\\"
export interface NexusGenInputs {
CreatePostInput: { // input type
author: string; // ID!
geo: ReadonlyArray<ReadonlyArray<number | null>>; // [[Float]!]!
name: string; // String!
}
PostFilters: { // input type
order: NexusGenEnums['OrderEnum']; // OrderEnum!
search: string | null; // String
}
}
export interface NexusGenEnums {
OrderEnum: \\"ASC\\" | \\"DESC\\"
SomeEnum: \\"A\\" | \\"B\\"
}
export interface NexusGenScalars {
String: string
Int: number
Float: number
Boolean: boolean
ID: string
UUID: string
}
export interface NexusGenObjects {
Mutation: {};
Post: { // root type
author: NexusGenRootTypes['User']; // User!
geo: ReadonlyArray<ReadonlyArray<number>>; // [[Float!]!]!
id: string; // ID!
messyGeo?: ReadonlyArray<ReadonlyArray<number> | null> | null; // [[Float!]]
uuid: NexusGenScalars['UUID']; // UUID!
}
Query: {};
User: { // root type
email: string; // String!
id: string; // ID!
name: string; // String!
outEnum?: NexusGenEnums['SomeEnum'] | null; // SomeEnum
phone?: string | null; // String
posts: ReadonlyArray<NexusGenRootTypes['Post']>; // [Post!]!
}
}
export interface NexusGenInterfaces {
Node: core.Discriminate<'Post', 'optional'> | core.Discriminate<'User', 'optional'>;
}
export interface NexusGenUnions {
ExampleUnion: core.Discriminate<'Post', 'optional'> | core.Discriminate<'User', 'optional'>;
}
export type NexusGenRootTypes = NexusGenInterfaces & NexusGenObjects & NexusGenUnions
export type NexusGenAllTypes = NexusGenRootTypes & NexusGenScalars & NexusGenEnums
export interface NexusGenFieldTypes {
Mutation: { // field return type
createPost: NexusGenRootTypes['Post']; // Post!
registerClick: NexusGenRootTypes['Query']; // Query!
someList: ReadonlyArray<string | null>; // [String]!
}
Post: { // field return type
author: NexusGenRootTypes['User']; // User!
geo: ReadonlyArray<ReadonlyArray<number>>; // [[Float!]!]!
id: string; // ID!
messyGeo: ReadonlyArray<ReadonlyArray<number> | null> | null; // [[Float!]]
uuid: NexusGenScalars['UUID']; // UUID!
}
Query: { // field return type
posts: ReadonlyArray<NexusGenRootTypes['Post']>; // [Post!]!
unionField: NexusGenRootTypes['ExampleUnion']; // ExampleUnion!
user: NexusGenRootTypes['User']; // User!
}
User: { // field return type
email: string; // String!
id: string; // ID!
name: string; // String!
outEnum: NexusGenEnums['SomeEnum'] | null; // SomeEnum
phone: string | null; // String
posts: ReadonlyArray<NexusGenRootTypes['Post']>; // [Post!]!
}
Node: { // field return type
id: string; // ID!
}
}
export interface NexusGenFieldTypeNames {
Mutation: { // field return type name
createPost: 'Post'
registerClick: 'Query'
someList: 'String'
}
Post: { // field return type name
author: 'User'
geo: 'Float'
id: 'ID'
messyGeo: 'Float'
uuid: 'UUID'
}
Query: { // field return type name
posts: 'Post'
unionField: 'ExampleUnion'
user: 'User'
}
User: { // field return type name
email: 'String'
id: 'ID'
name: 'String'
outEnum: 'SomeEnum'
phone: 'String'
posts: 'Post'
}
Node: { // field return type name
id: 'ID'
}
}
export interface NexusGenArgTypes {
Mutation: {
createPost: { // args
input: NexusGenInputs['CreatePostInput']; // CreatePostInput!
}
registerClick: { // args
uuid?: NexusGenScalars['UUID'] | null; // UUID
}
someList: { // args
items: ReadonlyArray<string | null>; // [String]!
}
}
Query: {
posts: { // args
filters: NexusGenInputs['PostFilters']; // PostFilters!
}
}
User: {
name: { // args
prefix?: string | null; // String
}
posts: { // args
filters?: NexusGenInputs['PostFilters'] | null; // PostFilters
}
}
}
export interface NexusGenAbstractTypeMembers {
ExampleUnion: \\"Post\\" | \\"User\\"
Node: \\"Post\\" | \\"User\\"
}
export interface NexusGenTypeInterfaces {
Post: \\"Node\\"
User: \\"Node\\"
}
export type NexusGenObjectNames = keyof NexusGenObjects;
export type NexusGenInputNames = keyof NexusGenInputs;
export type NexusGenEnumNames = keyof NexusGenEnums;
export type NexusGenInterfaceNames = keyof NexusGenInterfaces;
export type NexusGenScalarNames = keyof NexusGenScalars;
export type NexusGenUnionNames = keyof NexusGenUnions;
export type NexusGenDirectives = \\"TestFieldDirective\\"
export interface NexusGenDirectiveArgs {
TestFieldDirective: {
}
}
export type NexusGenObjectsUsingAbstractStrategyIsTypeOf = never;
export type NexusGenAbstractsUsingStrategyResolveType = \\"ExampleUnion\\" | \\"Node\\";
export type NexusGenFeaturesConfig = {
abstractTypeStrategies: {
__typename: true
isTypeOf: false
resolveType: false
}
}
export interface NexusGenTypes {
context: TestContext;
inputTypes: NexusGenInputs;
directives: NexusGenDirectives;
directiveArgs: NexusGenDirectiveArgs;
rootTypes: NexusGenRootTypes;
inputTypeShapes: NexusGenInputs & NexusGenEnums & NexusGenScalars;
argTypes: NexusGenArgTypes;
fieldTypes: NexusGenFieldTypes;
fieldTypeNames: NexusGenFieldTypeNames;
allTypes: NexusGenAllTypes;
typeInterfaces: NexusGenTypeInterfaces;
objectNames: NexusGenObjectNames;
inputNames: NexusGenInputNames;
enumNames: NexusGenEnumNames;
interfaceNames: NexusGenInterfaceNames;
scalarNames: NexusGenScalarNames;
unionNames: NexusGenUnionNames;
allInputTypes: NexusGenTypes['inputNames'] | NexusGenTypes['enumNames'] | NexusGenTypes['scalarNames'];
allOutputTypes: NexusGenTypes['objectNames'] | NexusGenTypes['enumNames'] | NexusGenTypes['unionNames'] | NexusGenTypes['interfaceNames'] | NexusGenTypes['scalarNames'];
allNamedTypes: NexusGenTypes['allInputTypes'] | NexusGenTypes['allOutputTypes']
abstractTypes: NexusGenTypes['interfaceNames'] | NexusGenTypes['unionNames'];
abstractTypeMembers: NexusGenAbstractTypeMembers;
objectsUsingAbstractStrategyIsTypeOf: NexusGenObjectsUsingAbstractStrategyIsTypeOf;
abstractsUsingStrategyResolveType: NexusGenAbstractsUsingStrategyResolveType;
features: NexusGenFeaturesConfig;
}",
}
`;

View File

@ -1,8 +1,10 @@
export const EXAMPLE_SDL = `
directive @TestFieldDirective on FIELD_DEFINITION
scalar UUID
type Query {
user: User!
user: User! @TestFieldDirective
posts(filters: PostFilters!): [Post!]!
unionField: ExampleUnion!
}

View File

@ -27,8 +27,10 @@ export function typeCheck(
const project = new tsm.Project({
tsConfigFilePath,
compilerOptions,
addFilesFromTsConfig: true,
compilerOptions: {
...compilerOptions,
useUnknownInCatchVariables: false,
},
})
if (fileNames.length) {

View File

@ -44,17 +44,17 @@ beforeAll(() => {
it('can be implemented by object types', async () => {
expect(
await graphql(
await graphql({
schema,
`
source: `
{
user(int: 1, bool: true, float: 123.45, str: "Test") {
id
name
}
}
`
)
`,
})
).toMatchSnapshot()
})

View File

@ -1,5 +1,6 @@
import * as path from 'path'
import { core, enumType, makeSchema, objectType, queryType } from '../src'
import type { NexusGraphQLSchema } from '../src/core'
import { A, B } from './_types'
const { TypegenPrinter, TypegenMetadata } = core
@ -31,7 +32,10 @@ function getSchemaWithConstEnums() {
types: [
enumType({
name: 'B',
members: [B.NINE, B.TEN],
members: {
NINE: B.NINE,
TEN: B.TEN,
},
}),
queryType({
definition(t) {
@ -49,7 +53,9 @@ describe('sourceTypes', () => {
beforeEach(async () => {
metadata = new TypegenMetadata({
outputs: {
typegen: path.join(__dirname, 'test-gen.ts'),
typegen: {
outputPath: path.join(__dirname, 'test-gen.ts'),
},
schema: path.join(__dirname, 'test-gen.graphql'),
},
sourceTypes: {
@ -70,22 +76,24 @@ describe('sourceTypes', () => {
it('can match source types to regular enums', async () => {
const schema = getSchemaWithNormalEnums()
const typegenInfo = await metadata.getTypegenInfo(schema)
const typegen = new TypegenPrinter(schema, {
const typegen = new TypegenPrinter(schema as NexusGraphQLSchema, {
...typegenInfo,
typegenPath: '',
})
// @ts-expect-error
expect(typegen.printEnumTypeMap()).toMatchSnapshot()
})
it('can match source types for const enums', async () => {
const schema = getSchemaWithConstEnums()
const typegenInfo = await metadata.getTypegenInfo(schema)
const typegen = new TypegenPrinter(schema, {
const typegen = new TypegenPrinter(schema as NexusGraphQLSchema, {
...typegenInfo,
typegenPath: '',
})
// @ts-expect-error
expect(typegen.printEnumTypeMap()).toMatchSnapshot()
})
})
@ -109,7 +117,7 @@ describe('sourceTypings', () => {
outputs: false,
})
const typegenInfo = await metadata.getTypegenInfo(schema)
const typegen = new TypegenPrinter(schema, {
const typegen = new TypegenPrinter(schema as NexusGraphQLSchema, {
...typegenInfo,
typegenPath: '',
})
@ -137,7 +145,7 @@ describe('sourceTypings', () => {
})
const typegenInfo = await metadata.getTypegenInfo(schema)
const typegen = new TypegenPrinter(schema, {
const typegen = new TypegenPrinter(schema as NexusGraphQLSchema, {
...typegenInfo,
typegenPath: '',
})
@ -168,7 +176,7 @@ describe('sourceTypings', () => {
})
const typegenInfo = await metadata.getTypegenInfo(schema)
const typegen = new TypegenPrinter(schema, {
const typegen = new TypegenPrinter(schema as NexusGraphQLSchema, {
...typegenInfo,
typegenPath: '',
})

Some files were not shown because too many files have changed in this diff Show More