Compare commits
No commits in common. "main" and "1.1.0-next.15" have entirely different histories.
main
...
1.1.0-next
|
|
@ -1,36 +1,36 @@
|
|||
name: pr
|
||||
|
||||
on:
|
||||
on:
|
||||
- pull_request
|
||||
|
||||
jobs:
|
||||
graphql-15:
|
||||
graphql-14:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14.x
|
||||
node-version: 12.x
|
||||
- name: Install Dependencies
|
||||
run: yarn --frozen-lockfile && yarn format:ci
|
||||
- name: Install GraphQL@15.x
|
||||
run: yarn add graphql@^15
|
||||
- name: Install GraphQL@14.x
|
||||
run: yarn add graphql@^14.5.8
|
||||
- name: Test
|
||||
run: yarn -s test:ci
|
||||
run: yarn -s test:ci --testPathIgnorePatterns v15
|
||||
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x, 16.x]
|
||||
node-version: [10.x, 12.x]
|
||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install Dependencies
|
||||
run: yarn --frozen-lockfile || yarn --frozen-lockfile
|
||||
run: yarn --frozen-lockfile
|
||||
- name: Check Prettier
|
||||
if: matrix.os != 'windows-latest'
|
||||
run: yarn format:ci
|
||||
|
|
@ -38,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 == '14.x'
|
||||
if: matrix.os == 'ubuntu-latest' && matrix.node-version == '10.x'
|
||||
with:
|
||||
directory: ./coverage
|
||||
|
||||
|
|
@ -56,18 +56,16 @@ jobs:
|
|||
# rm examples/star-wars/star-wars-schema.graphql
|
||||
# node examples/star-wars/dist/schema.js
|
||||
# git diff --exit-code
|
||||
node-version: [14.x]
|
||||
node-version: [10.x]
|
||||
os: [macos-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install Dependencies
|
||||
run: yarn --frozen-lockfile || yarn --frozen-lockfile
|
||||
- name: Check Formatting
|
||||
run: yarn format:ci
|
||||
run: yarn --frozen-lockfile && yarn format:ci
|
||||
- name: Link
|
||||
run: yarn link
|
||||
- name: Example Install
|
||||
|
|
@ -83,8 +81,8 @@ jobs:
|
|||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v1
|
||||
- name: Install Dependencies
|
||||
run: yarn --frozen-lockfile || yarn --frozen-lockfile
|
||||
run: yarn --frozen-lockfile
|
||||
- name: Prettier
|
||||
run: yarn format:ci
|
||||
|
|
|
|||
|
|
@ -5,40 +5,40 @@ on:
|
|||
branches: [main]
|
||||
|
||||
jobs:
|
||||
graphql-15:
|
||||
graphql-14:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14.x
|
||||
node-version: 12.x
|
||||
- name: Install Dependencies
|
||||
run: yarn --frozen-lockfile && yarn format:ci
|
||||
- name: Install GraphQL@15.x
|
||||
run: yarn add graphql@^15
|
||||
run: yarn --frozen-lockfile
|
||||
- name: Install GraphQL@14.x
|
||||
run: yarn add graphql@^14.5.8
|
||||
- name: Test
|
||||
run: yarn -s test:ci
|
||||
run: yarn -s test:ci --testPathIgnorePatterns v15
|
||||
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x, 16.x]
|
||||
node-version: [10.x, 12.x]
|
||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install Dependencies
|
||||
run: yarn --frozen-lockfile || yarn --frozen-lockfile
|
||||
run: yarn --frozen-lockfile
|
||||
- name: Check Prettier
|
||||
if: matrix.os != 'windows-latest'
|
||||
run: yarn format:ci
|
||||
- name: Test
|
||||
run: yarn -s test:ci
|
||||
- name: Upload coverage to Codecov
|
||||
if: matrix.os == 'ubuntu-latest' && matrix.node-version == '14.x'
|
||||
if: matrix.os == 'ubuntu-latest' && matrix.node-version == '10.x'
|
||||
uses: codecov/codecov-action@v1
|
||||
with:
|
||||
directory: ./coverage
|
||||
|
|
@ -57,18 +57,16 @@ jobs:
|
|||
# rm examples/star-wars/star-wars-schema.graphql
|
||||
# node examples/star-wars/dist/schema.js
|
||||
# git diff --exit-code
|
||||
node-version: [14.x]
|
||||
node-version: [10.x]
|
||||
os: [macos-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install Dependencies
|
||||
run: yarn --frozen-lockfile || yarn --frozen-lockfile
|
||||
- name: Check Formatting
|
||||
run: yarn format:ci
|
||||
run: yarn --frozen-lockfile && yarn format:ci
|
||||
- name: Link
|
||||
run: yarn link
|
||||
- name: Example Install
|
||||
|
|
@ -85,9 +83,9 @@ jobs:
|
|||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v1
|
||||
- name: Install Dependencies
|
||||
run: yarn --frozen-lockfile || yarn --frozen-lockfile
|
||||
run: yarn --frozen-lockfile
|
||||
- name: Release Canary
|
||||
env:
|
||||
NPM_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||
|
|
|
|||
|
|
@ -5,4 +5,3 @@ examples/*/dist
|
|||
website/static/playground-dist
|
||||
yarn-error.log
|
||||
coverage/*
|
||||
tests/esm/out/
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
(c) 2018-2022 Tim Griesser
|
||||
(c) 2018-2019 Tim Griesser
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Nexus
|
||||
|
||||
[](https://github.com/graphql-nexus/nexus/actions/workflows/trunk.yml)
|
||||
[](https://badge.fury.io/js/nexus)
|
||||

|
||||
[](https://badge.fury.io/js/%40nexus%2Fschema)
|
||||
|
||||
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://nexusjs.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://nexus.js.org/converter).
|
||||
|
|
|
|||
|
|
@ -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 install nexus graphql apollo-server
|
||||
npm add 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 install 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 install --save-dev typescript ts-node-dev
|
||||
npm add --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'
|
||||
import { server } from './server.ts'
|
||||
|
||||
server.listen().then(({ url }) => {
|
||||
console.log(`🚀 Server ready at ${url}`)
|
||||
|
|
|
|||
|
|
@ -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 install --save-dev jest @types/jest ts-jest graphql-request get-port@5.1.1
|
||||
npm add --save-dev jest @types/jest ts-jest graphql-request get-port
|
||||
```
|
||||
|
||||
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 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 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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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 install @prisma/client
|
||||
npm install --save-dev prisma
|
||||
npm add @prisma/client
|
||||
npm add --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 draftToPublish = ctx.db.posts.find((p) => p.id === args.draftId)
|
||||
- let postToPublish = ctx.db.posts.find((p) => p.id === args.draftId)
|
||||
|
||||
- if (!draftToPublish) {
|
||||
- if (!postToPublish) {
|
||||
- throw new Error('Could not find draft with id ' + args.draftId)
|
||||
- }
|
||||
|
||||
- draftToPublish.published = true
|
||||
- postToPublish.published = true
|
||||
|
||||
- return draftToPublish
|
||||
- return postToPublish
|
||||
|
||||
+ return ctx.db.post.update({
|
||||
+ where: { id: args.draftId },
|
||||
|
|
|
|||
|
|
@ -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 install --save-dev sqlite3 @types/sqlite3
|
||||
npm add --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 database
|
||||
2. Pushes the Prisma Schema to the adatabase
|
||||
3. Generates a new Prisma Client
|
||||
4. Add an instance of a Prisma Client connected to the schema specifically for the test
|
||||
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ const Post = objectType({
|
|||
const Query = queryType({
|
||||
definition(t) {
|
||||
t.list.field('posts', {
|
||||
type: "Post",
|
||||
resolve: () => [
|
||||
{
|
||||
id: '1',
|
||||
|
|
@ -94,7 +93,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 languages.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
|
|
@ -134,7 +133,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 language:
|
||||
When defining an enum using the schema-first approach, the enum must first be defined in the schema definition languange:
|
||||
|
||||
```graphql
|
||||
enum UserRole {
|
||||
|
|
|
|||
|
|
@ -28,3 +28,18 @@ 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)
|
||||
},
|
||||
})
|
||||
```
|
||||
|
|
|
|||
|
|
@ -65,14 +65,3 @@ 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
|
||||
})
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ codeStyle: true
|
|||
|
||||
## interfaceType
|
||||
|
||||
[GraphQL Docs for Interface Types](https://graphql.org/learn/schema/#interfaces)
|
||||
[GraphQL Docs for Interface Types](https://graphql.org/learn/schema/#input-types)
|
||||
|
||||
In Nexus, you do not need to redefine the interface fields on the
|
||||
implementing object types, instead you may use `.implements(interfaceName)`
|
||||
|
|
|
|||
|
|
@ -10,31 +10,11 @@ codeStyle: true
|
|||
Defines a complex object which can be passed as an input value.
|
||||
|
||||
```ts
|
||||
import { extendType, inputObjectType } from 'nexus'
|
||||
|
||||
export const CommentInputType = inputObjectType({
|
||||
name: 'CommentInputType',
|
||||
export const InputType = inputObjectType({
|
||||
name: 'InputType',
|
||||
definition(t) {
|
||||
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,
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
t.nonNull.string('key')
|
||||
t.int('answer')
|
||||
},
|
||||
})
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -133,26 +133,9 @@ You should make a decision on this and supply the option yourself, it may be cha
|
|||
|
||||
Read more on this in the [getting-started](../../../getting-started) guide.
|
||||
|
||||
### typegenConfig
|
||||
### typegenConfig, formatTypegen
|
||||
|
||||
Escape hatch for more advanced cases which need further control over generated files. You typically won't need this.
|
||||
|
||||
### formatTypegen
|
||||
|
||||
Manually apply a formatter to the generated content before saving. Function exposes content and type of generated file.
|
||||
|
||||
```ts
|
||||
makeSchema({
|
||||
// ...
|
||||
formatTypegen: (content, type) => {
|
||||
if (type === 'types') {
|
||||
return `/* eslint-disable */
|
||||
\n ${content}`;
|
||||
}
|
||||
return content;
|
||||
},
|
||||
})
|
||||
```
|
||||
Escape hatches for more advanced cases which need further control over. You typically won't need these.
|
||||
|
||||
### customPrintSchemaFn
|
||||
|
||||
|
|
|
|||
|
|
@ -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://relay.dev/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://facebook.github.io/relay/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:
|
||||
|
|
|
|||
|
|
@ -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**: You may also use [`nexus-prisma`](https://github.com/graphql-nexus/nexus-prisma), a newer API for integrating Nexus and Prisma.
|
||||
> **Note**: The Prisma team is currently [rewriting](https://github.com/graphql-nexus/nexus-plugin-prisma/issues/1039) the plugin to make it maintainable longterm.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash-symbol
|
||||
npm install nexus-plugin-prisma @prisma/client
|
||||
npm install -D prisma
|
||||
npm add nexus-plugin-prisma @prisma/client
|
||||
npm add -D prisma
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
|
|
|||
|
|
@ -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: desc }]) {
|
||||
posts(orderBy: { title: dsc }) {
|
||||
title
|
||||
body
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 install -D typescript ts-node ts-node-dev
|
||||
npm add -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 install express apollo-server-express
|
||||
npm add express apollo-server-express
|
||||
```
|
||||
|
||||
2. If using TypeScript then Install typings for Express
|
||||
|
||||
```tsx
|
||||
npm install -D @types/express
|
||||
npm add -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 install floggy
|
||||
npm add 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 install graphql-scalars
|
||||
npm add 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.ts'),
|
||||
module: Path.join(__dirname, './path/to/contextModule'),
|
||||
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 install jest
|
||||
npm add jest
|
||||
```
|
||||
|
||||
2. If you are a TypeScript user then install and configure `ts-jest`
|
||||
|
||||
```bash
|
||||
npm install ts-jest
|
||||
npm add 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 install -D graphql-request
|
||||
npm add -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 install setset
|
||||
npm add setset
|
||||
```
|
||||
|
||||
```tsx
|
||||
|
|
|
|||
|
|
@ -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 install -D @prisma/cli
|
||||
npm install @prisma/client
|
||||
npm add -D @prisma/cli
|
||||
npm add @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 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.
|
||||
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.
|
||||
|
||||
```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
|
||||
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ Check out the [example projects](https://github.com/graphql-nexus/nexus/tree/mai
|
|||
## Installation
|
||||
|
||||
```sh
|
||||
npm install nexus
|
||||
npm install graphql # required as a peer dependency
|
||||
npm add nexus
|
||||
npm add 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.
|
||||
|
|
|
|||
|
|
@ -214,7 +214,8 @@ const Footer = ({ footerProps }: FooterViewProps) => {
|
|||
}
|
||||
</div>
|
||||
|
||||
<p className="social-text">Tim Griesser © 2018-2022</p>
|
||||
<p className="social-text">Prisma © 2018-2020</p>
|
||||
<p>Made with ❤️ in Berlin</p>
|
||||
</div>
|
||||
</SocialWrapper>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -34,6 +34,6 @@ npm run examples
|
|||
- [apollo-fullstack](apollo-fullstack)
|
||||
- [star-wars](star-wars)
|
||||
- [kitchen-sink](kitchen-sink)
|
||||
- [with-prisma](with-prisma)
|
||||
- [nexus-prisma](nexus-prisma)
|
||||
|
||||
> The `with-prisma` example is not included when all examples are ran at once. You can try it by following the instructions in its [README](with-prisma) instead.
|
||||
> The `nexus-prisma` example is not included when all examples are ran at once. You can try it by following the instructions in its [README](nexus-prisma) instead.
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
"apollo-server-testing": "^2.18.1",
|
||||
"dedent": "^0.7.0",
|
||||
"fullstack-tutorial": "apollographql/fullstack-tutorial.git",
|
||||
"graphql": "^16.3.0",
|
||||
"graphql": "^15.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": "^4.5.5"
|
||||
"typescript": "^3.9"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { idArg, list, nonNull, objectType, stringArg } from 'nexus'
|
||||
import { idArg, list, nonNull, nullable, objectType, stringArg } from 'nexus'
|
||||
|
||||
export const Mutation = objectType({
|
||||
name: 'Mutation',
|
||||
|
|
|
|||
|
|
@ -3169,11 +3169,6 @@ 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"
|
||||
|
|
@ -6804,10 +6799,10 @@ type-is@~1.6.17, type-is@~1.6.18:
|
|||
media-typer "0.3.0"
|
||||
mime-types "~2.1.24"
|
||||
|
||||
typescript@^4.5.5:
|
||||
version "4.5.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3"
|
||||
integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==
|
||||
typescript@^3.9:
|
||||
version "3.9.7"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
|
||||
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
|
||||
|
||||
uglify-js@^3.1.4:
|
||||
version "3.4.9"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
"dataloader": "tgriesser/dataloader.git#ts-types",
|
||||
"express": "^4.16.4",
|
||||
"ghost": "^3.35.3",
|
||||
"graphql": "^16.3.0",
|
||||
"graphql": "^15.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": "^4.5.5"
|
||||
"typescript": "^3.9"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -6,7 +6,7 @@
|
|||
"dependencies": {
|
||||
"apollo-server": "^2.18.1",
|
||||
"githunt-api": "peggyrayzis/GitHunt-API",
|
||||
"graphql": "^16.3.0",
|
||||
"graphql": "^14.5.8",
|
||||
"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": "^4.5.5"
|
||||
"typescript": "^3.9"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2962,16 +2962,18 @@ 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"
|
||||
|
|
@ -3514,7 +3516,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.1.0, iterall@^1.1.3, iterall@^1.2.1, iterall@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.2.2.tgz#92d70deb8028e0c39ff3164fdbf4d8b088130cd7"
|
||||
integrity sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==
|
||||
|
|
@ -5586,10 +5588,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@^4.5.5:
|
||||
version "4.5.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3"
|
||||
integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==
|
||||
typescript@^3.9:
|
||||
version "3.9.7"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
|
||||
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
|
||||
|
||||
uid-safe@~2.1.4:
|
||||
version "2.1.5"
|
||||
|
|
|
|||
|
|
@ -19,24 +19,24 @@ interface Baz {
|
|||
|
||||
type BooleanConnection {
|
||||
"""
|
||||
https://relay.dev/graphql/connections.htm#sec-Edge-Types
|
||||
https://facebook.github.io/relay/graphql/connections.htm#sec-Edge-Types
|
||||
"""
|
||||
edges: [BooleanEdge]
|
||||
|
||||
"""
|
||||
https://relay.dev/graphql/connections.htm#sec-undefined.PageInfo
|
||||
https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo
|
||||
"""
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type BooleanEdge {
|
||||
"""
|
||||
https://relay.dev/graphql/connections.htm#sec-Cursor
|
||||
https://facebook.github.io/relay/graphql/connections.htm#sec-Cursor
|
||||
"""
|
||||
cursor: String!
|
||||
|
||||
"""
|
||||
https://relay.dev/graphql/connections.htm#sec-Node
|
||||
https://facebook.github.io/relay/graphql/connections.htm#sec-Node
|
||||
"""
|
||||
node: Boolean
|
||||
}
|
||||
|
|
@ -49,24 +49,24 @@ scalar Date
|
|||
|
||||
type DateConnection {
|
||||
"""
|
||||
https://relay.dev/graphql/connections.htm#sec-Edge-Types
|
||||
https://facebook.github.io/relay/graphql/connections.htm#sec-Edge-Types
|
||||
"""
|
||||
edges: [DateEdge]
|
||||
|
||||
"""
|
||||
https://relay.dev/graphql/connections.htm#sec-undefined.PageInfo
|
||||
https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo
|
||||
"""
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type DateEdge {
|
||||
"""
|
||||
https://relay.dev/graphql/connections.htm#sec-Cursor
|
||||
https://facebook.github.io/relay/graphql/connections.htm#sec-Cursor
|
||||
"""
|
||||
cursor: String!
|
||||
|
||||
"""
|
||||
https://relay.dev/graphql/connections.htm#sec-Node
|
||||
https://facebook.github.io/relay/graphql/connections.htm#sec-Node
|
||||
"""
|
||||
node: Date
|
||||
}
|
||||
|
|
@ -104,7 +104,7 @@ interface Node {
|
|||
}
|
||||
|
||||
"""
|
||||
PageInfo cursor, as defined in https://relay.dev/graphql/connections.htm#sec-undefined.PageInfo
|
||||
PageInfo cursor, as defined in https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo
|
||||
"""
|
||||
type PageInfo {
|
||||
"""
|
||||
|
|
@ -306,24 +306,24 @@ type User {
|
|||
|
||||
type UserConnection {
|
||||
"""
|
||||
https://relay.dev/graphql/connections.htm#sec-Edge-Types
|
||||
https://facebook.github.io/relay/graphql/connections.htm#sec-Edge-Types
|
||||
"""
|
||||
edges: [UserEdge]
|
||||
|
||||
"""
|
||||
https://relay.dev/graphql/connections.htm#sec-undefined.PageInfo
|
||||
https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo
|
||||
"""
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type UserEdge {
|
||||
"""
|
||||
https://relay.dev/graphql/connections.htm#sec-Cursor
|
||||
https://facebook.github.io/relay/graphql/connections.htm#sec-Cursor
|
||||
"""
|
||||
cursor: String!
|
||||
|
||||
"""
|
||||
https://relay.dev/graphql/connections.htm#sec-Node
|
||||
https://facebook.github.io/relay/graphql/connections.htm#sec-Node
|
||||
"""
|
||||
node: User
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"apollo-server": "^2.18.1",
|
||||
"graphql": "^16.3.0",
|
||||
"graphql": "^15.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": "^4.5.5"
|
||||
"typescript": "^3.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/graphql-relay": "^0.4.11",
|
||||
|
|
|
|||
|
|
@ -21,11 +21,7 @@ const schema = makeSchema({
|
|||
types,
|
||||
outputs: {
|
||||
schema: path.join(__dirname, '../kitchen-sink-schema.graphql'),
|
||||
typegen: {
|
||||
outputPath: path.join(__dirname, './kitchen-sink.gen.ts'),
|
||||
globalsPath: path.join(__dirname, './kitchen-sink-globals.gen.ts'),
|
||||
declareInputs: true,
|
||||
},
|
||||
typegen: path.join(__dirname, './kitchen-sink.gen.ts'),
|
||||
},
|
||||
plugins: [
|
||||
NodePlugin,
|
||||
|
|
|
|||
|
|
@ -391,17 +391,9 @@ export const MoreQueryFields = extendType({
|
|||
|
||||
export const DateScalar = scalarType({
|
||||
name: 'Date',
|
||||
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')
|
||||
},
|
||||
serialize: (value) => value.getTime(),
|
||||
parseValue: (value) => new Date(value),
|
||||
parseLiteral: (ast) => (ast.kind === 'IntValue' ? new Date(ast.value) : null),
|
||||
asNexusMethod: 'date',
|
||||
sourceType: 'Date',
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,65 +0,0 @@
|
|||
/** 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 {}
|
||||
}
|
||||
|
|
@ -1,34 +1,61 @@
|
|||
/** This file was generated by Nexus Schema Do not make changes to this file directly */
|
||||
|
||||
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
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
declare global {
|
||||
interface NexusGen extends NexusGenTypes {}
|
||||
}
|
||||
|
||||
export interface NexusGenInputs {
|
||||
InputType: InputType
|
||||
InputType2: InputType2
|
||||
NestedType: NestedType
|
||||
SomeArg: SomeArg
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
export interface NexusGenEnums {}
|
||||
|
|
@ -363,117 +390,100 @@ 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: FooArgsTestArgs
|
||||
argsTest: {
|
||||
// args
|
||||
a: NexusGenInputs['InputType'] | null // InputType
|
||||
}
|
||||
}
|
||||
Mutation: {
|
||||
someMutationField: MutationSomeMutationFieldArgs
|
||||
someMutationField: {
|
||||
// args
|
||||
id: string // ID!
|
||||
}
|
||||
}
|
||||
Query: {
|
||||
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
|
||||
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
|
||||
}
|
||||
}
|
||||
TestObj: {
|
||||
argsTest: TestObjArgsTestArgs
|
||||
argsTest: {
|
||||
// args
|
||||
a: NexusGenInputs['InputType'] | null // InputType
|
||||
}
|
||||
}
|
||||
Bar: {
|
||||
argsTest: BarArgsTestArgs
|
||||
argsTest: {
|
||||
// args
|
||||
a: NexusGenInputs['InputType'] | null // InputType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -544,3 +554,99 @@ 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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2140,11 +2140,6 @@ 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"
|
||||
|
|
@ -5075,10 +5070,10 @@ type-is@~1.6.16:
|
|||
media-typer "0.3.0"
|
||||
mime-types "~2.1.18"
|
||||
|
||||
typescript@^4.5.5:
|
||||
version "4.5.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3"
|
||||
integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==
|
||||
typescript@^3.9:
|
||||
version "3.9.7"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
|
||||
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
|
||||
|
||||
uglify-js@^3.1.4:
|
||||
version "3.4.9"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"apollo-server": "^2.18.1",
|
||||
"graphql": "^16.3.0",
|
||||
"graphql": "^15.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": "^4.5.5"
|
||||
"typescript": "^3.9"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2097,11 +2097,6 @@ 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"
|
||||
|
|
@ -5011,10 +5006,10 @@ type-is@~1.6.16:
|
|||
media-typer "0.3.0"
|
||||
mime-types "~2.1.18"
|
||||
|
||||
typescript@^4.5.5:
|
||||
version "4.5.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3"
|
||||
integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==
|
||||
typescript@^3.9:
|
||||
version "3.9.7"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
|
||||
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
|
||||
|
||||
uglify-js@^3.1.4:
|
||||
version "3.4.9"
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
"dependencies": {
|
||||
"apollo-server": "^2.18.1",
|
||||
"fs-extra": "^7.0.1",
|
||||
"graphql": "^16.3.0",
|
||||
"graphql": "^15.3.0",
|
||||
"graphql-tools": "^4.0.7",
|
||||
"nexus": "^1.0.0",
|
||||
"ts-node-dev": "1.0.0-pre.31",
|
||||
"typescript": "^4.5.5"
|
||||
"typescript": "^3.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/fs-extra": "^5.0.4"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { objectType, arg, list, nullable, core } from 'nexus'
|
||||
import ts from 'typescript'
|
||||
import { objectType, arg, list, nullable } from 'nexus'
|
||||
import { nodeType, functionLikeDeclaration, hasTypeParameters } from './mixins'
|
||||
import { filteredNodesList } from './utils'
|
||||
|
||||
|
|
@ -22,7 +21,7 @@ export const SourceFile = objectType({
|
|||
t.list.field('statements', {
|
||||
type: 'Node',
|
||||
args: nodeSkipSyntax,
|
||||
resolve: (root, args) => filteredNodesList<ts.Statement>(args, Array.from(root.statements)),
|
||||
resolve: (root, args) => filteredNodesList(args, Array.from(root.statements)),
|
||||
})
|
||||
},
|
||||
})
|
||||
|
|
@ -157,7 +156,7 @@ export const ClassDeclaration = objectType({
|
|||
t.list.field('members', {
|
||||
type: 'Node',
|
||||
args: nodeSkipSyntax,
|
||||
resolve: (root, args) => filteredNodesList<ts.ClassElement>(args, Array.from(root.members)),
|
||||
resolve: (root, args) => filteredNodesList(args, Array.from(root.members)),
|
||||
})
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { arg, interfaceType, list, nullable } from 'nexus'
|
||||
import ts, { JSDoc, SyntaxKind } from 'typescript'
|
||||
import { 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<ts.Modifier>(args, Array.from(root.modifiers))
|
||||
return syntaxKindFilter(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
|
||||
},
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ export const TupleTypeNode = objectType({
|
|||
name: 'TupleTypeNode',
|
||||
definition(t) {
|
||||
nodeType(t)
|
||||
t.list.field('elements', { type: 'Node' })
|
||||
t.list.field('elementTypes', { type: 'Node' })
|
||||
},
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,69 +1,72 @@
|
|||
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[]
|
||||
): T[] => {
|
||||
const { skip, only } = args
|
||||
) => {
|
||||
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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1113,11 +1113,6 @@ 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"
|
||||
|
|
@ -2169,10 +2164,10 @@ type-is@~1.6.16:
|
|||
media-typer "0.3.0"
|
||||
mime-types "~2.1.18"
|
||||
|
||||
typescript@^4.5.5:
|
||||
version "4.5.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3"
|
||||
integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==
|
||||
typescript@^3.9:
|
||||
version "3.9.7"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
|
||||
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
|
||||
|
||||
universalify@^0.1.0:
|
||||
version "0.1.2"
|
||||
|
|
|
|||
|
|
@ -20,13 +20,13 @@
|
|||
"@prisma/client": "2.14.0",
|
||||
"apollo-server-express": "^2.19.1",
|
||||
"express": "^4.17.1",
|
||||
"graphql": "^16.3.0",
|
||||
"graphql": "^15.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.5.5"
|
||||
"typescript": "^4.0.2"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1015,11 +1015,6 @@ 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"
|
||||
|
|
@ -1819,10 +1814,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.5.5:
|
||||
version "4.5.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3"
|
||||
integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==
|
||||
typescript@^4.0.2:
|
||||
version "4.1.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7"
|
||||
integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==
|
||||
|
||||
unpipe@1.0.0, unpipe@~1.0.0:
|
||||
version "1.0.0"
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@
|
|||
"trailingComma": "all"
|
||||
},
|
||||
"dependencies": {
|
||||
"graphql": "^16.3.0",
|
||||
"graphql": "^15.3.0",
|
||||
"nexus": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@now/node": "^1.0.1",
|
||||
"@types/node": "^12.11.1",
|
||||
"ts-node": "^8.4.1",
|
||||
"typescript": "^4.5.5"
|
||||
"typescript": "^3.9"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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@^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==
|
||||
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==
|
||||
|
||||
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@^4.5.5:
|
||||
version "4.5.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3"
|
||||
integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==
|
||||
typescript@^3.9:
|
||||
version "3.9.7"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
|
||||
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
|
||||
|
||||
yn@^3.0.0:
|
||||
version "3.1.1"
|
||||
|
|
|
|||
28
package.json
28
package.json
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "nexus",
|
||||
"version": "1.3.0",
|
||||
"version": "0.0.0-dripip",
|
||||
"description": "Scalable, strongly typed GraphQL schema development",
|
||||
"keywords": [
|
||||
"graphql",
|
||||
|
|
@ -46,6 +46,7 @@
|
|||
"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",
|
||||
|
|
@ -61,10 +62,12 @@
|
|||
},
|
||||
"lint-staged": {
|
||||
"*.{ts,js,graphql,json,css,md}": [
|
||||
"prettier --write"
|
||||
"prettier --write",
|
||||
"git add"
|
||||
],
|
||||
"*package.json": [
|
||||
"sort-package-json"
|
||||
"sort-package-json",
|
||||
"git add"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
@ -79,28 +82,29 @@
|
|||
"@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": "^16.3.0",
|
||||
"graphql-relay": "^0.10.0",
|
||||
"graphql-scalars": "^1.14.1",
|
||||
"graphql": "^15.3.0",
|
||||
"graphql-relay": "^0.6.0",
|
||||
"graphql-scalars": "^1.2.6",
|
||||
"gulp": "4.0.2",
|
||||
"husky": "^1.1.2",
|
||||
"jest": "^26.6.3",
|
||||
"jest-watch-typeahead": "^0.6.1",
|
||||
"lint-staged": "^12.4.1",
|
||||
"prettier": "^2.5.1",
|
||||
"lint-staged": "^7.3.0",
|
||||
"patch-package": "6.2.2",
|
||||
"prettier": "^2.2.1",
|
||||
"prettier-plugin-jsdoc": "^0.2.5",
|
||||
"sort-package-json": "^1.22.1",
|
||||
"ts-jest": "^26.4.4",
|
||||
"ts-morph": "^13.0.3",
|
||||
"ts-morph": "^8.2.0",
|
||||
"ts-node": "^9.0.0",
|
||||
"tsd": "^0.13.1",
|
||||
"tslint": "^5.11.0",
|
||||
"tslint-config-prettier": "^1.15.0",
|
||||
"typescript": "^4.5.5"
|
||||
"typescript": "^4.1.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"graphql": "15.x || 16.x"
|
||||
"graphql": "^14.5.8 || 15.x"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
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;
|
||||
}
|
||||
/**
|
||||
863
src/builder.ts
863
src/builder.ts
File diff suppressed because it is too large
Load Diff
|
|
@ -1,9 +1,7 @@
|
|||
// The "core" is used as a namespace to re-export everything,
|
||||
// For anyone who wants to use the internals
|
||||
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'
|
||||
|
|
@ -22,14 +20,12 @@ export * from './definitions/queryType'
|
|||
export * from './definitions/scalarType'
|
||||
export * from './definitions/subscriptionField'
|
||||
export * from './definitions/subscriptionType'
|
||||
export * from './definitions/nexusMeta'
|
||||
export * from './definitions/unionType'
|
||||
export * from './definitions/wrapping'
|
||||
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'
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import type {
|
|||
GraphQLSchema,
|
||||
GraphQLUnionType,
|
||||
} from 'graphql'
|
||||
import type { NexusDirectiveConfig } from '../core'
|
||||
import type {
|
||||
NexusFieldExtension,
|
||||
NexusInputObjectTypeExtension,
|
||||
|
|
@ -26,8 +25,7 @@ import type { RequiredDeeply } from '../typeHelpersInternal'
|
|||
|
||||
export type { AbstractTypes }
|
||||
|
||||
/** Conveniently represents flow's "Maybe" type https://flow.org/en/docs/types/maybe/ */
|
||||
export type Maybe<T> = null | undefined | T
|
||||
export type Maybe<T> = T | null
|
||||
|
||||
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
|
||||
|
||||
|
|
@ -54,8 +52,6 @@ export enum NexusTypes {
|
|||
PrintedGenTypingImport = 'PrintedGenTypingImport',
|
||||
Scalar = 'Scalar',
|
||||
Union = 'Union',
|
||||
Directive = 'Directive',
|
||||
DirectiveUse = 'DirectiveUse',
|
||||
}
|
||||
|
||||
export interface DeprecationInfo {
|
||||
|
|
@ -158,13 +154,8 @@ export type NexusGraphQLInterfaceTypeConfig = WithExt<
|
|||
NexusInterfaceTypeExtension
|
||||
> & { interfaces: () => GraphQLInterfaceType[] }
|
||||
|
||||
export type NexusGraphQLDirectiveConfig = WithExt<NexusDirectiveConfig, NexusInputObjectTypeExtension>
|
||||
|
||||
export interface NexusGraphQLSchema extends GraphQLSchema {
|
||||
extensions: {
|
||||
nexus: NexusSchemaExtension
|
||||
[attributeName: string]: unknown
|
||||
}
|
||||
export type NexusGraphQLSchema = Omit<GraphQLSchema, 'extensions'> & {
|
||||
extensions: { nexus: NexusSchemaExtension }
|
||||
}
|
||||
|
||||
export type NexusFeaturesInput = {
|
||||
|
|
@ -187,9 +178,12 @@ export type NexusFeaturesInput = {
|
|||
* 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,
|
||||
* @default
|
||||
* {
|
||||
* resolveType: true,
|
||||
* __typename: false
|
||||
* isTypeOf: false,}
|
||||
* isTypeOf: false,
|
||||
* }
|
||||
*/
|
||||
abstractTypeStrategies?: {
|
||||
/**
|
||||
|
|
@ -218,8 +212,8 @@ export type NexusFeaturesInput = {
|
|||
* 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
|
||||
* 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).
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import type { GraphQLScalarTypeConfig } from 'graphql'
|
||||
import type { AllInputTypes, GetGen2 } from '../typegenTypeHelpers'
|
||||
import type { Directives } from './directive'
|
||||
import type { AllNexusArgsDefs, AllNexusInputTypeDefs } from './wrapping'
|
||||
import { Maybe, NexusTypes, withNexusSymbol } from './_types'
|
||||
import { NexusTypes, withNexusSymbol } from './_types'
|
||||
|
||||
export type ArgsRecord = Record<string, AllNexusArgsDefs>
|
||||
|
||||
|
|
@ -40,7 +39,7 @@ export type CommonArgConfig = {
|
|||
* // ): [Int]
|
||||
* // }
|
||||
*/
|
||||
description?: Maybe<string>
|
||||
description?: string
|
||||
|
||||
/**
|
||||
* Data that will be added to the arg-level [extensions field on the graphql-js type def
|
||||
|
|
@ -48,20 +47,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 {
|
||||
/**
|
||||
* The default value for this argument when ***none*** is given by the client.
|
||||
*
|
||||
* Note that *null* is still considered something meaning if the client gives an explicit null that will
|
||||
* Note that _null_ is still considered something meaning if the client gives an explicit null that will
|
||||
* prevent the default from activating. This is why the type of an arg with a default value in the resolver
|
||||
* includes "undefined | null".
|
||||
*
|
||||
|
|
@ -94,10 +86,12 @@ 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.
|
||||
*
|
||||
|
|
@ -199,7 +193,8 @@ export function arg<T extends string>(config: NexusArgConfig<T>) {
|
|||
* },
|
||||
* })
|
||||
*
|
||||
* @param config Configuration for the argument like its description. See jsdoc on each config field for details.
|
||||
* @param config Configuration for the argument like its description. See jsdoc on each config field
|
||||
* for details.
|
||||
*/
|
||||
export function stringArg(config?: ScalarArgConfig<string>) {
|
||||
return arg({ type: 'String', ...config })
|
||||
|
|
@ -229,7 +224,8 @@ export function stringArg(config?: ScalarArgConfig<string>) {
|
|||
* },
|
||||
* })
|
||||
*
|
||||
* @param config Configuration for the argument like its description. See jsdoc on each config field for details.
|
||||
* @param config Configuration for the argument like its description. See jsdoc on each config field
|
||||
* for details.
|
||||
*/
|
||||
export function intArg(config?: ScalarArgConfig<number>) {
|
||||
return arg({ type: 'Int', ...config })
|
||||
|
|
@ -259,7 +255,8 @@ export function intArg(config?: ScalarArgConfig<number>) {
|
|||
* },
|
||||
* })
|
||||
*
|
||||
* @param config Configuration for the argument like its description. See jsdoc on each config field for details.
|
||||
* @param config Configuration for the argument like its description. See jsdoc on each config field
|
||||
* for details.
|
||||
*/
|
||||
export function floatArg(config?: ScalarArgConfig<number>) {
|
||||
return arg({ type: 'Float', ...config })
|
||||
|
|
@ -289,7 +286,8 @@ export function floatArg(config?: ScalarArgConfig<number>) {
|
|||
* },
|
||||
* })
|
||||
*
|
||||
* @param config Configuration for the argument like its description. See jsdoc on each config field for details.
|
||||
* @param config Configuration for the argument like its description. See jsdoc on each config field
|
||||
* for details.
|
||||
*/
|
||||
export function idArg(config?: ScalarArgConfig<string>) {
|
||||
return arg({ type: 'ID', ...config })
|
||||
|
|
@ -319,7 +317,8 @@ export function idArg(config?: ScalarArgConfig<string>) {
|
|||
* },
|
||||
* })
|
||||
*
|
||||
* @param config Configuration for the argument like its description. See jsdoc on each config field for details.
|
||||
* @param config Configuration for the argument like its description. See jsdoc on each config field
|
||||
* for details.
|
||||
*/
|
||||
export function booleanArg(config?: ScalarArgConfig<boolean>) {
|
||||
return arg({ type: 'Boolean', ...config })
|
||||
|
|
|
|||
|
|
@ -6,13 +6,17 @@ 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: {
|
||||
...Object(type.extensions?.nexus),
|
||||
...config,
|
||||
asNexusMethod: config.asNexusMethod,
|
||||
sourceType: config.sourceType,
|
||||
},
|
||||
}
|
||||
return type
|
||||
return type as any
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,19 +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, Maybe } from './_types'
|
||||
import type { BaseScalars } from './_types'
|
||||
|
||||
export interface CommonFieldConfig {
|
||||
//todo
|
||||
/** The description to annotate the GraphQL SDL */
|
||||
description?: Maybe<string>
|
||||
description?: string
|
||||
//todo
|
||||
/**
|
||||
* 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?: Maybe<string> // | DeprecationInfo;
|
||||
deprecation?: string // | DeprecationInfo;
|
||||
}
|
||||
|
||||
export type CommonOutputFieldConfig<TypeName extends string, FieldName extends string> = CommonFieldConfig & {
|
||||
|
|
@ -74,7 +74,7 @@ export type CommonOutputFieldConfig<TypeName extends string, FieldName extends s
|
|||
* },
|
||||
* })
|
||||
*/
|
||||
args?: Maybe<ArgsRecord>
|
||||
args?: 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
|
||||
|
|
@ -104,43 +104,8 @@ 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>
|
||||
|
|
@ -150,16 +115,7 @@ export type CommonInputFieldConfig<TypeName extends string, FieldName extends st
|
|||
* graphql-js based tools which rely on looking for special data here.
|
||||
*/
|
||||
extensions?: GraphQLInputFieldConfig['extensions']
|
||||
/**
|
||||
* 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>
|
||||
|
||||
} & NexusGenPluginFieldConfig<TypeName, FieldName>
|
||||
export interface OutputScalarConfig<TypeName extends string, FieldName extends string>
|
||||
extends CommonOutputFieldConfig<TypeName, FieldName> {
|
||||
/**
|
||||
|
|
@ -170,7 +126,11 @@ 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.
|
||||
|
|
@ -188,23 +148,23 @@ 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.
|
||||
* @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 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.
|
||||
* @param info The GraphQL resolve info.
|
||||
|
|
@ -215,8 +175,8 @@ export interface OutputScalarConfig<TypeName extends string, FieldName extends s
|
|||
resolve?: FieldResolver<TypeName, FieldName>
|
||||
}
|
||||
|
||||
// prettier-ignore
|
||||
export interface NexusOutputFieldConfig<TypeName extends string, FieldName extends string> extends OutputScalarConfig<TypeName, FieldName> {
|
||||
export interface NexusOutputFieldConfig<TypeName extends string, FieldName extends string>
|
||||
extends OutputScalarConfig<TypeName, FieldName> {
|
||||
/**
|
||||
* [GraphQL 2018 Spec](https://spec.graphql.org/June2018/#sec-Types)
|
||||
*
|
||||
|
|
@ -310,15 +270,7 @@ export interface NexusOutputFieldConfig<TypeName extends string, FieldName exten
|
|||
* },
|
||||
* })
|
||||
*/
|
||||
type: GetGen<'allOutputTypes', string> | AllNexusOutputTypeDefs | NexusMetaType
|
||||
}
|
||||
|
||||
// prettier-ignore
|
||||
export interface NexusOutputFieldConfigWithName<TypeName extends string, FieldName extends string> extends NexusOutputFieldConfig<TypeName, FieldName> {
|
||||
/**
|
||||
* The name of this field. Must conform to the regex pattern: [_A-Za-z][_0-9A-Za-z]*
|
||||
*/
|
||||
name: FieldName
|
||||
type: GetGen<'allOutputTypes', string> | AllNexusOutputTypeDefs
|
||||
}
|
||||
|
||||
export type NexusOutputFieldDef = NexusOutputFieldConfig<string, any> & {
|
||||
|
|
@ -346,21 +298,14 @@ export type ScalarOutConfig<TypeName extends string, FieldName extends string> =
|
|||
}
|
||||
: OutputScalarConfig<TypeName, FieldName>
|
||||
|
||||
// prettier-ignore
|
||||
export type FieldOutConfig<TypeName extends string, FieldName extends string> =
|
||||
NeedsResolver<TypeName, FieldName> extends true
|
||||
? NexusOutputFieldConfig<TypeName, FieldName> & {
|
||||
resolve: FieldResolver<TypeName, FieldName>
|
||||
}
|
||||
: NexusOutputFieldConfig<TypeName, FieldName>
|
||||
|
||||
// prettier-ignore
|
||||
export type FieldOutConfigWithName<TypeName extends string, FieldName extends string> =
|
||||
NeedsResolver<TypeName, FieldName> extends true
|
||||
? NexusOutputFieldConfigWithName<TypeName, FieldName> & {
|
||||
resolve: FieldResolver<TypeName, FieldName>
|
||||
}
|
||||
: NexusOutputFieldConfigWithName<TypeName, FieldName>
|
||||
export type FieldOutConfig<TypeName extends string, FieldName extends string> = NeedsResolver<
|
||||
TypeName,
|
||||
FieldName
|
||||
> extends true
|
||||
? NexusOutputFieldConfig<TypeName, FieldName> & {
|
||||
resolve: FieldResolver<TypeName, FieldName>
|
||||
}
|
||||
: NexusOutputFieldConfig<TypeName, FieldName>
|
||||
|
||||
export interface OutputDefinitionBuilder {
|
||||
typeName: string
|
||||
|
|
@ -468,7 +413,7 @@ export class OutputDefinitionBlock<TypeName extends string> {
|
|||
* Guide](https://nexusjs.org/docs/guides/nullability) | [GraphQL 2018
|
||||
* Spec](https://spec.graphql.org/June2018/#sec-Type-System.Non-Null)
|
||||
*
|
||||
* Chain this property to *unwrap* the right-hand-side type (the field type or a list) of a Non-Null type.
|
||||
* Chain this property to _unwrap_ the right-hand-side type (the field type or a list) of a Non-Null type.
|
||||
*
|
||||
* In Nexus output types are nullable by default so this is only useful when you have changed your
|
||||
* nonNullDefaults configuration either globally in your makeSchema config or at the type definition level
|
||||
|
|
@ -516,7 +461,7 @@ export class OutputDefinitionBlock<TypeName extends string> {
|
|||
*
|
||||
* This is a shorthand equivalent to:
|
||||
*
|
||||
* `t.field('...', { type: boolean() })`
|
||||
* ` t.field('...', { type: boolean() }) `
|
||||
*
|
||||
* @example
|
||||
* objectType({
|
||||
|
|
@ -533,10 +478,14 @@ export class OutputDefinitionBlock<TypeName extends string> {
|
|||
* 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
|
||||
*
|
||||
* ...in which case the default resolver will be available whose behaviour is to simply return that field
|
||||
* from the received source type.
|
||||
* 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.
|
||||
*/
|
||||
boolean<FieldName extends string>(name: FieldName, ...config: ScalarOutSpread<TypeName, FieldName>) {
|
||||
this.addScalarField(name, 'Boolean', config)
|
||||
|
|
@ -554,7 +503,7 @@ export class OutputDefinitionBlock<TypeName extends string> {
|
|||
*
|
||||
* This is a shorthand, equivalent to:
|
||||
*
|
||||
* `t.field('...', { type: string() })`
|
||||
* ` t.field('...', { type: string() }) `
|
||||
*
|
||||
* @example
|
||||
* objectType({
|
||||
|
|
@ -571,10 +520,14 @@ export class OutputDefinitionBlock<TypeName extends string> {
|
|||
* 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
|
||||
*
|
||||
* ...in which case the default resolver will be available whose behaviour is to simply return that field
|
||||
* from the received source type.
|
||||
* 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.
|
||||
*/
|
||||
string<FieldName extends string>(name: FieldName, ...config: ScalarOutSpread<TypeName, FieldName>) {
|
||||
this.addScalarField(name, 'String', config)
|
||||
|
|
@ -593,7 +546,7 @@ export class OutputDefinitionBlock<TypeName extends string> {
|
|||
*
|
||||
* This is a shorthand, equivalent to:
|
||||
*
|
||||
* `t.field('...', { type: id() })`
|
||||
* ` t.field('...', { type: id() }) `
|
||||
*
|
||||
* @example
|
||||
* objectType({
|
||||
|
|
@ -610,10 +563,14 @@ export class OutputDefinitionBlock<TypeName extends string> {
|
|||
* 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
|
||||
*
|
||||
* ...in which case the default resolver will be available whose behaviour is to simply return that field
|
||||
* from the received source type.
|
||||
* 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.
|
||||
*/
|
||||
id<FieldName extends string>(name: FieldName, ...config: ScalarOutSpread<TypeName, FieldName>) {
|
||||
this.addScalarField(name, 'ID', config)
|
||||
|
|
@ -630,7 +587,7 @@ export class OutputDefinitionBlock<TypeName extends string> {
|
|||
*
|
||||
* This is a shorthand equivalent to:
|
||||
*
|
||||
* `t.field('...', { type: int() })`
|
||||
* ` t.field('...', { type: int() }) `
|
||||
*
|
||||
* @example
|
||||
* objectType({
|
||||
|
|
@ -647,10 +604,14 @@ export class OutputDefinitionBlock<TypeName extends string> {
|
|||
* 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
|
||||
*
|
||||
* ...in which case the default resolver will be available whose behaviour is to simply return that field
|
||||
* from the received source type.
|
||||
* 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.
|
||||
*/
|
||||
int<FieldName extends string>(name: FieldName, ...config: ScalarOutSpread<TypeName, FieldName>) {
|
||||
this.addScalarField(name, 'Int', config)
|
||||
|
|
@ -668,7 +629,7 @@ export class OutputDefinitionBlock<TypeName extends string> {
|
|||
*
|
||||
* This is a shorthand, equivalent to:
|
||||
*
|
||||
* `t.field('...', { type: float() })`
|
||||
* ` t.field('...', { type: float() }) `
|
||||
*
|
||||
* @example
|
||||
* objectType({
|
||||
|
|
@ -685,10 +646,14 @@ export class OutputDefinitionBlock<TypeName extends string> {
|
|||
* 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
|
||||
*
|
||||
* ...in which case the default resolver will be available whose behaviour is to simply return that field
|
||||
* from the received source type.
|
||||
* 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.
|
||||
*/
|
||||
float<FieldName extends string>(name: FieldName, ...config: ScalarOutSpread<TypeName, FieldName>) {
|
||||
this.addScalarField(name, 'Float', config)
|
||||
|
|
@ -716,44 +681,12 @@ 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.
|
||||
* @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.
|
||||
*/
|
||||
field<FieldName extends string>(name: FieldName, config: FieldOutConfig<TypeName, FieldName>): void
|
||||
/**
|
||||
* [GraphQL 2018 Spec](https://spec.graphql.org/June2018/#sec-Language.Fields)
|
||||
*
|
||||
* Define a field on this object.
|
||||
*
|
||||
* A field describes one discrete piece of information available to request within a [selection
|
||||
* set](https://spec.graphql.org/June2018/#sec-Selection-Sets). They are in fact most of what any selection
|
||||
* set will contain. Fields can be typed as scalars (marking the terminal point of a branch of a selection
|
||||
* set) or as other object types in your schema thus allowing you to model relationships between things.
|
||||
*
|
||||
* @example
|
||||
* objectType({
|
||||
* name: 'User',
|
||||
* definition(t) {
|
||||
* t.field({
|
||||
* name: 'id',
|
||||
* type: id(),
|
||||
* description: 'The unique identification number for this user',
|
||||
* })
|
||||
* },
|
||||
* })
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
field<FieldName extends string>(config: FieldOutConfigWithName<TypeName, FieldName>): void
|
||||
field<FieldName extends string>(
|
||||
...args:
|
||||
| [name: FieldName, config: FieldOutConfig<TypeName, FieldName>]
|
||||
| [config: FieldOutConfigWithName<TypeName, FieldName>]
|
||||
): void {
|
||||
const config = args.length === 2 ? { name: args[0], ...args[1] } : args[0]
|
||||
|
||||
field<FieldName extends string>(name: FieldName, config: FieldOutConfig<TypeName, FieldName>) {
|
||||
this.typeBuilder.addField({
|
||||
name,
|
||||
...config,
|
||||
configFor: 'outputField',
|
||||
wrapping: this.wrapping,
|
||||
|
|
@ -792,21 +725,11 @@ export class OutputDefinitionBlock<TypeName extends string> {
|
|||
}
|
||||
}
|
||||
|
||||
/** TODO move the code below to definitionBlocks/input.ts Input */
|
||||
|
||||
// prettier-ignore
|
||||
export interface NexusInputFieldConfig<TypeName extends string, FieldName extends string> extends CommonInputFieldConfig<TypeName, FieldName> {
|
||||
export interface NexusInputFieldConfig<TypeName extends string, FieldName extends string>
|
||||
extends CommonInputFieldConfig<TypeName, FieldName> {
|
||||
type: AllInputTypes | AllNexusInputTypeDefs
|
||||
}
|
||||
|
||||
// prettier-ignore
|
||||
export interface NexusInputFieldConfigWithName<TypeName extends string, FieldName extends string> extends NexusInputFieldConfig<TypeName, FieldName> {
|
||||
/**
|
||||
* The name of this field. Must conform to the regex pattern: [_A-Za-z][_0-9A-Za-z]*
|
||||
*/
|
||||
name: FieldName
|
||||
}
|
||||
|
||||
export type NexusInputFieldDef = NexusInputFieldConfig<string, string> & {
|
||||
configFor: 'inputField'
|
||||
name: string
|
||||
|
|
@ -864,17 +787,13 @@ export class InputDefinitionBlock<TypeName extends string> {
|
|||
this.field(fieldName, { ...config, type: 'Float' })
|
||||
}
|
||||
|
||||
field<FieldName extends string>(config: NexusInputFieldConfigWithName<TypeName, FieldName>): void
|
||||
field<FieldName extends string>(name: FieldName, config: NexusInputFieldConfig<TypeName, FieldName>): void
|
||||
field<FieldName extends string>(
|
||||
...args:
|
||||
| [FieldName, NexusInputFieldConfig<TypeName, FieldName>]
|
||||
| [NexusInputFieldConfigWithName<TypeName, FieldName>]
|
||||
): void {
|
||||
const config = args.length === 2 ? { name: args[0], ...args[1] } : args[0]
|
||||
|
||||
fieldName: FieldName,
|
||||
fieldConfig: NexusInputFieldConfig<TypeName, FieldName>
|
||||
) {
|
||||
this.typeBuilder.addField({
|
||||
...config,
|
||||
name: fieldName,
|
||||
...fieldConfig,
|
||||
wrapping: this.wrapping,
|
||||
parentType: this.typeName,
|
||||
configFor: 'inputField',
|
||||
|
|
|
|||
|
|
@ -1,230 +0,0 @@
|
|||
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,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
import { assertValidName, GraphQLEnumTypeConfig, GraphQLEnumValueConfig } from 'graphql'
|
||||
import { arg, NexusArgDef, NexusAsArgConfig } from './args'
|
||||
import type { Directives } from './directive'
|
||||
import { Maybe, NexusTypes, SourceTypingDef, withNexusSymbol } from './_types'
|
||||
import { NexusTypes, SourceTypingDef, withNexusSymbol } from './_types'
|
||||
|
||||
type TypeScriptEnumLike = {
|
||||
[key: number]: string
|
||||
|
|
@ -13,36 +12,29 @@ export interface EnumMemberInfo {
|
|||
/** The internal representation of the enum */
|
||||
value?: string | number | object | boolean
|
||||
/** The description to annotate the GraphQL SDL */
|
||||
description?: Maybe<string>
|
||||
description?: 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?: Maybe<string> // | DeprecationInfo;
|
||||
deprecation?: 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?: Maybe<string>
|
||||
description?: string | null
|
||||
/** 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 */
|
||||
members:
|
||||
| ReadonlyArray<string | EnumMemberInfo>
|
||||
| Array<string | EnumMemberInfo>
|
||||
| Record<string, string | number | object | boolean>
|
||||
| TypeScriptEnumLike
|
||||
/**
|
||||
|
|
@ -51,15 +43,6 @@ 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> {
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ export interface NexusExtendTypeConfig<TypeName extends string> {
|
|||
* "definition" method.
|
||||
*
|
||||
* @param t The type builder. Usually the same as that passed to objectType "definition" method except if
|
||||
* extending the Subscription type in which case you get a subscription type builder (which differs
|
||||
* slightly in that it requires implementation of a "subscribe" method on field configurations).
|
||||
* extending the Subscription type in which case you get a subscription type builder (which differs
|
||||
* slightly in that it requires implementation of a "subscribe" method on field configurations).
|
||||
*/
|
||||
definition(
|
||||
t: IsSubscriptionType<TypeName> extends true ? SubscriptionBuilder : ObjectDefinitionBlock<TypeName>
|
||||
|
|
@ -57,10 +57,10 @@ withNexusSymbol(NexusExtendTypeDef, NexusTypes.ExtendObject)
|
|||
* use-case is so common Nexus ships dedicated functions for it: queryField, mutationField, subscriptionField.
|
||||
*
|
||||
* You can extend types before defining them strictly with objectType or the root field functions (queryType
|
||||
* etc.). The typing for "type" property will appear to suggest that you cannot, however once Nexus reflection
|
||||
* has run you'll see that the type you "extended" exists in the schema and that your static typing error has
|
||||
* been resolved. This behaviour is a convenience especially when extending root types which you might never
|
||||
* define in your schema directly.
|
||||
* etc.). The typing for "type" property will appear to suggest that you cannot, however once Nexus
|
||||
* reflection has run you'll see that the type you "extended" exists in the schema and that your static
|
||||
* typing error has been resolved. This behaviour is a convenience especially when extending root types which
|
||||
* you might never define in your schema directly.
|
||||
*
|
||||
* @example
|
||||
* // types/User.ts
|
||||
|
|
@ -85,8 +85,8 @@ withNexusSymbol(NexusExtendTypeDef, NexusTypes.ExtendObject)
|
|||
* },
|
||||
* })
|
||||
*
|
||||
* @param config The specification of which type to extend and how. This is basically a subset of the
|
||||
* configuration object passed to the objectType function.
|
||||
* @param config The specification of which type to extend and how. This is basically a subset of the configuration
|
||||
* object passed to the objectType function.
|
||||
*/
|
||||
export function extendType<TypeName extends AllOutputTypesPossible>(config: NexusExtendTypeConfig<TypeName>) {
|
||||
return new NexusExtendTypeDef(config.type, { ...config, name: config.type }) as NexusExtendTypeDef<any>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import { assertValidName, GraphQLInputObjectTypeConfig } from 'graphql'
|
||||
import { arg, NexusArgDef, NexusAsArgConfig } from './args'
|
||||
import type { InputDefinitionBlock } from './definitionBlocks'
|
||||
import type { Directives } from './directive'
|
||||
import { Maybe, NexusTypes, NonNullConfig, withNexusSymbol } from './_types'
|
||||
import { NexusTypes, NonNullConfig, withNexusSymbol } from './_types'
|
||||
|
||||
export type NexusInputObjectTypeConfig<TypeName extends string> = {
|
||||
/** Name of the input object type */
|
||||
|
|
@ -10,7 +9,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?: Maybe<string>
|
||||
description?: 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.
|
||||
|
|
@ -22,15 +21,6 @@ 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> {
|
||||
|
|
|
|||
|
|
@ -2,19 +2,18 @@ import { assertValidName, GraphQLInterfaceTypeConfig } from 'graphql'
|
|||
import type { FieldResolver, GetGen, InterfaceFieldsFor, ModificationType } from '../typegenTypeHelpers'
|
||||
import type { ArgsRecord } from './args'
|
||||
import { OutputDefinitionBlock, OutputDefinitionBuilder } from './definitionBlocks'
|
||||
import type { Directives } from './directive'
|
||||
import { AbstractTypes, Maybe, NexusTypes, NonNullConfig, SourceTypingDef, withNexusSymbol } from './_types'
|
||||
import { AbstractTypes, 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?: Maybe<string>
|
||||
description?: 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?: Maybe<ArgsRecord>
|
||||
args?: ArgsRecord
|
||||
/**
|
||||
* Custom extensions, as supported in graphql-js
|
||||
*
|
||||
|
|
@ -45,7 +44,7 @@ export type NexusInterfaceTypeConfig<TypeName extends string> = {
|
|||
*/
|
||||
nonNullDefaults?: NonNullConfig
|
||||
/** The description to annotate the GraphQL SDL */
|
||||
description?: Maybe<string>
|
||||
description?: string | null
|
||||
/** Source type information for this type */
|
||||
sourceType?: SourceTypingDef
|
||||
/**
|
||||
|
|
@ -54,15 +53,6 @@ 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 {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
import { isType } from 'graphql'
|
||||
import { isNexusMeta } from './nexusMeta'
|
||||
import { isNexusStruct, NexusListableTypes } from './wrapping'
|
||||
import { AllNamedTypeDefs, 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
|
||||
|
|
@ -10,12 +13,7 @@ export class NexusListDef<TypeName extends NexusListableTypes> {
|
|||
|
||||
constructor(readonly ofNexusType: TypeName) {
|
||||
/* istanbul ignore if */
|
||||
if (
|
||||
typeof ofNexusType !== 'string' &&
|
||||
!isNexusStruct(ofNexusType) &&
|
||||
!isNexusMeta(ofNexusType) &&
|
||||
!isType(ofNexusType)
|
||||
) {
|
||||
if (typeof ofNexusType !== 'string' && !isNexusStruct(ofNexusType) && !isType(ofNexusType)) {
|
||||
throw new Error('Cannot wrap unknown types in list(). Saw ' + ofNexusType)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { FieldOutConfig, OutputDefinitionBlock } from './definitionBlocks'
|
||||
import type { FieldOutConfig, OutputDefinitionBlock } from '../core'
|
||||
import { extendType, NexusExtendTypeDef } from './extendType'
|
||||
|
||||
export type MutationFieldConfig<FieldName extends string> =
|
||||
|
|
@ -114,8 +114,9 @@ export function mutationField(
|
|||
* // ...
|
||||
* })
|
||||
*
|
||||
* @param name The name of the field on the Mutation type. Names are case‐sensitive and must conform to
|
||||
* pattern: `[_A-Za-z][_0-9A-Za-z]*`
|
||||
* @param name The name of the field on the Mutation type. Names are case‐sensitive and must conform to 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>(
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import { NexusObjectTypeConfig, objectType } from './objectType'
|
|||
*
|
||||
* @example
|
||||
* mutationType({
|
||||
* definition(t) {
|
||||
* definitin(t) {
|
||||
* t.field('signup', {
|
||||
* type: 'User',
|
||||
* args: {
|
||||
|
|
@ -37,7 +37,7 @@ import { NexusObjectTypeConfig, objectType } from './objectType'
|
|||
* })
|
||||
*
|
||||
* @param config Specify your Mutation type's fields, description, and more. See each config property's jsDoc
|
||||
* for more detail.
|
||||
* for more detail.
|
||||
*/
|
||||
export function mutationType(config: Omit<NexusObjectTypeConfig<'Mutation'>, 'name'>) {
|
||||
return objectType({ ...config, name: 'Mutation' })
|
||||
|
|
|
|||
|
|
@ -1,64 +0,0 @@
|
|||
import { ownProp } from '../utils'
|
||||
import type { NexusInterfaceTypeDef } from './interfaceType'
|
||||
import type { NexusObjectTypeDef } from './objectType'
|
||||
import { isNexusStruct, isNexusInterfaceTypeDef, isNexusObjectTypeDef } from './wrapping'
|
||||
|
||||
/** Symbol marking an object as something that can provide Nexus schema definitions */
|
||||
export const NEXUS_TYPE = Symbol.for('@nexus/meta/NEXUS_TYPE')
|
||||
export const NEXUS_BUILD = Symbol.for('@nexus/meta/NEXUS_BUILD')
|
||||
|
||||
type OutType = NexusObjectTypeDef<any> | NexusInterfaceTypeDef<any>
|
||||
|
||||
/** Object representing a single output or interface type */
|
||||
export type NexusMetaTypeProp = {
|
||||
[NEXUS_TYPE]: OutType
|
||||
}
|
||||
|
||||
export type NexusMetaTypeFn = {
|
||||
[NEXUS_TYPE]: () => OutType
|
||||
}
|
||||
|
||||
export type NexusMetaType = NexusMetaTypeProp | NexusMetaTypeFn
|
||||
|
||||
/** Object containing a symbol defining a function that should be fed into the Nexus type construction layer */
|
||||
export type NexusMetaBuild = {
|
||||
[NEXUS_BUILD]: () => any
|
||||
}
|
||||
|
||||
export type NexusMeta = NexusMetaType | NexusMetaBuild
|
||||
|
||||
export function isNexusMetaBuild(obj: any): obj is NexusMetaBuild {
|
||||
return Boolean(obj && typeof ownProp.get(obj, NEXUS_BUILD) === 'function')
|
||||
}
|
||||
|
||||
export function isNexusMetaType(obj: any): obj is NexusMetaType {
|
||||
return isNexusMetaTypeProp(obj) || isNexusMetaTypeFn(obj)
|
||||
}
|
||||
|
||||
export function isNexusMetaTypeProp(obj: any): obj is NexusMetaTypeProp {
|
||||
return Boolean(obj && ownProp.has(obj, NEXUS_TYPE) && isNexusStruct(ownProp.get(obj, NEXUS_TYPE)))
|
||||
}
|
||||
|
||||
export function isNexusMetaTypeFn(obj: any): obj is NexusMetaTypeFn {
|
||||
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 {
|
||||
return isNexusMetaBuild(obj) || isNexusMetaType(obj) || isNexusMetaTypeFn(obj)
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the thunk, replacing it with the type
|
||||
*
|
||||
* @param obj
|
||||
*/
|
||||
export function resolveNexusMetaType(obj: NexusMetaType): OutType {
|
||||
let value = ownProp.get(obj, NEXUS_TYPE)
|
||||
if (typeof value === 'function') {
|
||||
value = ownProp.set(obj, NEXUS_TYPE, value.call(obj))
|
||||
}
|
||||
if (!isNexusObjectTypeDef(value) && !isNexusInterfaceTypeDef(value)) {
|
||||
throw new Error(`Expected property of NEXUS_TYPE to be an object or interface type`)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
import { isNonNullType, isType } from 'graphql'
|
||||
import { isNexusMeta } from './nexusMeta'
|
||||
import { isNexusNonNullTypeDef, isNexusNullTypeDef, isNexusStruct, NexusNonNullableTypes } from './wrapping'
|
||||
import { NexusTypes, withNexusSymbol } from './_types'
|
||||
|
||||
|
|
@ -9,12 +8,7 @@ export class NexusNonNullDef<TypeName extends NexusNonNullableTypes> {
|
|||
private _isNexusNonNullDef: boolean = true
|
||||
|
||||
constructor(readonly ofNexusType: TypeName) {
|
||||
if (
|
||||
typeof ofNexusType !== 'string' &&
|
||||
!isNexusStruct(ofNexusType) &&
|
||||
!isNexusMeta(ofNexusType) &&
|
||||
!isType(ofNexusType)
|
||||
) {
|
||||
if (typeof ofNexusType !== 'string' && !isNexusStruct(ofNexusType) && !isType(ofNexusType)) {
|
||||
throw new Error('Cannot wrap unknown types in a nonNull(). Saw ' + ofNexusType)
|
||||
}
|
||||
}
|
||||
|
|
@ -60,13 +54,16 @@ withNexusSymbol(NexusNonNullDef, NexusTypes.NonNull)
|
|||
*
|
||||
* @param type The type to wrap in Non-Null. This may be expressed in one of three ways:
|
||||
*
|
||||
* 1. As string literals matching the name of a builtin scalar. E.g.: 'ID', 'String', ...
|
||||
* 2. As string literals matching the name of another type. E.g.: 'User', 'Location', ... Thanks to [Nexus'
|
||||
* reflection system](https://nxs.li/guides/reflection) this is typesafe and autocompletable. This is
|
||||
* the idiomatic approach in Nexus because it avoids excessive importing and circular references.
|
||||
* 3. As references to other enums or object type definitions. E.g.: User, Location
|
||||
* 1. As string literals matching the name of a builtin scalar. E.g.: 'ID', 'String', ...
|
||||
*
|
||||
* You may also use other type modifier helpers like list() which in turn accept one of the three
|
||||
* 2. As string literals matching the name of another type. E.g.: 'User', 'Location', ... Thanks to
|
||||
* [Nexus' reflection
|
||||
* system](https://nxs.li/guides/reflection) this is typesafe and autocompletable. This is the idiomatic
|
||||
* approach in Nexus because it avoids excessive importing and circular references.
|
||||
*
|
||||
* 3. As references to other enums or object type definitions. E.g.: User, Location
|
||||
*
|
||||
* You may also use other type modifier helpers like list() which in turn accept one of the three
|
||||
*/
|
||||
export function nonNull<TypeName extends NexusNonNullableTypes>(type: TypeName) {
|
||||
if (isNexusNonNullTypeDef(type) || isNonNullType(type)) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { isType } from 'graphql'
|
||||
import { isNexusMeta } from './nexusMeta'
|
||||
import { isNexusNonNullTypeDef, isNexusNullTypeDef, isNexusStruct, NexusNullableTypes } from './wrapping'
|
||||
import { NexusTypes, withNexusSymbol } from './_types'
|
||||
|
||||
|
|
@ -9,12 +8,7 @@ export class NexusNullDef<TypeName extends NexusNullableTypes> {
|
|||
private _isNexusNullDef: boolean = true
|
||||
|
||||
constructor(readonly ofNexusType: TypeName) {
|
||||
if (
|
||||
typeof ofNexusType !== 'string' &&
|
||||
!isNexusStruct(ofNexusType) &&
|
||||
!isNexusMeta(ofNexusType) &&
|
||||
!isType(ofNexusType)
|
||||
) {
|
||||
if (typeof ofNexusType !== 'string' && !isNexusStruct(ofNexusType) && !isType(ofNexusType)) {
|
||||
throw new Error('Cannot wrap unknown types in nullable(). Saw ' + ofNexusType)
|
||||
}
|
||||
}
|
||||
|
|
@ -64,13 +58,16 @@ withNexusSymbol(NexusNullDef, NexusTypes.Null)
|
|||
*
|
||||
* @param type The type to wrap in Non-Null. This may be expressed in one of three ways:
|
||||
*
|
||||
* 1. As string literals matching the name of a builtin scalar. E.g.: 'ID', 'String', ...
|
||||
* 2. As string literals matching the name of another type. E.g.: 'User', 'Location', ... Thanks to [Nexus'
|
||||
* reflection system](https://nxs.li/guides/reflection) this is typesafe and autocompletable. This is
|
||||
* the idiomatic approach in Nexus because it avoids excessive importing and circular references.
|
||||
* 3. As references to other enums or object type definitions. E.g.: User, Location
|
||||
* 1. As string literals matching the name of a builtin scalar. E.g.: 'ID', 'String', ...
|
||||
*
|
||||
* You may also use other type modifier helpers like list() which in turn accept one of the three
|
||||
* 2. As string literals matching the name of another type. E.g.: 'User', 'Location', ... Thanks to
|
||||
* [Nexus' reflection
|
||||
* system](https://nxs.li/guides/reflection) this is typesafe and autocompletable. This is the idiomatic
|
||||
* approach in Nexus because it avoids excessive importing and circular references.
|
||||
*
|
||||
* 3. As references to other enums or object type definitions. E.g.: User, Location
|
||||
*
|
||||
* You may also use other type modifier helpers like list() which in turn accept one of the three
|
||||
*/
|
||||
export function nullable<TypeName extends NexusNullableTypes>(type: TypeName) {
|
||||
if (isNexusNonNullTypeDef(type)) {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
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, Maybe, NexusTypes, NonNullConfig, SourceTypingDef, withNexusSymbol } from './_types'
|
||||
import { AbstractTypes, NexusTypes, NonNullConfig, SourceTypingDef, withNexusSymbol } from './_types'
|
||||
|
||||
export interface ObjectDefinitionBuilder extends OutputDefinitionBuilder {
|
||||
addInterfaces(toAdd: Implemented[]): void
|
||||
|
|
@ -103,7 +102,7 @@ export type NexusObjectTypeConfig<TypeName extends string> = {
|
|||
* // # ...
|
||||
* // }
|
||||
*/
|
||||
description?: Maybe<string>
|
||||
description?: string
|
||||
/**
|
||||
* [Source Types Guide](https://nxs.li/guides/backing-types)
|
||||
*
|
||||
|
|
@ -119,8 +118,8 @@ export type NexusObjectTypeConfig<TypeName extends string> = {
|
|||
*
|
||||
* @example
|
||||
* {
|
||||
* "module": "some-package",
|
||||
* "export": "User"
|
||||
* module: 'some-package',
|
||||
* export: 'User',
|
||||
* }
|
||||
*
|
||||
* @example
|
||||
|
|
@ -166,9 +165,10 @@ export type NexusObjectTypeConfig<TypeName extends string> = {
|
|||
* 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* time––as 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_ time––as this code will run during
|
||||
* build to support [Nexus' reflection system](https://nxs.li/guides/reflection).
|
||||
*
|
||||
* @example
|
||||
* objectType({
|
||||
|
|
@ -186,19 +186,10 @@ 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>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { FieldOutConfig, OutputDefinitionBlock } from './definitionBlocks'
|
||||
import type { FieldOutConfig, OutputDefinitionBlock } from '../core'
|
||||
import { extendType, NexusExtendTypeDef } from './extendType'
|
||||
|
||||
export type QueryFieldConfig<FieldName extends string> =
|
||||
|
|
@ -101,7 +101,8 @@ export function queryField(
|
|||
* })
|
||||
*
|
||||
* @param name The name of the field on the Query type. Names are case‐sensitive 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>(
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import { NexusObjectTypeConfig, objectType } from './objectType'
|
|||
*
|
||||
* @example
|
||||
* queryType({
|
||||
* definition(t) {
|
||||
* definitin(t) {
|
||||
* t.field('user', {
|
||||
* type: 'User',
|
||||
* args: {
|
||||
|
|
@ -36,8 +36,8 @@ import { NexusObjectTypeConfig, objectType } from './objectType'
|
|||
* },
|
||||
* })
|
||||
*
|
||||
* @param config Specify your Query type's fields, description, and more. See each config property's jsDoc for
|
||||
* more detail.
|
||||
* @param config Specify your Query type's fields, description, and more. See each config property's jsDoc
|
||||
* for more detail.
|
||||
*/
|
||||
export function queryType(config: Omit<NexusObjectTypeConfig<'Query'>, 'name'>) {
|
||||
return objectType({ ...config, name: 'Query' })
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
import { assertValidName, GraphQLNamedType, GraphQLScalarTypeConfig } from 'graphql'
|
||||
import type { AllNexusInputTypeDefs, AllNexusOutputTypeDefs } from '../core'
|
||||
import { assertValidName, GraphQLScalarType, GraphQLScalarTypeConfig } from 'graphql'
|
||||
import { decorateType } from './decorateType'
|
||||
import type { Directives } from './directive'
|
||||
import { GraphQLNamedOutputType, Maybe, NexusTypes, SourceTypingDef, withNexusSymbol } from './_types'
|
||||
import { NexusTypes, SourceTypingDef, withNexusSymbol } from './_types'
|
||||
|
||||
export interface ScalarBase
|
||||
extends Pick<
|
||||
|
|
@ -12,7 +10,7 @@ export interface ScalarBase
|
|||
|
||||
export interface ScalarConfig {
|
||||
/** Any deprecation info for this scalar type */
|
||||
deprecation?: Maybe<string> // | DeprecationInfo;
|
||||
deprecation?: string // | DeprecationInfo;
|
||||
/** Adds this type as a method on the Object/Interface definition blocks */
|
||||
asNexusMethod?: string
|
||||
/** Source type information for this type */
|
||||
|
|
@ -23,13 +21,6 @@ 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 {
|
||||
|
|
@ -52,13 +43,13 @@ export function scalarType<TypeName extends string>(options: NexusScalarTypeConf
|
|||
return new NexusScalarTypeDef(options.name, options)
|
||||
}
|
||||
|
||||
export function asNexusMethod<T extends GraphQLNamedType>(
|
||||
namedType: T,
|
||||
export function asNexusMethod<T extends GraphQLScalarType>(
|
||||
scalar: T,
|
||||
methodName: string,
|
||||
sourceType?: SourceTypingDef
|
||||
): T extends GraphQLNamedOutputType ? AllNexusOutputTypeDefs : AllNexusInputTypeDefs {
|
||||
return decorateType(namedType, {
|
||||
): T {
|
||||
return decorateType(scalar, {
|
||||
asNexusMethod: methodName,
|
||||
sourceType,
|
||||
}) as any
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,16 +15,16 @@ export type SubscriptionFieldConfig<FieldName extends string, Event> =
|
|||
* `extendType({ type: 'Subscription' })`
|
||||
*
|
||||
* The Subscription type is one of three [root
|
||||
* types](https://spec.graphql.org/June2018/#sec-Root-Operation-Types) in GraphQL and its fields represent API
|
||||
* operations your clients can run to be pushed data changes over time.
|
||||
* types](https://spec.graphql.org/June2018/#sec-Root-Operation-Types) in GraphQL and its fields represent
|
||||
* API operations your clients can run to be pushed data changes over time.
|
||||
*
|
||||
* Use this instead of subscriptionType if you are going to modularize your schema and thus be wanting to
|
||||
* contribute fields to the Subscription type from multiple modules. You do not have to have previously
|
||||
* defined a Query type before using this. If you haven't Nexus will create one automatically for you.
|
||||
*
|
||||
* Note that the main difference about Subscription type from other object types is that its field
|
||||
* configurations require a special "subscribe" method where you can return an asynchronous iterator. Promises
|
||||
* yielded by that iterator become available to the resolver in its first param, the source data.
|
||||
* configurations require a special "subscribe" method where you can return an asynchronous iterator.
|
||||
* Promises yielded by that iterator become available to the resolver in its first param, the source data.
|
||||
*
|
||||
* If you need to leverage plugins or define multiple fields then use the typeBuilder overload variant of this
|
||||
* function. Otherwise you may prefer to the field name/config variant.
|
||||
|
|
@ -126,16 +126,16 @@ export function subscriptionField(
|
|||
* `extendType({ type: 'Subscription' })`
|
||||
*
|
||||
* The Subscription type is one of three [root
|
||||
* types](https://spec.graphql.org/June2018/#sec-Root-Operation-Types) in GraphQL and its fields represent API
|
||||
* operations your clients can run to be pushed data changes over time.
|
||||
* types](https://spec.graphql.org/June2018/#sec-Root-Operation-Types) in GraphQL and its fields represent
|
||||
* API operations your clients can run to be pushed data changes over time.
|
||||
*
|
||||
* Use this instead of subscriptionType if you are going to modularize your schema and thus be wanting to
|
||||
* contribute fields to the Subscription type from multiple modules. You do not have to have previously
|
||||
* defined a Query type before using this. If you haven't Nexus will create one automatically for you.
|
||||
*
|
||||
* Note that the main difference about Subscription type from other object types is that its field
|
||||
* configurations require a special "subscribe" method where you can return an asynchronous iterator. Promises
|
||||
* yielded by that iterator become available to the resolver in its first param, the source data.
|
||||
* configurations require a special "subscribe" method where you can return an asynchronous iterator.
|
||||
* Promises yielded by that iterator become available to the resolver in its first param, the source data.
|
||||
*
|
||||
* If you need to leverage plugins or define multiple fields then use the typeBuilder overload variant of this
|
||||
* function. Otherwise you may prefer to the field name/config variant.
|
||||
|
|
@ -222,7 +222,8 @@ export function subscriptionField(
|
|||
* })
|
||||
*
|
||||
* @param name The name of the field on the Query type. Names are case‐sensitive 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 subscriptionField<FieldName extends string, Event>(
|
||||
|
|
|
|||
|
|
@ -30,17 +30,11 @@ export type SubscriptionScalarConfig<FieldName extends string, Event> =
|
|||
& SubscriptionTypeConfigBase<FieldName, Event>
|
||||
|
||||
// prettier-ignore
|
||||
export interface SubscriptionTypeConfig<FieldName extends string, Event> extends SubscriptionScalarConfig<FieldName, Event> {
|
||||
type: GetGen<'allOutputTypes'> | AllNexusOutputTypeDefs
|
||||
}
|
||||
|
||||
// prettier-ignore
|
||||
export interface SubscriptionTypeConfigWithName<FieldName extends string, Event> extends SubscriptionTypeConfig<FieldName, Event> {
|
||||
/**
|
||||
* The name of this field. Must conform to the regex pattern: [_A-Za-z][_0-9A-Za-z]*
|
||||
*/
|
||||
name: FieldName
|
||||
}
|
||||
export interface SubscriptionTypeConfig<FieldName extends string, Event>
|
||||
extends SubscriptionScalarConfig<FieldName, Event>
|
||||
{
|
||||
type: GetGen<'allOutputTypes'> | AllNexusOutputTypeDefs
|
||||
}
|
||||
|
||||
// prettier-ignore
|
||||
export interface SubscriptionBuilder {
|
||||
|
|
@ -52,8 +46,7 @@ export interface SubscriptionBuilder {
|
|||
boolean<FieldName extends string, Event>(fieldName: FieldName, opts: SubscriptionScalarConfig<FieldName, Event>): void
|
||||
id<FieldName extends string, Event>(fieldName: FieldName, config: SubscriptionScalarConfig<FieldName, Event>): void
|
||||
float<FieldName extends string, Event>(fieldName: FieldName, config: SubscriptionScalarConfig<FieldName, Event>): void
|
||||
field<FieldName extends string, Event>(config: SubscriptionTypeConfigWithName<FieldName, Event>): void
|
||||
field<FieldName extends string, Event>(name: FieldName, config: SubscriptionTypeConfig<FieldName, Event>): void
|
||||
field<FieldName extends string, Event>(name: FieldName, fieldConfig: SubscriptionTypeConfig<FieldName, Event>): void
|
||||
}
|
||||
|
||||
export type SubscriptionTypeParams = {
|
||||
|
|
@ -70,16 +63,16 @@ export type SubscriptionTypeParams = {
|
|||
* `objectType({ name: 'Subscription' })`
|
||||
*
|
||||
* The Subscription type is one of three [root
|
||||
* types](https://spec.graphql.org/June2018/#sec-Root-Operation-Types) in GraphQL and its fields represent API
|
||||
* operations your clients can run to be pushed data changes over time.
|
||||
* types](https://spec.graphql.org/June2018/#sec-Root-Operation-Types) in GraphQL and its fields represent
|
||||
* API operations your clients can run to be pushed data changes over time.
|
||||
*
|
||||
* You can only have one of these in your schema. If you are going to modularize your schema and thus be
|
||||
* wanting to contribute fields to the Subscription type from multiple modules then use
|
||||
* [queryField](https://nxs.li/docs/api/subscription-field) intead.
|
||||
*
|
||||
* Note that the main difference about Subscription type from other object types is that its field
|
||||
* configurations require a special "subscribe" method where you can return an asynchronous iterator. Promises
|
||||
* yielded by that iterator become available to the resolver in its first param, the source data.
|
||||
* configurations require a special "subscribe" method where you can return an asynchronous iterator.
|
||||
* Promises yielded by that iterator become available to the resolver in its first param, the source data.
|
||||
*
|
||||
* @example
|
||||
* // Contrived but simple self-contained example
|
||||
|
|
@ -172,8 +165,8 @@ export type SubscriptionTypeParams = {
|
|||
* },
|
||||
* })
|
||||
*
|
||||
* @param config Specify your Subscription type's fields, description, and more. See each config property's
|
||||
* jsDoc for more detail.
|
||||
* @param config Specify your Subscription type's fields, description, and more. See each config property's jsDoc
|
||||
* for more detail.
|
||||
*/
|
||||
export function subscriptionType(config: SubscriptionTypeParams) {
|
||||
return objectType({ ...config, name: 'Subscription' } as any)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import { assertValidName, GraphQLUnionTypeConfig } from 'graphql'
|
||||
import type { Directives } from '../core'
|
||||
import type { GetGen } from '../typegenTypeHelpers'
|
||||
import type { NexusObjectTypeDef } from './objectType'
|
||||
import { AbstractTypes, Maybe, NexusTypes, SourceTypingDef, withNexusSymbol } from './_types'
|
||||
import { AbstractTypes, NexusTypes, SourceTypingDef, withNexusSymbol } from './_types'
|
||||
|
||||
export interface UnionDefinitionBuilder {
|
||||
typeName: string
|
||||
|
|
@ -28,12 +27,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?: Maybe<string>
|
||||
description?: 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?: Maybe<string> // | DeprecationInfo;
|
||||
deprecation?: string // | DeprecationInfo;
|
||||
/** Source type information for this type */
|
||||
sourceType?: SourceTypingDef
|
||||
/**
|
||||
|
|
@ -42,15 +41,6 @@ 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> {
|
||||
|
|
|
|||
|
|
@ -24,33 +24,23 @@ import { NexusNonNullDef, nonNull } from './nonNull'
|
|||
import { NexusNullDef, nullable } from './nullable'
|
||||
import type { NexusObjectTypeDef } from './objectType'
|
||||
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> =
|
||||
| AllNamedInputTypeDefs<T>
|
||||
| AllNexusNamedInputTypeDefs<T>
|
||||
| NexusListDef<any>
|
||||
| NexusNonNullDef<any>
|
||||
| NexusNullDef<any>
|
||||
| GraphQLList<any>
|
||||
| GraphQLNonNull<any>
|
||||
|
||||
/** Output(named): Nexus only */
|
||||
export type AllNexusNamedOutputTypeDefs =
|
||||
| NexusObjectTypeDef<any>
|
||||
| NexusInterfaceTypeDef<any>
|
||||
|
|
@ -58,53 +48,34 @@ 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>
|
||||
| NexusNonNullDef<NexusNonNullableTypes>
|
||||
| NexusNullDef<NexusNullableTypes>
|
||||
| GraphQLType
|
||||
| NexusMetaType
|
||||
|
||||
/** All inputs to nonNull(...) */
|
||||
export type NexusNonNullableTypes =
|
||||
| GetGen<'allNamedTypes', string>
|
||||
| AllNamedTypeDefs
|
||||
| NexusListDef<NexusListableTypes>
|
||||
| NexusArgDef<any>
|
||||
| NexusMetaType
|
||||
export type NexusNonNullableTypes = AllNamedTypeDefs | NexusListDef<NexusListableTypes> | NexusArgDef<any>
|
||||
|
||||
/** All inputs to nullable(...) */
|
||||
export type NexusNullableTypes =
|
||||
| GetGen<'allNamedTypes', string>
|
||||
| AllNamedTypeDefs
|
||||
| NexusListDef<NexusListableTypes>
|
||||
| NexusArgDef<any>
|
||||
| NexusMetaType
|
||||
export type NexusNullableTypes = AllNamedTypeDefs | NexusListDef<NexusListableTypes> | NexusArgDef<any>
|
||||
|
||||
export type AllNamedTypeDefs = GetGen<'allNamedTypes', string> | AllNexusNamedTypeDefs
|
||||
|
||||
export type AllNexusNamedArgsDefs<T extends AllInputTypes = AllInputTypes> =
|
||||
| T
|
||||
| NexusArgDef<T>
|
||||
| AllNamedInputTypeDefs<T>
|
||||
| AllNexusNamedInputTypeDefs<T>
|
||||
| GraphQLInputType
|
||||
|
||||
export type AllNexusArgsDefs =
|
||||
|
|
@ -181,13 +152,6 @@ 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
|
||||
}
|
||||
|
|
@ -208,20 +172,12 @@ 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'
|
||||
|
||||
export function unwrapGraphQLDef(typeDef: GraphQLType): {
|
||||
namedType: GraphQLNamedType
|
||||
wrapping: NexusFinalWrapKind[]
|
||||
} {
|
||||
export function unwrapGraphQLDef(
|
||||
typeDef: GraphQLType
|
||||
): { namedType: GraphQLNamedType; wrapping: NexusFinalWrapKind[] } {
|
||||
const wrapping: NexusFinalWrapKind[] = []
|
||||
let namedType = typeDef
|
||||
while (isWrappingType(namedType)) {
|
||||
|
|
@ -239,17 +195,15 @@ export function unwrapGraphQLDef(typeDef: GraphQLType): {
|
|||
|
||||
/** Unwraps any wrapped Nexus or GraphQL types, turning into a list of wrapping */
|
||||
export function unwrapNexusDef(
|
||||
typeDef: AllNexusTypeDefs | AllNexusArgsDefs | GraphQLType | NexusMetaType | string
|
||||
typeDef: AllNexusTypeDefs | AllNexusArgsDefs | GraphQLType | string
|
||||
): {
|
||||
namedType: AllNexusNamedTypeDefs | AllNexusArgsDefs | GraphQLNamedType | string
|
||||
wrapping: NexusWrapKind[]
|
||||
} {
|
||||
const wrapping: NexusWrapKind[] = []
|
||||
let namedType = typeDef
|
||||
while (isNexusWrappingType(namedType) || isWrappingType(namedType) || isNexusMetaType(namedType)) {
|
||||
if (isNexusMetaType(namedType)) {
|
||||
namedType = resolveNexusMetaType(namedType)
|
||||
} else if (isWrappingType(namedType)) {
|
||||
while (isNexusWrappingType(namedType) || isWrappingType(namedType)) {
|
||||
if (isWrappingType(namedType)) {
|
||||
if (isListType(namedType)) {
|
||||
wrapping.unshift('List')
|
||||
} else if (isNonNullType(namedType)) {
|
||||
|
|
@ -279,10 +233,10 @@ export function rewrapAsGraphQLType(baseType: GraphQLNamedType, wrapping: NexusF
|
|||
let finalType: GraphQLType = baseType
|
||||
wrapping.forEach((wrap) => {
|
||||
if (wrap === 'List') {
|
||||
finalType = new GraphQLList(finalType)
|
||||
finalType = GraphQLList(finalType)
|
||||
} else if (wrap === 'NonNull') {
|
||||
if (!isNonNullType(finalType)) {
|
||||
finalType = new GraphQLNonNull(finalType)
|
||||
finalType = GraphQLNonNull(finalType)
|
||||
}
|
||||
} else {
|
||||
throw new Unreachable(wrap)
|
||||
|
|
|
|||
|
|
@ -63,9 +63,9 @@ withNexusSymbol(DynamicOutputMethodDef, NexusTypes.DynamicOutputMethod)
|
|||
* Defines a new property on the object definition block for an output type, taking arbitrary input to define
|
||||
* additional types. See the connectionPlugin:
|
||||
*
|
||||
* T.connectionField('posts', { nullable: true, totalCount(root, args, ctx, info) { return
|
||||
* ctx.user.getTotalPostCount(root.id, args) }, nodes(root, args, ctx, info) { return
|
||||
* ctx.user.getPosts(root.id, args) } })
|
||||
* T.connectionField('posts', { nullable: true, totalCount(root, args, ctx, info) {
|
||||
* return ctx.user.getTotalPostCount(root.id, args) }, nodes(root, args, ctx, info) {
|
||||
* return ctx.user.getPosts(root.id, args) } })
|
||||
*/
|
||||
export function dynamicOutputMethod<T extends string>(config: DynamicOutputMethodConfig<T>) {
|
||||
return new DynamicOutputMethodDef(config.name, config)
|
||||
|
|
|
|||
|
|
@ -1,20 +1,10 @@
|
|||
import { defaultFieldResolver, GraphQLNamedType } from 'graphql'
|
||||
import type { DynamicFieldDefs, SchemaConfig } from './builder'
|
||||
import type { SourceTypings } from './definitions/_types'
|
||||
import type { SourceTypingDef, 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?: {
|
||||
|
|
@ -28,17 +18,13 @@ 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>>) {
|
||||
|
|
@ -48,7 +34,6 @@ 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
|
||||
|
|
@ -58,7 +43,6 @@ 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
|
||||
|
|
@ -68,7 +52,6 @@ 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
|
||||
|
|
@ -78,8 +61,7 @@ export class NexusInterfaceTypeExtension<TypeName extends string = any> {
|
|||
|
||||
export interface NexusSchemaExtensionConfig extends Omit<SchemaConfig, 'types'> {
|
||||
dynamicFields: DynamicFieldDefs
|
||||
sourceTypings: SourceTypings
|
||||
schemaDirectives?: Directives
|
||||
rootTypings: SourceTypings
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -89,3 +71,10 @@ export interface NexusSchemaExtensionConfig extends Omit<SchemaConfig, 'types'>
|
|||
export class NexusSchemaExtension {
|
||||
constructor(readonly config: NexusSchemaExtensionConfig) {}
|
||||
}
|
||||
|
||||
export type NexusScalarExtensions = {
|
||||
nexus: {
|
||||
asNexusMethod?: string
|
||||
sourceType?: SourceTypingDef
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,219 +0,0 @@
|
|||
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, '\\"""') + '"""'
|
||||
}
|
||||
|
|
@ -2,9 +2,8 @@ import * as blocks from './blocks'
|
|||
import * as core from './core'
|
||||
|
||||
// All of the Public API definitions
|
||||
export { makeSchema } from './makeSchema'
|
||||
export { makeSchema } from './builder'
|
||||
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'
|
||||
|
|
|
|||
|
|
@ -1,171 +0,0 @@
|
|||
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, objValues, runAbstractTypeRuntimeChecks } from './utils'
|
||||
|
||||
/**
|
||||
* Defines the GraphQL schema, by combining the GraphQL types defined by the GraphQL Nexus layer or any
|
||||
* manually defined GraphQLType objects.
|
||||
*
|
||||
* Requires at least one type be named "Query", which will be used as the root query type.
|
||||
*/
|
||||
export function makeSchema(config: SchemaConfig): NexusGraphQLSchema {
|
||||
const { schema, missingTypes, finalConfig } = makeSchemaInternal(config)
|
||||
const typegenConfig = resolveTypegenConfig(finalConfig)
|
||||
const sdl = typegenConfig.outputs.schema
|
||||
const typegen = typegenConfig.outputs.typegen
|
||||
if (sdl || typegen) {
|
||||
// Generating in the next tick allows us to use the schema
|
||||
// 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 ==> ${typegenPath}
|
||||
GraphQL Schema ==> ${typegenConfig.outputs.schema || '(not enabled)'}`)
|
||||
process.exit(0)
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e)
|
||||
process.exit(1)
|
||||
})
|
||||
} else {
|
||||
typegenPromise.catch((e) => {
|
||||
console.error(e)
|
||||
})
|
||||
}
|
||||
}
|
||||
assertNoMissingTypes(schema, missingTypes)
|
||||
runAbstractTypeRuntimeChecks(schema, finalConfig.features)
|
||||
return schema
|
||||
}
|
||||
|
||||
/** Like makeSchema except that typegen is always run and waited upon. */
|
||||
export async function generateSchema(config: SchemaConfig): Promise<NexusGraphQLSchema> {
|
||||
const { schema, missingTypes, finalConfig } = makeSchemaInternal(config)
|
||||
const typegenConfig = resolveTypegenConfig(finalConfig)
|
||||
await new TypegenMetadata(typegenConfig).generateArtifacts(schema)
|
||||
assertNoMissingTypes(schema, missingTypes)
|
||||
runAbstractTypeRuntimeChecks(schema, finalConfig.features)
|
||||
return schema
|
||||
}
|
||||
|
||||
/**
|
||||
* Mainly useful for testing, generates the schema and returns the artifacts that would have been otherwise
|
||||
* written to the filesystem.
|
||||
*/
|
||||
generateSchema.withArtifacts = async (
|
||||
config: SchemaConfig,
|
||||
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, globalTypes } = await new TypegenMetadata(
|
||||
typegenConfig
|
||||
).generateArtifactContents(schema, typegen)
|
||||
assertNoMissingTypes(schema, missingTypes)
|
||||
runAbstractTypeRuntimeChecks(schema, finalConfig.features)
|
||||
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
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
export function nodeImports() {
|
||||
const fs = require('fs') as typeof import('fs')
|
||||
const path = require('path') as typeof import('path')
|
||||
return {
|
||||
fs,
|
||||
path,
|
||||
}
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ export type CreateFieldResolverInfo<FieldExt = any, TypeExt = any> = {
|
|||
parentTypeConfig: (
|
||||
| Omit<NexusGraphQLObjectTypeConfig, 'fields' | 'extensions'>
|
||||
| (Omit<NexusGraphQLInterfaceTypeConfig, 'fields' | 'extensions'> & {
|
||||
interfaces: readonly GraphQLInterfaceType[]
|
||||
interfaces: 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?: Maybe<string>
|
||||
description?: 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 */
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
import { defaultFieldResolver, GraphQLFieldResolver, GraphQLResolveInfo } from 'graphql'
|
||||
import { ArgsRecord, intArg, stringArg } from '../definitions/args'
|
||||
import type {
|
||||
CommonFieldConfig,
|
||||
FieldOutConfig,
|
||||
FieldOutConfigWithName,
|
||||
} from '../definitions/definitionBlocks'
|
||||
import type { CommonFieldConfig, FieldOutConfig } from '../definitions/definitionBlocks'
|
||||
import { NexusNonNullDef, nonNull } from '../definitions/nonNull'
|
||||
import { NexusNullDef, nullable } from '../definitions/nullable'
|
||||
import { ObjectDefinitionBlock, objectType } from '../definitions/objectType'
|
||||
|
|
@ -117,8 +113,8 @@ export interface ConnectionPluginConfig {
|
|||
* Any additional fields to make available to the connection type, beyond edges / pageInfo / nodes.
|
||||
*
|
||||
* Any fields defined extended on the Connection type will automatically receive the args from the
|
||||
* connection. If the field also defines args, they will be merged with the args of the connection, with the
|
||||
* extension's field args taking precedence if there is a conflict.
|
||||
* connection. If the field also defines args, they will be merged with the args of the connection, with
|
||||
* the extension's field args taking precedence if there is a conflict.
|
||||
*/
|
||||
extendConnection?: Record<
|
||||
string,
|
||||
|
|
@ -160,9 +156,10 @@ export interface ConnectionPluginConfig {
|
|||
}
|
||||
|
||||
// Extract the node value from the connection for a given field.
|
||||
export type NodeValue<TypeName extends string = any, FieldName extends string = any> = SourceValue<
|
||||
EdgeTypeLookup<TypeName, FieldName>
|
||||
>['node']
|
||||
export type NodeValue<TypeName extends string = any, FieldName extends string = any> = ResultValue<
|
||||
EdgeTypeLookup<TypeName, FieldName>,
|
||||
'node'
|
||||
>
|
||||
|
||||
export type ConnectionFieldConfig<TypeName extends string = any, FieldName extends string = any> = {
|
||||
type: GetGen<'allOutputTypes', string> | AllNexusNamedOutputTypeDefs
|
||||
|
|
@ -303,8 +300,8 @@ export type ConnectionFieldConfig<TypeName extends string = any, FieldName exten
|
|||
| {
|
||||
/**
|
||||
* Implement the full resolve, including `edges` and `pageInfo`. Useful in more complex pagination
|
||||
* cases, or if you want to use utilities from other libraries like GraphQL Relay JS, and only use Nexus
|
||||
* for the construction and type-safety:
|
||||
* cases, or if you want to use utilities from other libraries like GraphQL Relay JS, and only use
|
||||
* Nexus for the construction and type-safety:
|
||||
*
|
||||
* Https://github.com/graphql/graphql-relay-js
|
||||
*/
|
||||
|
|
@ -494,11 +491,11 @@ export const connectionPlugin = (connectionPluginConfig?: ConnectionPluginConfig
|
|||
definition(t2) {
|
||||
t2.list.field('edges', {
|
||||
type: edgeName as any,
|
||||
description: `https://relay.dev/graphql/connections.htm#sec-Edge-Types`,
|
||||
description: `https://facebook.github.io/relay/graphql/connections.htm#sec-Edge-Types`,
|
||||
})
|
||||
t2.nonNull.field('pageInfo', {
|
||||
type: 'PageInfo' as any,
|
||||
description: `https://relay.dev/graphql/connections.htm#sec-undefined.PageInfo`,
|
||||
description: `https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo`,
|
||||
})
|
||||
if (includeNodesField) {
|
||||
t2.list.field('nodes', {
|
||||
|
|
@ -530,11 +527,11 @@ export const connectionPlugin = (connectionPluginConfig?: ConnectionPluginConfig
|
|||
definition(t2) {
|
||||
t2.field('cursor', {
|
||||
type: cursorType ?? nonNull('String'),
|
||||
description: 'https://relay.dev/graphql/connections.htm#sec-Cursor',
|
||||
description: 'https://facebook.github.io/relay/graphql/connections.htm#sec-Cursor',
|
||||
})
|
||||
t2.field('node', {
|
||||
type: targetType,
|
||||
description: 'https://relay.dev/graphql/connections.htm#sec-Node',
|
||||
description: 'https://facebook.github.io/relay/graphql/connections.htm#sec-Node',
|
||||
})
|
||||
if (pluginExtendEdge) {
|
||||
eachObj(pluginExtendEdge, (val, key) => {
|
||||
|
|
@ -558,7 +555,7 @@ export const connectionPlugin = (connectionPluginConfig?: ConnectionPluginConfig
|
|||
objectType({
|
||||
name: 'PageInfo',
|
||||
description:
|
||||
'PageInfo cursor, as defined in https://relay.dev/graphql/connections.htm#sec-undefined.PageInfo',
|
||||
'PageInfo cursor, as defined in https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo',
|
||||
definition(t2) {
|
||||
t2.nonNull.field('hasNextPage', {
|
||||
type: 'Boolean',
|
||||
|
|
@ -709,8 +706,10 @@ export function makeResolveFn(
|
|||
return (root, args: PaginationArgs, ctx, info) => {
|
||||
const { nodes: nodesResolve } = fieldConfig
|
||||
const { decodeCursor = base64Decode, encodeCursor = base64Encode } = pluginConfig
|
||||
const { pageInfoFromNodes = defaultPageInfoFromNodes, cursorFromNode = defaultCursorFromNode } =
|
||||
mergedConfig
|
||||
const {
|
||||
pageInfoFromNodes = defaultPageInfoFromNodes,
|
||||
cursorFromNode = defaultCursorFromNode,
|
||||
} = mergedConfig
|
||||
if (!nodesResolve) {
|
||||
return null
|
||||
}
|
||||
|
|
@ -724,6 +723,10 @@ 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>>
|
||||
|
|
@ -800,9 +803,10 @@ export function makeResolveFn(
|
|||
})
|
||||
|
||||
if (hasPromise) {
|
||||
return Promise.all([Promise.all(resolvedEdgeList), Promise.all(resolvedNodeList)]).then(
|
||||
([edges, nodes]) => ({ edges, nodes })
|
||||
)
|
||||
return Promise.all([
|
||||
Promise.all(resolvedEdgeList),
|
||||
Promise.all(resolvedNodeList),
|
||||
]).then(([edges, nodes]) => ({ edges, nodes }))
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
@ -923,16 +927,9 @@ function mergeArgs(obj: object, fieldArgs: ArgsValue<any, any>): ArgsValue<any,
|
|||
*/
|
||||
function provideArgs(block: ObjectDefinitionBlock<any>, fn: () => void) {
|
||||
const fieldDef = block.field
|
||||
block.field = function (
|
||||
...args:
|
||||
| [name: string, config: FieldOutConfig<any, string>]
|
||||
| [config: FieldOutConfigWithName<any, string>]
|
||||
) {
|
||||
let config = args.length === 2 ? { name: args[0], ...args[1] } : args[0]
|
||||
|
||||
block.field = function (fieldName, config) {
|
||||
const { resolve = defaultFieldResolver } = config
|
||||
|
||||
fieldDef.call(this, {
|
||||
fieldDef.call(this, fieldName, {
|
||||
...config,
|
||||
resolve(root, args, ctx, info) {
|
||||
return resolve(root, mergeArgs(root, args), ctx, info)
|
||||
|
|
@ -945,16 +942,9 @@ function provideArgs(block: ObjectDefinitionBlock<any>, fn: () => void) {
|
|||
|
||||
function provideSourceAndArgs(block: ObjectDefinitionBlock<any>, fn: () => void) {
|
||||
const fieldDef = block.field
|
||||
block.field = function (
|
||||
...args:
|
||||
| [name: string, config: FieldOutConfig<any, string>]
|
||||
| [config: FieldOutConfigWithName<any, string>]
|
||||
) {
|
||||
let config = args.length === 2 ? { name: args[0], ...args[1] } : args[0]
|
||||
|
||||
block.field = function (fieldName, config) {
|
||||
const { resolve = defaultFieldResolver } = config
|
||||
|
||||
fieldDef.call(this, {
|
||||
fieldDef.call(this, fieldName, {
|
||||
...config,
|
||||
resolve(root, args, ctx, info) {
|
||||
return resolve(root.__connectionSource, mergeArgs(root, args), ctx, info)
|
||||
|
|
@ -974,10 +964,8 @@ 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 + startOffset], i)
|
||||
cb(nodes[i], i)
|
||||
}
|
||||
} else {
|
||||
// Only happens if we have a custom validateArgs that ignores first/last
|
||||
|
|
@ -1061,9 +1049,14 @@ 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') {
|
||||
const offset = args.before ? parseInt(args.before, 10) : nodes.length
|
||||
const len = Math.min(nodes.length, args.last)
|
||||
cursorIndex = offset - len + index
|
||||
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')
|
||||
}
|
||||
}
|
||||
return `${CURSOR_PREFIX}${cursorIndex}`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,15 +50,16 @@ export const defaultFormatError = ({ error }: FieldAuthorizePluginErrorConfig):
|
|||
|
||||
export const fieldAuthorizePlugin = (authConfig: FieldAuthorizePluginConfig = {}) => {
|
||||
const { formatError = defaultFormatError } = authConfig
|
||||
const ensureError =
|
||||
(root: any, args: any, ctx: GetGen<'context'>, info: GraphQLResolveInfo) => (error: Error) => {
|
||||
const finalErr = formatError({ error, root, args, ctx, info })
|
||||
if (finalErr instanceof Error) {
|
||||
throw finalErr
|
||||
}
|
||||
console.error(`Non-Error value ${finalErr} returned from custom formatError in authorize plugin`)
|
||||
throw new Error('Not authorized')
|
||||
const ensureError = (root: any, args: any, ctx: GetGen<'context'>, info: GraphQLResolveInfo) => (
|
||||
error: Error
|
||||
) => {
|
||||
const finalErr = formatError({ error, root, args, ctx, info })
|
||||
if (finalErr instanceof Error) {
|
||||
throw finalErr
|
||||
}
|
||||
console.error(`Non-Error value ${finalErr} returned from custom formatError in authorize plugin`)
|
||||
throw new Error('Not authorized')
|
||||
}
|
||||
let hasWarned = false
|
||||
return plugin({
|
||||
name: 'NexusAuthorize',
|
||||
|
|
|
|||
|
|
@ -31,9 +31,11 @@ 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. */
|
||||
|
|
|
|||
|
|
@ -1,323 +0,0 @@
|
|||
/** 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(', ')})`
|
||||
}
|
||||
|
|
@ -1,232 +0,0 @@
|
|||
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
|
||||
}
|
||||
|
|
@ -38,7 +38,7 @@ export type RequiredDeeply<T> = DoRequireDeeply<Exclude<T, undefined>>
|
|||
* Represents a POJO. Prevents from allowing arrays and functions.
|
||||
*
|
||||
* @remarks
|
||||
* TypeScript interfaces will not be considered sub-types.
|
||||
* TypeScript interfaces will not be considered sub-types.
|
||||
*/
|
||||
export type PlainObject = {
|
||||
[x: string]: Primitive | object
|
||||
|
|
@ -56,5 +56,3 @@ 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>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import type { GraphQLResolveInfo } from 'graphql'
|
||||
import type { Maybe } from './definitions/_types'
|
||||
import type {
|
||||
AbstractTypeResolver,
|
||||
GetGen,
|
||||
|
|
@ -43,8 +42,9 @@ export type AbstractTypeNames<TypeName extends string> = ConditionalKeys<
|
|||
>
|
||||
|
||||
/** Returns whether all the abstract type names where TypeName is used have implemented `resolveType` */
|
||||
export type IsStrategyResolveTypeImplementedInAllAbstractTypes<TypeName extends string> =
|
||||
AbstractTypeNames<TypeName> extends GetGen<'abstractsUsingStrategyResolveType'> ? true : false
|
||||
export type IsStrategyResolveTypeImplementedInAllAbstractTypes<
|
||||
TypeName extends string
|
||||
> = AbstractTypeNames<TypeName> extends GetGen<'abstractsUsingStrategyResolveType'> ? true : false
|
||||
|
||||
/** Returns whether all the members of an abstract type have implemented `isTypeOf` */
|
||||
export type IsStrategyIsTypeOfImplementedInAllMembers<AbstractTypeName extends string> = GetGen2<
|
||||
|
|
@ -122,17 +122,16 @@ 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.
|
||||
|
|
@ -201,17 +200,16 @@ 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.
|
||||
|
|
@ -279,17 +277,16 @@ 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.
|
||||
|
|
@ -347,17 +344,16 @@ 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.
|
||||
|
|
@ -390,7 +386,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?: Maybe<AbstractTypeResolver<TypeName>>
|
||||
resolveType?: AbstractTypeResolver<TypeName>
|
||||
} // Make resolveType optional when __typename strategy is enabled
|
||||
: IsFeatureEnabled2<'abstractTypeStrategies', '__typename'> extends true
|
||||
? {
|
||||
|
|
@ -401,7 +397,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?: Maybe<AbstractTypeResolver<TypeName>>
|
||||
resolveType?: AbstractTypeResolver<TypeName>
|
||||
}
|
||||
: {
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
@ -31,7 +31,8 @@ export interface SourceTypeModule {
|
|||
*
|
||||
* If not provided, the default implementation is:
|
||||
*
|
||||
* (type) => [ new RegExp(`(?:interface|type|class|enum)\\s+(${type.name})\\W`, "g"), ]
|
||||
* (type) => [
|
||||
* new RegExp(`(?:interface|type|class|enum)\\s+(${type.name})\\W`, "g"), ]
|
||||
*/
|
||||
typeMatch?: (type: GraphQLNamedType, defaultRegex: RegExp) => RegExp | RegExp[]
|
||||
/**
|
||||
|
|
@ -129,12 +130,16 @@ 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(
|
||||
|
|
@ -150,7 +155,7 @@ export function typegenAutoConfig(options: SourceTypesConfigOptions, contextType
|
|||
if (path.extname(resolvedPath) !== '.ts') {
|
||||
resolvedPath = findTypingForFile(resolvedPath, pathOrModule)
|
||||
}
|
||||
fileContents = String(await nodeImports().fs.promises.readFile(resolvedPath, 'utf-8'))
|
||||
fileContents = await 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`)
|
||||
|
|
@ -160,8 +165,9 @@ export function typegenAutoConfig(options: SourceTypesConfigOptions, contextType
|
|||
return null
|
||||
}
|
||||
|
||||
const importPath = (
|
||||
path.isAbsolute(pathOrModule) ? relativePathTo(resolvedPath, outputPath) : pathOrModule
|
||||
const importPath = (path.isAbsolute(pathOrModule)
|
||||
? relativePathTo(resolvedPath, outputPath)
|
||||
: pathOrModule
|
||||
).replace(typeScriptFileExtension, '')
|
||||
|
||||
if (allImportsMap[alias] && allImportsMap[alias] !== importPath) {
|
||||
|
|
@ -190,7 +196,7 @@ export function typegenAutoConfig(options: SourceTypesConfigOptions, contextType
|
|||
const builtinScalars = new Set(Object.keys(SCALAR_TYPES))
|
||||
|
||||
Object.keys(typeMap).forEach((typeName) => {
|
||||
if (typeName.startsWith('__')) {
|
||||
if (typeName.indexOf('__') === 0) {
|
||||
return
|
||||
}
|
||||
if (typesToIgnore.has(typeName)) {
|
||||
|
|
@ -273,7 +279,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(nodeImports().path.extname(absolutePath), '.d.ts')
|
||||
const typeDefPath = absolutePath.replace(path.extname(absolutePath), '.d.ts')
|
||||
require.resolve(typeDefPath)
|
||||
return typeDefPath
|
||||
} catch (e) {
|
||||
|
|
|
|||
|
|
@ -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,8 +22,6 @@ 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)) {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
import { GraphQLSchema, lexicographicSortSchema } from 'graphql'
|
||||
import { GraphQLSchema, lexicographicSortSchema, printSchema } from 'graphql'
|
||||
import * as path from 'path'
|
||||
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 { typegenFormatPrettier } from './typegenFormatPrettier'
|
||||
import { TypegenFormatFn, typegenFormatPrettier } from './typegenFormatPrettier'
|
||||
import { TypegenPrinter } from './typegenPrinter'
|
||||
|
||||
export interface TypegenMetadataConfig
|
||||
|
|
@ -14,7 +12,7 @@ export interface TypegenMetadataConfig
|
|||
nexusSchemaImportId?: string
|
||||
outputs: {
|
||||
schema: null | string
|
||||
typegen: null | ConfiguredTypegen
|
||||
typegen: null | string
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -28,42 +26,26 @@ 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)
|
||||
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 || this.config.outputs.typegen) {
|
||||
const { schemaTypes, tsTypes } = await this.generateArtifactContents(
|
||||
sortedSchema,
|
||||
this.config.outputs.typegen
|
||||
)
|
||||
if (this.config.outputs.schema) {
|
||||
await this.writeFile('schema', schemaTypes, this.config.outputs.schema)
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
if (this.config.outputs.typegen) {
|
||||
await this.writeFile('types', tsTypes, this.config.outputs.typegen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
async generateArtifactContents(schema: NexusGraphQLSchema, typeFilePath: string | null) {
|
||||
const [schemaTypes, tsTypes] = await Promise.all([
|
||||
this.generateSchemaFile(schema),
|
||||
typeFilePath ? this.generateTypesFile(schema, typeFilePath) : '',
|
||||
])
|
||||
return { schemaTypes, tsTypes }
|
||||
}
|
||||
|
||||
sortSchema(schema: NexusGraphQLSchema) {
|
||||
|
|
@ -75,26 +57,31 @@ export class TypegenMetadata {
|
|||
}
|
||||
|
||||
async writeFile(type: 'schema' | 'types', output: string, filePath: string) {
|
||||
if (typeof filePath !== 'string' || !nodeImports().path.isAbsolute(filePath)) {
|
||||
if (typeof filePath !== 'string' || !path.isAbsolute(filePath)) {
|
||||
return Promise.reject(
|
||||
new Error(`Expected an absolute path to output the Nexus ${type}, saw ${filePath}`)
|
||||
)
|
||||
}
|
||||
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(() => ''),
|
||||
])
|
||||
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(() => '')])
|
||||
if (toSave !== existing) {
|
||||
const dirPath = nodeImports().path.dirname(filePath)
|
||||
const dirPath = path.dirname(filePath)
|
||||
try {
|
||||
await fs.promises.mkdir(dirPath, { recursive: true })
|
||||
await mkdir(dirPath, { recursive: true })
|
||||
} catch (e) {
|
||||
if (e.code !== 'EEXIST') {
|
||||
throw e
|
||||
|
|
@ -104,14 +91,14 @@ export class TypegenMetadata {
|
|||
// apparently. See issue motivating this logic here:
|
||||
// https://github.com/graphql-nexus/schema/issues/247.
|
||||
try {
|
||||
await fs.promises.unlink(filePath)
|
||||
await removeFile(filePath)
|
||||
} catch (e) {
|
||||
/* istanbul ignore next */
|
||||
if (e.code !== 'ENOENT' && e.code !== 'ENOTDIR') {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
return fs.promises.writeFile(filePath, toSave)
|
||||
return writeFile(filePath, toSave)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -119,7 +106,7 @@ export class TypegenMetadata {
|
|||
generateSchemaFile(schema: GraphQLSchema): string {
|
||||
let printedSchema = this.config.customPrintSchemaFn
|
||||
? this.config.customPrintSchemaFn(schema)
|
||||
: printSchemaWithDirectives(schema)
|
||||
: printSchema(schema)
|
||||
return [SDL_HEADER, printedSchema].join('\n\n')
|
||||
}
|
||||
|
||||
|
|
@ -128,34 +115,11 @@ 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(
|
||||
|
|
@ -166,7 +130,7 @@ export class TypegenMetadata {
|
|||
if (this.config.sourceTypes) {
|
||||
return typegenAutoConfig(this.config.sourceTypes, this.config.contextType)(
|
||||
schema,
|
||||
typegenPath || this.config.outputs.typegen?.outputPath || ''
|
||||
typegenPath || this.config.outputs.typegen || ''
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,17 +18,13 @@ 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,
|
||||
|
|
@ -38,7 +34,6 @@ import {
|
|||
mapObj,
|
||||
mapValues,
|
||||
PrintedGenTypingImport,
|
||||
relativePathTo,
|
||||
resolveImportPath,
|
||||
} from './utils'
|
||||
|
||||
|
|
@ -57,26 +52,27 @@ 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 {
|
||||
private groupedTypes: GroupedTypes
|
||||
private printImports: Record<string, Record<string, boolean | string>>
|
||||
private hasDiscriminatedTypes: boolean
|
||||
groupedTypes: GroupedTypes
|
||||
printImports: Record<string, Record<string, boolean | string>>
|
||||
hasDiscriminatedTypes: boolean
|
||||
|
||||
constructor(protected schema: NexusGraphQLSchema, protected typegenInfo: TypegenInfoWithFile) {
|
||||
this.groupedTypes = groupTypes(schema)
|
||||
|
|
@ -85,33 +81,7 @@ export class TypegenPrinter {
|
|||
}
|
||||
|
||||
print() {
|
||||
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 [
|
||||
const body = [
|
||||
this.printInputTypeMap(),
|
||||
this.printEnumTypeMap(),
|
||||
this.printScalarTypeMap(),
|
||||
|
|
@ -131,98 +101,35 @@ 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')
|
||||
}
|
||||
|
||||
private printHeaders() {
|
||||
return [this.printHeadersCommon(), this.printHeadersGlobal()].join('\n')
|
||||
}
|
||||
|
||||
private printHeadersCommon() {
|
||||
printHeaders() {
|
||||
const fieldDefs = [
|
||||
this.printDynamicInputFieldDefinitions(),
|
||||
this.printDynamicOutputFieldDefinitions(),
|
||||
this.printDynamicOutputPropertyDefinitions(),
|
||||
]
|
||||
return [
|
||||
this.typegenInfo.headers.join('\n'),
|
||||
this.typegenInfo.imports.join('\n'),
|
||||
this.printDynamicImport(),
|
||||
...fieldDefs,
|
||||
GLOBAL_DECLARATION,
|
||||
].join('\n')
|
||||
}
|
||||
|
||||
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() {
|
||||
printGenTypeMap() {
|
||||
return [`export interface NexusGenTypes {`]
|
||||
.concat([
|
||||
` context: ${this.printContext()};`,
|
||||
` inputTypes: NexusGenInputs;`,
|
||||
` directives: NexusGenDirectives;`,
|
||||
` directiveArgs: NexusGenDirectiveArgs;`,
|
||||
` rootTypes: NexusGenRootTypes;`,
|
||||
` inputTypeShapes: NexusGenInputs & NexusGenEnums & NexusGenScalars;`,
|
||||
` argTypes: NexusGenArgTypes;`,
|
||||
|
|
@ -249,8 +156,11 @@ export class TypegenPrinter {
|
|||
.join('\n')
|
||||
}
|
||||
|
||||
private printDynamicImport(forGlobal = false) {
|
||||
const { sourceTypings } = this.schema.extensions.nexus.config
|
||||
printDynamicImport() {
|
||||
const {
|
||||
rootTypings,
|
||||
dynamicFields: { dynamicInputFields, dynamicOutputFields },
|
||||
} = this.schema.extensions.nexus.config
|
||||
const { contextTypeImport } = this.typegenInfo
|
||||
const imports: string[] = []
|
||||
const importMap: Record<string, Set<string>> = {}
|
||||
|
|
@ -258,33 +168,38 @@ export class TypegenPrinter {
|
|||
const nexusSchemaImportId = this.typegenInfo.nexusSchemaImportId ?? getOwnPackage().name
|
||||
|
||||
if (!this.printImports[nexusSchemaImportId]) {
|
||||
this.maybeAddCoreImport(forGlobal)
|
||||
if (
|
||||
[dynamicInputFields, dynamicOutputFields].some((o) => Object.keys(o).length > 0) ||
|
||||
this.hasDiscriminatedTypes === true
|
||||
) {
|
||||
this.printImports[nexusSchemaImportId] = {
|
||||
core: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!forGlobal) {
|
||||
if (contextTypeImport) {
|
||||
const importPath = resolveImportPath(contextTypeImport, 'context', outputPath)
|
||||
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)
|
||||
importMap[importPath] = importMap[importPath] || new Set()
|
||||
importMap[importPath].add(
|
||||
contextTypeImport.alias
|
||||
? `${contextTypeImport.export} as ${contextTypeImport.alias}`
|
||||
: contextTypeImport.export
|
||||
rootType.alias ? `${rootType.export} as ${rootType.alias}` : rootType.export
|
||||
)
|
||||
}
|
||||
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(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 = []
|
||||
|
|
@ -303,29 +218,7 @@ export class TypegenPrinter {
|
|||
return imports.join('\n')
|
||||
}
|
||||
|
||||
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() {
|
||||
printDynamicInputFieldDefinitions() {
|
||||
const { dynamicInputFields } = this.schema.extensions.nexus.config.dynamicFields
|
||||
// If there is nothing custom... exit
|
||||
if (!Object.keys(dynamicInputFields).length) {
|
||||
|
|
@ -353,7 +246,7 @@ export class TypegenPrinter {
|
|||
.join('\n')
|
||||
}
|
||||
|
||||
private printDynamicOutputFieldDefinitions() {
|
||||
printDynamicOutputFieldDefinitions() {
|
||||
const { dynamicOutputFields } = this.schema.extensions.nexus.config.dynamicFields
|
||||
// If there is nothing custom... exit
|
||||
if (!Object.keys(dynamicOutputFields).length) {
|
||||
|
|
@ -381,7 +274,7 @@ export class TypegenPrinter {
|
|||
.join('\n')
|
||||
}
|
||||
|
||||
private prependDoc(typeDef: string, typeDescription?: string | null) {
|
||||
prependDoc(typeDef: string, typeDescription?: string | null) {
|
||||
let outStr = ''
|
||||
if (typeDescription) {
|
||||
let parts = typeDescription.split('\n').map((f) => f.trimLeft())
|
||||
|
|
@ -396,7 +289,7 @@ export class TypegenPrinter {
|
|||
return `${outStr}${typeDef}`
|
||||
}
|
||||
|
||||
private printDynamicOutputPropertyDefinitions() {
|
||||
printDynamicOutputPropertyDefinitions() {
|
||||
const { dynamicOutputProperties } = this.schema.extensions.nexus.config.dynamicFields
|
||||
// If there is nothing custom... exit
|
||||
if (!Object.keys(dynamicOutputProperties).length) {
|
||||
|
|
@ -415,9 +308,9 @@ export class TypegenPrinter {
|
|||
.join('\n')
|
||||
}
|
||||
|
||||
private printInheritedFieldMap() {
|
||||
printInheritedFieldMap() {
|
||||
const hasInterfaces: (
|
||||
| (GraphQLInterfaceType & { getInterfaces(): ReadonlyArray<GraphQLInterfaceType> })
|
||||
| (GraphQLInterfaceType & { getInterfaces(): GraphQLInterfaceType[] })
|
||||
| GraphQLObjectType
|
||||
)[] = []
|
||||
const withInterfaces = hasInterfaces
|
||||
|
|
@ -440,15 +333,37 @@ export class TypegenPrinter {
|
|||
.join('\n')
|
||||
}
|
||||
|
||||
private printContext() {
|
||||
printContext() {
|
||||
return this.typegenInfo.contextTypeImport?.alias || this.typegenInfo.contextTypeImport?.export || 'any'
|
||||
}
|
||||
|
||||
private printAbstractTypeMembers() {
|
||||
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() {
|
||||
return this.printTypeInterface('NexusGenAbstractTypeMembers', this.buildAbstractTypeMembers())
|
||||
}
|
||||
|
||||
private buildAbstractTypeMembers() {
|
||||
buildAbstractTypeMembers() {
|
||||
const sourceMap: TypeMapping = {}
|
||||
const abstractTypes: (GraphQLInterfaceType | GraphQLUnionType)[] = []
|
||||
abstractTypes
|
||||
|
|
@ -470,13 +385,13 @@ export class TypegenPrinter {
|
|||
return sourceMap
|
||||
}
|
||||
|
||||
private printTypeNames(name: keyof GroupedTypes, exportName: string, source: string) {
|
||||
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};`
|
||||
}
|
||||
|
||||
private printIsTypeOfObjectTypeNames(exportName: string) {
|
||||
printIsTypeOfObjectTypeNames(exportName: string) {
|
||||
const objectTypes = this.groupedTypes.object.filter((o) => o.isTypeOf !== undefined)
|
||||
const typeDef =
|
||||
objectTypes.length === 0
|
||||
|
|
@ -488,7 +403,7 @@ export class TypegenPrinter {
|
|||
return `export type ${exportName} = ${typeDef};`
|
||||
}
|
||||
|
||||
private printResolveTypeAbstractTypes(exportName: string) {
|
||||
printResolveTypeAbstractTypes(exportName: string) {
|
||||
const abstractTypes = [...this.groupedTypes.interface, ...this.groupedTypes.union].filter(
|
||||
(o) => o.resolveType !== undefined
|
||||
)
|
||||
|
|
@ -503,7 +418,7 @@ export class TypegenPrinter {
|
|||
return `export type ${exportName} = ${typeDef};`
|
||||
}
|
||||
|
||||
private printFeaturesConfig(exportName: string) {
|
||||
printFeaturesConfig(exportName: string) {
|
||||
const abstractTypes = this.schema.extensions.nexus.config.features?.abstractTypeStrategies ?? {}
|
||||
const unionProps = renderObject(mapValues(abstractTypes, (val) => val ?? false))
|
||||
|
||||
|
|
@ -513,7 +428,7 @@ export class TypegenPrinter {
|
|||
.join('\n')
|
||||
}
|
||||
|
||||
private buildEnumTypeMap() {
|
||||
buildEnumTypeMap() {
|
||||
const enumMap: TypeMapping = {}
|
||||
this.groupedTypes.enum.forEach((e) => {
|
||||
const sourceType = this.resolveSourceType(e.name)
|
||||
|
|
@ -527,7 +442,7 @@ export class TypegenPrinter {
|
|||
return enumMap
|
||||
}
|
||||
|
||||
private buildInputTypeMap() {
|
||||
buildInputTypeMap() {
|
||||
const inputObjMap: TypeFieldMapping = {}
|
||||
this.groupedTypes.input.forEach((input) => {
|
||||
eachObj(input.getFields(), (field) => {
|
||||
|
|
@ -538,7 +453,7 @@ export class TypegenPrinter {
|
|||
return inputObjMap
|
||||
}
|
||||
|
||||
private buildScalarTypeMap() {
|
||||
buildScalarTypeMap() {
|
||||
const scalarMap: TypeMapping = {}
|
||||
this.groupedTypes.scalar.forEach((e) => {
|
||||
if (isSpecifiedScalarType(e)) {
|
||||
|
|
@ -555,37 +470,19 @@ export class TypegenPrinter {
|
|||
return scalarMap
|
||||
}
|
||||
|
||||
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')
|
||||
printInputTypeMap() {
|
||||
return this.printTypeFieldInterface('NexusGenInputs', this.buildInputTypeMap(), 'input type')
|
||||
}
|
||||
|
||||
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)
|
||||
printEnumTypeMap() {
|
||||
return this.printTypeInterface('NexusGenEnums', this.buildEnumTypeMap())
|
||||
}
|
||||
|
||||
private printScalarTypeMap() {
|
||||
printScalarTypeMap() {
|
||||
return this.printTypeInterface('NexusGenScalars', this.buildScalarTypeMap())
|
||||
}
|
||||
|
||||
private shouldDiscriminateType(
|
||||
shouldDiscriminateType(
|
||||
abstractType: GraphQLAbstractType,
|
||||
objectType: GraphQLObjectType
|
||||
): 'required' | 'optional' | false {
|
||||
|
|
@ -604,7 +501,7 @@ export class TypegenPrinter {
|
|||
return 'required'
|
||||
}
|
||||
|
||||
private maybeDiscriminate(abstractType: GraphQLAbstractType, objectType: GraphQLObjectType) {
|
||||
maybeDiscriminate(abstractType: GraphQLAbstractType, objectType: GraphQLObjectType) {
|
||||
const requiredOrOptional = this.shouldDiscriminateType(abstractType, objectType)
|
||||
|
||||
if (requiredOrOptional === false) {
|
||||
|
|
@ -616,7 +513,7 @@ export class TypegenPrinter {
|
|||
return `core.Discriminate<'${objectType.name}', '${requiredOrOptional}'>`
|
||||
}
|
||||
|
||||
private buildRootTypeMap(hasFields: Array<GraphQLInterfaceType | GraphQLObjectType | GraphQLUnionType>) {
|
||||
buildRootTypeMap(hasFields: Array<GraphQLInterfaceType | GraphQLObjectType | GraphQLUnionType>) {
|
||||
const rootTypeMap: RootTypeMapping = {}
|
||||
hasFields.forEach((type) => {
|
||||
const rootTyping = this.resolveSourceType(type.name)
|
||||
|
|
@ -641,17 +538,8 @@ export class TypegenPrinter {
|
|||
} else {
|
||||
eachObj(type.getFields(), (field) => {
|
||||
const obj = (rootTypeMap[type.name] = rootTypeMap[type.name] || {})
|
||||
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)) {
|
||||
if (!this.hasResolver(field, type)) {
|
||||
if (typeof obj !== 'string') {
|
||||
obj[field.name] = [
|
||||
this.argSeparator(field.type as GraphQLInputType, false),
|
||||
this.printOutputType(field.type),
|
||||
|
|
@ -664,55 +552,44 @@ export class TypegenPrinter {
|
|||
return rootTypeMap
|
||||
}
|
||||
|
||||
private resolveSourceType(typeName: string): string | undefined {
|
||||
const rootTyping = this.schema.extensions.nexus.config.sourceTypings[typeName]
|
||||
resolveSourceType(typeName: string): string | undefined {
|
||||
const rootTyping = this.schema.extensions.nexus.config.rootTypings[typeName]
|
||||
if (rootTyping) {
|
||||
return typeof rootTyping === 'string' ? rootTyping : rootTyping.export
|
||||
}
|
||||
return (this.typegenInfo.sourceTypeMap as any)[typeName]
|
||||
}
|
||||
|
||||
private fieldSourceType(
|
||||
hasResolver(
|
||||
field: GraphQLField<any, any>,
|
||||
// Used in test mocking
|
||||
_type: GraphQLObjectType
|
||||
) {
|
||||
if (field.extensions && isNexusFieldExtension(field.extensions.nexus)) {
|
||||
return field.extensions.nexus.sourceType
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
private hasResolver(
|
||||
field: GraphQLField<any, any>,
|
||||
// Used in test mocking
|
||||
_type: GraphQLObjectType
|
||||
) {
|
||||
if (field.extensions && hasNexusExtension(field.extensions.nexus)) {
|
||||
if (field.extensions && field.extensions.nexus) {
|
||||
return field.extensions.nexus.hasDefinedResolver
|
||||
}
|
||||
return Boolean(field.resolve)
|
||||
}
|
||||
|
||||
private printObjectTypeMap() {
|
||||
printObjectTypeMap() {
|
||||
return this.printRootTypeFieldInterface(
|
||||
'NexusGenObjects',
|
||||
this.buildRootTypeMap(this.groupedTypes.object)
|
||||
)
|
||||
}
|
||||
|
||||
private printInterfaceTypeMap() {
|
||||
printInterfaceTypeMap() {
|
||||
return this.printRootTypeFieldInterface(
|
||||
'NexusGenInterfaces',
|
||||
this.buildRootTypeMap(this.groupedTypes.interface)
|
||||
)
|
||||
}
|
||||
|
||||
private printUnionTypeMap() {
|
||||
printUnionTypeMap() {
|
||||
return this.printRootTypeFieldInterface('NexusGenUnions', this.buildRootTypeMap(this.groupedTypes.union))
|
||||
}
|
||||
|
||||
private printRootTypeDef() {
|
||||
printRootTypeDef() {
|
||||
const toJoin: string[] = []
|
||||
if (this.groupedTypes.interface.length) {
|
||||
toJoin.push('NexusGenInterfaces')
|
||||
|
|
@ -726,7 +603,7 @@ export class TypegenPrinter {
|
|||
return `export type NexusGenRootTypes = ${toJoin.join(' & ')}`
|
||||
}
|
||||
|
||||
private printAllTypesMap() {
|
||||
printAllTypesMap() {
|
||||
const toJoin: string[] = ['NexusGenRootTypes']
|
||||
if (this.groupedTypes.scalar.length) {
|
||||
toJoin.push('NexusGenScalars')
|
||||
|
|
@ -737,7 +614,7 @@ export class TypegenPrinter {
|
|||
return `export type NexusGenAllTypes = ${toJoin.join(' & ')}`
|
||||
}
|
||||
|
||||
private buildArgTypeMap() {
|
||||
buildArgTypeMap() {
|
||||
const argTypeMap: Record<string, TypeFieldMapping> = {}
|
||||
const hasFields: (GraphQLInterfaceType | GraphQLObjectType)[] = []
|
||||
hasFields
|
||||
|
|
@ -757,38 +634,11 @@ export class TypegenPrinter {
|
|||
return argTypeMap
|
||||
}
|
||||
|
||||
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)
|
||||
printArgTypeMap() {
|
||||
return this.printArgTypeFieldInterface(this.buildArgTypeMap())
|
||||
}
|
||||
|
||||
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() {
|
||||
buildReturnTypeMap() {
|
||||
const returnTypeMap: TypeFieldMapping = {}
|
||||
const hasFields: (GraphQLInterfaceType | GraphQLObjectType)[] = []
|
||||
hasFields
|
||||
|
|
@ -803,7 +653,7 @@ export class TypegenPrinter {
|
|||
return returnTypeMap
|
||||
}
|
||||
|
||||
private buildReturnTypeNamesMap() {
|
||||
buildReturnTypeNamesMap() {
|
||||
const returnTypeMap: TypeFieldMapping = {}
|
||||
const hasFields: (GraphQLInterfaceType | GraphQLObjectType)[] = []
|
||||
hasFields
|
||||
|
|
@ -818,26 +668,26 @@ export class TypegenPrinter {
|
|||
return returnTypeMap
|
||||
}
|
||||
|
||||
private printOutputType(type: GraphQLOutputType) {
|
||||
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 `ReadonlyArray<${toPrint}>`
|
||||
return toPrint.indexOf('null') === -1 ? `${toPrint}[]` : `Array<${toPrint}>`
|
||||
}
|
||||
return item[0]
|
||||
}
|
||||
if (Array.isArray(item[1])) {
|
||||
const toPrint = combine(item[1])
|
||||
return `ReadonlyArray<${toPrint}> | null`
|
||||
return toPrint.indexOf('null') === -1 ? `${toPrint}[] | null` : `Array<${toPrint}> | null`
|
||||
}
|
||||
return `${item[1]} | null`
|
||||
}
|
||||
return `${combine(returnType)}; // ${type}`
|
||||
}
|
||||
|
||||
private typeToArr(type: GraphQLOutputType): any[] {
|
||||
typeToArr(type: GraphQLOutputType): any[] {
|
||||
const typing = []
|
||||
if (isNonNullType(type)) {
|
||||
type = type.ofType
|
||||
|
|
@ -849,22 +699,18 @@ export class TypegenPrinter {
|
|||
} else if (isScalarType(type)) {
|
||||
typing.push(this.printScalar(type))
|
||||
} else if (isEnumType(type)) {
|
||||
if (this.typegenInfo.declareInputs) {
|
||||
typing.push(type.name)
|
||||
} else {
|
||||
typing.push(`NexusGenEnums['${type.name}']`)
|
||||
}
|
||||
typing.push(`NexusGenEnums['${type.name}']`)
|
||||
} else if (isObjectType(type) || isInterfaceType(type) || isUnionType(type)) {
|
||||
typing.push(`NexusGenRootTypes['${type.name}']`)
|
||||
}
|
||||
return typing
|
||||
}
|
||||
|
||||
private printFieldTypesMap() {
|
||||
printFieldTypesMap() {
|
||||
return this.printTypeFieldInterface('NexusGenFieldTypes', this.buildReturnTypeMap(), 'field return type')
|
||||
}
|
||||
|
||||
private printFieldTypeNamesMap() {
|
||||
printFieldTypeNamesMap() {
|
||||
return this.printTypeFieldInterface(
|
||||
'NexusGenFieldTypeNames',
|
||||
this.buildReturnTypeNamesMap(),
|
||||
|
|
@ -872,11 +718,11 @@ export class TypegenPrinter {
|
|||
)
|
||||
}
|
||||
|
||||
private normalizeArg(arg: GraphQLInputField | GraphQLArgument): [string, string] {
|
||||
normalizeArg(arg: GraphQLInputField | GraphQLArgument): [string, string] {
|
||||
return [this.argSeparator(arg.type, Boolean(arg.defaultValue)), this.argTypeRepresentation(arg.type)]
|
||||
}
|
||||
|
||||
private argSeparator(type: GraphQLInputType, hasDefaultValue: boolean) {
|
||||
argSeparator(type: GraphQLInputType, hasDefaultValue: boolean) {
|
||||
if (hasDefaultValue || isNonNullType(type)) {
|
||||
return ':'
|
||||
}
|
||||
|
|
@ -884,25 +730,18 @@ export class TypegenPrinter {
|
|||
return '?:'
|
||||
}
|
||||
|
||||
private argTypeRepresentation(arg: GraphQLInputType): string {
|
||||
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`
|
||||
|
|
@ -910,7 +749,7 @@ export class TypegenPrinter {
|
|||
return `${combine(argType)}; // ${arg}`
|
||||
}
|
||||
|
||||
private argTypeArr(arg: GraphQLInputType): any[] {
|
||||
argTypeArr(arg: GraphQLInputType): any[] {
|
||||
const typing = []
|
||||
if (isNonNullType(arg)) {
|
||||
arg = arg.ofType
|
||||
|
|
@ -922,29 +761,21 @@ export class TypegenPrinter {
|
|||
} else if (isScalarType(arg)) {
|
||||
typing.push(this.printScalar(arg))
|
||||
} else if (isEnumType(arg)) {
|
||||
if (this.typegenInfo.declareInputs) {
|
||||
typing.push(arg.name)
|
||||
} else {
|
||||
typing.push(`NexusGenEnums['${arg.name}']`)
|
||||
}
|
||||
typing.push(`NexusGenEnums['${arg.name}']`)
|
||||
} else if (isInputObjectType(arg)) {
|
||||
if (this.typegenInfo.declareInputs) {
|
||||
typing.push(arg.name)
|
||||
} else {
|
||||
typing.push(`NexusGenInputs['${arg.name}']`)
|
||||
}
|
||||
typing.push(`NexusGenInputs['${arg.name}']`)
|
||||
}
|
||||
return typing
|
||||
}
|
||||
|
||||
private printTypeInterface(interfaceName: string, typeMapping: TypeMapping) {
|
||||
printTypeInterface(interfaceName: string, typeMapping: TypeMapping) {
|
||||
return [`export interface ${interfaceName} {`]
|
||||
.concat(mapObj(typeMapping, (val, key) => ` ${key}: ${val}`))
|
||||
.concat('}')
|
||||
.join('\n')
|
||||
}
|
||||
|
||||
private printRootTypeFieldInterface(interfaceName: string, typeMapping: RootTypeMapping) {
|
||||
printRootTypeFieldInterface(interfaceName: string, typeMapping: RootTypeMapping) {
|
||||
return [`export interface ${interfaceName} {`]
|
||||
.concat(
|
||||
mapObj(typeMapping, (val, key) => {
|
||||
|
|
@ -961,26 +792,18 @@ export class TypegenPrinter {
|
|||
.join('\n')
|
||||
}
|
||||
|
||||
private printTypeFieldInterface(interfaceName: string, typeMapping: TypeFieldMapping, source: string) {
|
||||
printTypeFieldInterface(interfaceName: string, typeMapping: TypeFieldMapping, source: string) {
|
||||
return [`export interface ${interfaceName} {`]
|
||||
.concat(mapObj(typeMapping, this.printObj(' ', source)))
|
||||
.concat('}')
|
||||
.join('\n')
|
||||
}
|
||||
|
||||
private printArgTypeFieldInterface(typeMapping: Record<string, TypeFieldMapping>) {
|
||||
printArgTypeFieldInterface(typeMapping: Record<string, TypeFieldMapping>) {
|
||||
return [`export interface NexusGenArgTypes {`]
|
||||
.concat(
|
||||
mapObj(typeMapping, (val, typeName) => {
|
||||
if (this.typegenInfo.declareInputs) {
|
||||
return [` ${typeName}: {`]
|
||||
.concat(
|
||||
mapObj(val, (_, fieldName) => ` ${fieldName}: ${this.getArgsName(typeName, fieldName)}`)
|
||||
)
|
||||
.concat(' }')
|
||||
.join('\n')
|
||||
}
|
||||
return [` ${typeName}: {`]
|
||||
mapObj(typeMapping, (val, key) => {
|
||||
return [` ${key}: {`]
|
||||
.concat(mapObj(val, this.printObj(' ', 'args')))
|
||||
.concat(' }')
|
||||
.join('\n')
|
||||
|
|
@ -990,26 +813,25 @@ export class TypegenPrinter {
|
|||
.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')
|
||||
}
|
||||
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 printScalar(type: GraphQLScalarType) {
|
||||
printScalar(type: GraphQLScalarType) {
|
||||
if (isSpecifiedScalarType(type)) {
|
||||
return this.resolveSourceType(type.name) ?? SpecifiedScalars[type.name as SpecifiedScalarNames]
|
||||
}
|
||||
return `NexusGenScalars['${type.name}']`
|
||||
}
|
||||
|
||||
private printPlugins() {
|
||||
printPlugins() {
|
||||
const pluginFieldExt: string[] = [
|
||||
` interface NexusGenPluginFieldConfig<TypeName extends string, FieldName extends string> {`,
|
||||
]
|
||||
|
|
@ -1058,7 +880,7 @@ export class TypegenPrinter {
|
|||
].join('\n')
|
||||
}
|
||||
|
||||
private printType(strLike: StringLike | StringLike[]): string {
|
||||
printType(strLike: StringLike | StringLike[]): string {
|
||||
if (Array.isArray(strLike)) {
|
||||
return strLike.map((s) => this.printType(s)).join('\n')
|
||||
}
|
||||
|
|
@ -1075,7 +897,7 @@ export class TypegenPrinter {
|
|||
return strLike
|
||||
}
|
||||
|
||||
private addImport(i: PrintedGenTypingImport) {
|
||||
addImport(i: PrintedGenTypingImport) {
|
||||
/* istanbul ignore if */
|
||||
if (!isNexusPrintedGenTypingImport(i)) {
|
||||
console.warn(`Expected printedGenTypingImport, saw ${i}`)
|
||||
|
|
|
|||
|
|
@ -100,20 +100,20 @@ export type FieldResolver<TypeName extends string, FieldName extends string> = (
|
|||
source: SourceValue<TypeName>,
|
||||
/**
|
||||
* 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*
|
||||
* 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.
|
||||
* will always be type safe.
|
||||
*/
|
||||
args: ArgsValue<TypeName, FieldName>,
|
||||
/**
|
||||
* 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
|
||||
* 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.
|
||||
|
|
@ -155,8 +155,6 @@ export type GenTypesShapeKeys =
|
|||
| 'inputTypes'
|
||||
| 'rootTypes'
|
||||
| 'inputTypeShapes'
|
||||
| 'directives'
|
||||
| 'directiveArgs'
|
||||
| 'argTypes'
|
||||
| 'fieldTypes'
|
||||
| 'fieldTypeNames'
|
||||
|
|
@ -181,7 +179,7 @@ export type GenTypesShapeKeys =
|
|||
export type GenTypesShape = Record<GenTypesShapeKeys, any>
|
||||
|
||||
export type GetGen<K extends GenTypesShapeKeys, Fallback = any> = NexusGen extends infer GenTypes
|
||||
? K extends keyof GenTypes
|
||||
? GenTypes extends GenTypesShape
|
||||
? GenTypes[K]
|
||||
: Fallback
|
||||
: Fallback
|
||||
|
|
@ -204,8 +202,10 @@ export type GetGen3<
|
|||
: Fallback
|
||||
|
||||
export type HasGen<K extends GenTypesShapeKeys> = NexusGen extends infer GenTypes
|
||||
? K extends keyof GenTypes
|
||||
? true
|
||||
? GenTypes extends GenTypesShape
|
||||
? K extends keyof GenTypes
|
||||
? true
|
||||
: false
|
||||
: false
|
||||
: false
|
||||
|
||||
|
|
@ -213,9 +213,11 @@ export type HasGen2<
|
|||
K extends GenTypesShapeKeys,
|
||||
K2 extends Extract<keyof GenTypesShape[K], string>
|
||||
> = NexusGen extends infer GenTypes
|
||||
? K extends keyof GenTypes
|
||||
? K2 extends keyof GenTypes[K]
|
||||
? true
|
||||
? GenTypes extends GenTypesShape
|
||||
? K extends keyof GenTypes
|
||||
? K2 extends keyof GenTypes[K]
|
||||
? true
|
||||
: false
|
||||
: false
|
||||
: false
|
||||
: false
|
||||
|
|
@ -225,10 +227,12 @@ export type HasGen3<
|
|||
K2 extends Extract<keyof GenTypesShape[K], string>,
|
||||
K3 extends Extract<keyof GenTypesShape[K][K2], string>
|
||||
> = NexusGen extends infer GenTypes
|
||||
? K extends keyof GenTypes
|
||||
? K2 extends keyof GenTypes[K]
|
||||
? K3 extends keyof GenTypes[K][K2]
|
||||
? true
|
||||
? GenTypes extends GenTypesShape
|
||||
? K extends keyof GenTypes
|
||||
? K2 extends keyof GenTypes[K]
|
||||
? K3 extends keyof GenTypes[K][K2]
|
||||
? true
|
||||
: false
|
||||
: false
|
||||
: false
|
||||
: false
|
||||
|
|
|
|||
|
|
@ -1,75 +1,51 @@
|
|||
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 = defaultShouldGenerateArtifacts(), ...rest } = config
|
||||
const {
|
||||
outputs,
|
||||
shouldGenerateArtifacts = Boolean(!process.env.NODE_ENV || process.env.NODE_ENV !== 'production'),
|
||||
...rest
|
||||
} = config
|
||||
|
||||
function getOutputPaths() {
|
||||
const defaultSDLFilePath = nodeImports().path.join(process.cwd(), 'schema.graphql')
|
||||
const defaultSDLFilePath = path.join(process.cwd(), 'schema.graphql')
|
||||
|
||||
let typegenFilePath: ConfiguredTypegen | null = null
|
||||
let sdlFilePath: string | null = null
|
||||
let typegenFilePath: string | null = null
|
||||
let sdlFilePath: string | null = null
|
||||
|
||||
if (outputs === undefined) {
|
||||
if (isProductionStage()) {
|
||||
sdlFilePath = defaultSDLFilePath
|
||||
}
|
||||
} else if (outputs === true) {
|
||||
if (outputs === undefined) {
|
||||
if (isProductionStage()) {
|
||||
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.`
|
||||
)
|
||||
}
|
||||
return {
|
||||
typegenFilePath,
|
||||
sdlFilePath,
|
||||
} 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 = 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 ? getOutputPaths().typegenFilePath : null,
|
||||
schema: shouldGenerateArtifacts ? getOutputPaths().sdlFilePath : null,
|
||||
typegen: shouldGenerateArtifacts ? typegenFilePath : null,
|
||||
schema: shouldGenerateArtifacts ? sdlFilePath : null,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function defaultShouldGenerateArtifacts() {
|
||||
return Boolean(
|
||||
typeof process === 'object' &&
|
||||
typeof process.cwd === 'function' &&
|
||||
(!process.env.NODE_ENV || process.env.NODE_ENV !== 'production')
|
||||
)
|
||||
}
|
||||
|
|
|
|||
87
src/utils.ts
87
src/utils.ts
|
|
@ -1,3 +1,4 @@
|
|||
import * as fs from 'fs'
|
||||
import {
|
||||
GraphQLEnumType,
|
||||
GraphQLInputObjectType,
|
||||
|
|
@ -21,18 +22,17 @@ import {
|
|||
isWrappingType,
|
||||
specifiedScalarTypes,
|
||||
} from 'graphql'
|
||||
import * as Path from 'path'
|
||||
import { decorateType } from './definitions/decorateType'
|
||||
import { isNexusMetaType, NexusMetaType, resolveNexusMetaType } from './definitions/nexusMeta'
|
||||
import {
|
||||
AllNexusArgsDefs,
|
||||
AllNexusNamedTypeDefs,
|
||||
AllNexusTypeDefs,
|
||||
isNexusWrappingType,
|
||||
isNexusArgDef,
|
||||
AllNamedInputTypeDefs,
|
||||
AllNexusNamedInputTypeDefs,
|
||||
} from './definitions/wrapping'
|
||||
import {
|
||||
Maybe,
|
||||
MissingType,
|
||||
NexusFeatures,
|
||||
NexusGraphQLSchema,
|
||||
|
|
@ -40,7 +40,6 @@ 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 +148,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 (!nodeImports().path.isAbsolute(pathName)) {
|
||||
if (!Path.isAbsolute(pathName)) {
|
||||
throw new Error(`Expected path for "${property}" to be an absolute path, saw "${pathName}"`)
|
||||
}
|
||||
return pathName
|
||||
|
|
@ -177,7 +176,7 @@ export function groupTypes(schema: GraphQLSchema) {
|
|||
Object.keys(schemaTypeMap)
|
||||
.sort()
|
||||
.forEach((typeName) => {
|
||||
if (typeName.startsWith('__')) {
|
||||
if (typeName.indexOf('__') === 0) {
|
||||
return
|
||||
}
|
||||
const type = schema.getType(typeName)
|
||||
|
|
@ -220,7 +219,7 @@ export function isPromiseLike(value: any): value is PromiseLike<any> {
|
|||
export const typeScriptFileExtension = /(\.d)?\.ts$/
|
||||
|
||||
function makeRelativePathExplicitlyRelative(path: string) {
|
||||
if (nodeImports().path.isAbsolute(path)) return path
|
||||
if (Path.isAbsolute(path)) return path
|
||||
if (path.startsWith('./')) return path
|
||||
return `./${path}`
|
||||
}
|
||||
|
|
@ -242,7 +241,6 @@ 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))
|
||||
|
|
@ -267,7 +265,7 @@ export interface PrintedGenTypingConfig {
|
|||
name: string
|
||||
optional: boolean
|
||||
type: string
|
||||
description?: Maybe<string>
|
||||
description?: string
|
||||
imports?: PrintedGenTypingImport[]
|
||||
}
|
||||
|
||||
|
|
@ -477,18 +475,20 @@ 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 !nodeImports().path.isAbsolute(path) && /^([A-z0-9@])/.test(path)
|
||||
return !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' ||
|
||||
(!nodeImports().path.isAbsolute(rootTypePath) && !isNodeModule(rootTypePath))
|
||||
) {
|
||||
if (typeof rootTypePath !== 'string' || (!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}"`
|
||||
)
|
||||
|
|
@ -500,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 (!nodeImports().fs.existsSync(rootTypePath)) {
|
||||
} else if (!fs.existsSync(rootTypePath)) {
|
||||
throw new Error(`Root typing path "${rootTypePath}" for the type "${typeName}" does not exist`)
|
||||
}
|
||||
|
||||
|
|
@ -508,7 +508,7 @@ export function resolveImportPath(rootType: TypingImport, typeName: string, outp
|
|||
return rootTypePath
|
||||
}
|
||||
|
||||
if (nodeImports().path.isAbsolute(rootTypePath)) {
|
||||
if (Path.isAbsolute(rootTypePath)) {
|
||||
return relativePathTo(rootTypePath, outputPath)
|
||||
}
|
||||
|
||||
|
|
@ -516,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): AllNamedInputTypeDefs | string {
|
||||
export function getArgNamedType(argDef: AllNexusArgsDefs | string): AllNexusNamedInputTypeDefs | string {
|
||||
let finalValue = argDef
|
||||
if (typeof finalValue === 'string') {
|
||||
return finalValue
|
||||
|
|
@ -534,24 +534,21 @@ export function getArgNamedType(argDef: AllNexusArgsDefs | string): AllNamedInpu
|
|||
}
|
||||
|
||||
export function getNexusNamedType(
|
||||
type: AllNexusTypeDefs | NexusMetaType | GraphQLType | string
|
||||
type: AllNexusTypeDefs | GraphQLType | string
|
||||
): AllNexusNamedTypeDefs | GraphQLNamedType | string {
|
||||
if (typeof type === 'string') {
|
||||
return type
|
||||
}
|
||||
let namedType = type
|
||||
while (isNexusWrappingType(namedType) || isWrappingType(namedType) || isNexusMetaType(namedType)) {
|
||||
while (isNexusWrappingType(namedType) || isWrappingType(namedType)) {
|
||||
if (isNexusWrappingType(namedType)) {
|
||||
namedType = namedType.ofNexusType
|
||||
}
|
||||
if (isWrappingType(namedType)) {
|
||||
namedType = namedType.ofType
|
||||
}
|
||||
if (isNexusMetaType(namedType)) {
|
||||
namedType = resolveNexusMetaType(namedType)
|
||||
}
|
||||
}
|
||||
return namedType as AllNexusNamedTypeDefs | GraphQLNamedType | string
|
||||
return namedType
|
||||
}
|
||||
|
||||
/** Assertion utility with nexus-aware feedback for users. */
|
||||
|
|
@ -596,48 +593,10 @@ export function graphql15InterfaceConfig<T extends GraphQLInterfaceTypeConfig<an
|
|||
}
|
||||
|
||||
export function graphql15InterfaceType<T extends GraphQLInterfaceType>(
|
||||
type: T & { getInterfaces?: () => ReadonlyArray<GraphQLInterfaceType> }
|
||||
): T & { getInterfaces(): ReadonlyArray<GraphQLInterfaceType> } {
|
||||
type: T & { getInterfaces?: () => GraphQLInterfaceType[] }
|
||||
): T & { getInterfaces(): GraphQLInterfaceType[] } {
|
||||
if (typeof type.getInterfaces !== 'function') {
|
||||
type.getInterfaces = () => []
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* A specially typed version of `Array.isArray` to work around [this
|
||||
* issue](https://github.com/microsoft/TypeScript/issues/17002).
|
||||
*/
|
||||
export function isArray<T>(
|
||||
arg: T | {}
|
||||
): arg is T extends readonly any[] ? (unknown extends T ? never : readonly any[]) : any[] {
|
||||
return Array.isArray(arg)
|
||||
}
|
||||
|
||||
export const ownProp = {
|
||||
has<O extends object, K extends keyof O>(obj: O, key: K): boolean {
|
||||
return Boolean(Object.getOwnPropertyDescriptor(obj, key))
|
||||
},
|
||||
set<O extends object, K extends keyof O>(obj: O, key: K, value: O[K]): O[K] {
|
||||
Object.defineProperty(obj, key, { value })
|
||||
return value
|
||||
},
|
||||
get<O extends object, K extends keyof O>(obj: O, key: K): O[K] | undefined {
|
||||
return Object.getOwnPropertyDescriptor(obj, key)?.value
|
||||
},
|
||||
}
|
||||
|
||||
export function result<T>(val: T | (() => T)): T {
|
||||
if (val instanceof Function) {
|
||||
return val()
|
||||
}
|
||||
return val as T
|
||||
return type as T & { getInterfaces(): GraphQLInterfaceType[] }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
/// <reference path="../_setup.ts" />
|
||||
import { join, relative } from 'path'
|
||||
import { core } from '../../src'
|
||||
import type { BuilderConfigInput } from '../../src/core'
|
||||
import { BuilderConfigInput } from '../../src/core'
|
||||
|
||||
const { generateSchema } = core
|
||||
const { generateSchema, typegenFormatPrettier } = core
|
||||
|
||||
type HookSettings = {
|
||||
rootDir: string
|
||||
|
|
@ -29,8 +29,12 @@ export async function generateTypegen(settings: HookSettings) {
|
|||
},
|
||||
shouldGenerateArtifacts: true,
|
||||
plugins: plugins || [],
|
||||
prettierConfig: require.resolve('../../.prettierrc'),
|
||||
formatTypegen: (content) => content.replace('from "nexus"', `from '${importPath}'`),
|
||||
async formatTypegen(source, type) {
|
||||
const prettierConfigPath = require.resolve('../../.prettierrc')
|
||||
const content = await typegenFormatPrettier(prettierConfigPath)(source, type)
|
||||
|
||||
return content.replace("'nexus'", `'${importPath}'`)
|
||||
},
|
||||
features: {
|
||||
abstractTypeStrategies: {
|
||||
resolveType: true,
|
||||
|
|
@ -55,11 +59,11 @@ type Settings = {
|
|||
/**
|
||||
* Test that the given app can be built by TypeScript without any type errors.
|
||||
*
|
||||
* - Nexus generateSchema will be run before TypeScript to ensure typegen is present. - By default looks for an
|
||||
* `__app.ts` entrypoint - All entrypoint exports are expected to be Nexus type definitions - Except the
|
||||
* optional export name "plugins" which is treated as an array of plugins for makeSchema - Outputs a
|
||||
* `__typegen.ts` typegen module - You must import the typegen module into your entrypoint module - If you
|
||||
* provide a `tsconfig.json` file in the root dir it will be used.
|
||||
* - Nexus generateSchema will be run before TypeScript to ensure typegen is present. - By default looks for
|
||||
* an `__app.ts` entrypoint - All entrypoint exports are expected to be Nexus type definitions - Except the
|
||||
* optional export name "plugins" which is treated as an array of plugins for makeSchema - Outputs a
|
||||
* `__typegen.ts` typegen module - You must import the typegen module into your entrypoint module - If you
|
||||
* provide a `tsconfig.json` file in the root dir it will be used.
|
||||
*/
|
||||
export function testApp(settings: Settings & HookSettings) {
|
||||
const name = settings?.name ?? 'app'
|
||||
|
|
|
|||
|
|
@ -90,11 +90,6 @@ export type NexusGenScalarNames = keyof NexusGenScalars;
|
|||
|
||||
export type NexusGenUnionNames = never;
|
||||
|
||||
export type NexusGenDirectives = never
|
||||
|
||||
export interface NexusGenDirectiveArgs {
|
||||
}
|
||||
|
||||
export type NexusGenObjectsUsingAbstractStrategyIsTypeOf = never;
|
||||
|
||||
export type NexusGenAbstractsUsingStrategyResolveType = never;
|
||||
|
|
@ -110,8 +105,6 @@ export type NexusGenFeaturesConfig = {
|
|||
export interface NexusGenTypes {
|
||||
context: any;
|
||||
inputTypes: NexusGenInputs;
|
||||
directives: NexusGenDirectives;
|
||||
directiveArgs: NexusGenDirectiveArgs;
|
||||
rootTypes: NexusGenRootTypes;
|
||||
inputTypeShapes: NexusGenInputs & NexusGenEnums & NexusGenScalars;
|
||||
argTypes: NexusGenArgTypes;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue