From e42836bc8b5d0846bd9dfeb20d10de75284cae45 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Mon, 6 Dec 2021 18:31:53 +0000 Subject: [PATCH 01/25] ops: trigger a ci run From fbef87d2112d7e7bc0f123edda887f3dd55ff6c3 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Mon, 6 Dec 2021 18:33:17 +0000 Subject: [PATCH 02/25] docs: fix doc typo --- src/generator/models/declaration.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/generator/models/declaration.ts b/src/generator/models/declaration.ts index d968f0606..62d1804e2 100644 --- a/src/generator/models/declaration.ts +++ b/src/generator/models/declaration.ts @@ -296,8 +296,8 @@ function renderNexusType(field: DMMF.Field, settings: Gentime.Settings): string /** * Map the fields type to a GraphQL type. * - * @remarks The `settings` param type uses settings data instead of setset instance because this helper - * is used at runtime too where we don't have a Setset instane for gentime. + * @remarks The `settings` param type uses settings data instead of Setset instance because this helper + * is used at runtime too where we don't have a Setset instance for gentime. */ export function fieldTypeToGraphQLType( field: DMMF.Field, From e078ec29ee2bb08d8ea8e45f820782ab0766f0ea Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Mon, 6 Dec 2021 18:50:21 +0000 Subject: [PATCH 03/25] drop support for pre-3.x prisma --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0ed56fbce..829bcf533 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ }, "prettier": "@prisma-labs/prettier-config", "peerDependencies": { - "@prisma/client": "2.29.x || 2.30.x || 3.x", + "@prisma/client": "3.0 | 3.1 | 3.2 | 3.3 | 3.4 | 3.5 | 3.6", "nexus": "^1.0.0", "ts-node": "^10.0.0" }, From fe4c97d757bb7de0c33802d606e067e30d26f52c Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Mon, 6 Dec 2021 19:07:51 +0000 Subject: [PATCH 04/25] refactor --- src/generator/models/declaration.ts | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/generator/models/declaration.ts b/src/generator/models/declaration.ts index 62d1804e2..dc28d1c2f 100644 --- a/src/generator/models/declaration.ts +++ b/src/generator/models/declaration.ts @@ -303,17 +303,22 @@ export function fieldTypeToGraphQLType( field: DMMF.Field, settings: Gentime.SettingsData ): LiteralUnion { + // TODO remove once PC is fixed https://prisma-company.slack.com/archives/C016KUHB1R6/p1638816683155000?thread_ts=1638563060.145800&cid=C016KUHB1R6 + if (typeof field.type !== 'string') { + throw new TypeError(`field.type is supposed to always be a string.`) + } + switch (field.kind) { case 'scalar': { - const typeName = field.type as PrismaScalarType - if (field.isId) { if (field.type === 'String' || (field.type === 'Int' && settings.projectIdIntToGraphQL === 'ID')) { return StandardGraphQLScalarTypes.ID } } - switch (typeName) { + const fieldType = field.type as PrismaScalarType + + switch (fieldType) { case 'String': { return StandardGraphQLScalarTypes.String } @@ -342,24 +347,18 @@ export function fieldTypeToGraphQLType( return 'Decimal' } default: { - return allCasesHandled(typeName) + return allCasesHandled(fieldType) } } } case 'enum': { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- But it does change the expression's type... - const typeName = field.type as string - return typeName + return field.type } case 'object': { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- But it does change the expression's type... - const typeName = field.type as string - return typeName + return field.type } case 'unsupported': { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- But it does change the expression's type... - const typeName = field.type as string - return typeName + return field.type } default: allCasesHandled(field.kind) From 002eb2753919f13d93481ed1475b4fb90644ca2e Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Mon, 6 Dec 2021 19:10:04 +0000 Subject: [PATCH 05/25] pc versions list --- .github/workflows/pr.yml | 2 +- .github/workflows/trunk.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 86a632113..5ca2d5a8b 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -58,7 +58,7 @@ jobs: matrix: os: ['ubuntu-latest'] node-version: [16.x] - prisma-client-version: ['2.29', '2.30'] + prisma-client-version: ['3.0','3.1','3.2','3.3','3.4','3.5'] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/trunk.yml b/.github/workflows/trunk.yml index 19fe2e7a1..f2d1198dd 100644 --- a/.github/workflows/trunk.yml +++ b/.github/workflows/trunk.yml @@ -37,7 +37,7 @@ jobs: matrix: os: ['ubuntu-latest'] node-version: [16.x] - prisma-client-version: ['2.29'] + prisma-client-version: ['3.0','3.1','3.2','3.3','3.4','3.5'] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 From bb2660b7ae4a2e2944d3560ba048df966b3b1e64 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Mon, 6 Dec 2021 19:31:44 +0000 Subject: [PATCH 06/25] drop support for pre-3.5 prisma --- .github/workflows/pr.yml | 2 +- .github/workflows/trunk.yml | 2 +- package.json | 4 ++-- yarn.lock | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 5ca2d5a8b..acb92efbc 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -58,7 +58,7 @@ jobs: matrix: os: ['ubuntu-latest'] node-version: [16.x] - prisma-client-version: ['3.0','3.1','3.2','3.3','3.4','3.5'] + prisma-client-version: ['3.5'] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/trunk.yml b/.github/workflows/trunk.yml index f2d1198dd..8e8230530 100644 --- a/.github/workflows/trunk.yml +++ b/.github/workflows/trunk.yml @@ -37,7 +37,7 @@ jobs: matrix: os: ['ubuntu-latest'] node-version: [16.x] - prisma-client-version: ['3.0','3.1','3.2','3.3','3.4','3.5'] + prisma-client-version: ['3.5'] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 diff --git a/package.json b/package.json index 829bcf533..42976a37d 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "devDependencies": { "@homer0/prettier-plugin-jsdoc": "^4.0.6", "@prisma-labs/prettier-config": "0.1.0", - "@prisma/client": "3.6.0", + "@prisma/client": "^3.6.0", "@prisma/sdk": "^3.6.0", "@types/debug": "^4.1.7", "@types/expand-tilde": "^2.0.0", @@ -111,7 +111,7 @@ }, "prettier": "@prisma-labs/prettier-config", "peerDependencies": { - "@prisma/client": "3.0 | 3.1 | 3.2 | 3.3 | 3.4 | 3.5 | 3.6", + "@prisma/client": "^3.5", "nexus": "^1.0.0", "ts-node": "^10.0.0" }, diff --git a/yarn.lock b/yarn.lock index 26495ff01..223957fc2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -780,7 +780,7 @@ resolved "https://registry.npmjs.org/@prisma-labs/prettier-config/-/prettier-config-0.1.0.tgz" integrity sha512-P0h2y+gnIxFP2HdsTYSYHWmabGBlxyVjnUepsrRe8gAF36mxOonGsbsQmKt/Q9H9CMjrSkFoDe5F5HLi2iW5/Q== -"@prisma/client@3.6.0": +"@prisma/client@^3.6.0": version "3.6.0" resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.6.0.tgz#68a60cd4c73a369b11f72e173e86fd6789939293" integrity sha512-ycSGY9EZGROtje0iCNsgC5Zqi/ttX2sO7BNMYaLsUMiTlf3F69ZPH+08pRo0hrDfkZzyimXYqeXJlaoYDH1w7A== From d80447ef95ab5ad39bb0d1618591054b3e8c450c Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Wed, 8 Dec 2021 18:47:21 +0000 Subject: [PATCH 07/25] refactor: resolver "constraints" --- src/generator/helpers/JSDocTemplates.ts | 2 +- src/generator/helpers/constraints.ts | 83 ------------------ src/generator/models/javascript.ts | 86 +++++++++---------- .../PrismaDocumentation.ts | 0 .../index.ts | 0 src/lib/prisma-utils/index.ts | 1 + src/lib/prisma-utils/index_.ts | 17 ++++ src/lib/prisma-utils/whereUniqueInput.ts | 73 ++++++++++++++++ 8 files changed, 131 insertions(+), 131 deletions(-) delete mode 100644 src/generator/helpers/constraints.ts rename src/lib/{prisma-documnetation => prisma-documentation}/PrismaDocumentation.ts (100%) rename src/lib/{prisma-documnetation => prisma-documentation}/index.ts (100%) create mode 100644 src/lib/prisma-utils/index.ts create mode 100644 src/lib/prisma-utils/index_.ts create mode 100644 src/lib/prisma-utils/whereUniqueInput.ts diff --git a/src/generator/helpers/JSDocTemplates.ts b/src/generator/helpers/JSDocTemplates.ts index 3f8d20ffe..bc0238844 100644 --- a/src/generator/helpers/JSDocTemplates.ts +++ b/src/generator/helpers/JSDocTemplates.ts @@ -1,6 +1,6 @@ import { DMMF } from '@prisma/client/runtime' import dedent from 'dindist' -import { PrismaDocumentation } from '../../lib/prisma-documnetation' +import { PrismaDocumentation } from '../../lib/prisma-documentation' import { Gentime } from '../gentime/settingsSingleton' type JSDoc = string diff --git a/src/generator/helpers/constraints.ts b/src/generator/helpers/constraints.ts deleted file mode 100644 index 54f97f876..000000000 --- a/src/generator/helpers/constraints.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { DMMF } from '@prisma/client/runtime' -import { RecordUnknown } from '../../helpers/utils' - -/** - * Find the unique identifiers necessary to indentify a field. - * - * @remarks Unique fields for a model can be one of (in this order): - * - * 1. Exacrly one field with an `@id` annotation. - * 2. Multiple fields with `@@id` clause. - * 3. Exactly one field with a `@unique` annotation (if multiple, use first). - * 4. Multiple fields with a `@@unique` clause. - */ -export function resolveUniqueIdentifiers(model: DMMF.Model): string[] { - // Try finding 1 - const singleIdField = model.fields.find((f) => f.isId) - - if (singleIdField) { - return [singleIdField.name] - } - - // Try finding 2 - if (model.primaryKey && model.primaryKey.fields.length > 0) { - return model.primaryKey.fields - } - - // Try finding 3 - const singleUniqueField = model.fields.find((f) => f.isUnique) - - if (singleUniqueField) { - return [singleUniqueField.name] - } - - // Try finding 4 - if (model.uniqueFields && model.uniqueFields.length > 0) { - return model.uniqueFields[0] as string[] // I don't know why typescript want a cast here - } - - throw new Error(`Unable to resolve a unique identifier for the Prisma model: ${model.name}`) -} - -export function findMissingUniqueIdentifiers( - data: RecordUnknown, - uniqueIdentifiers: string[] -): string[] | null { - const missingIdentifiers: string[] = [] - - for (const identifier of uniqueIdentifiers) { - if (!data[identifier]) { - missingIdentifiers.push(identifier) - } - } - - if (missingIdentifiers.length > 0) { - return missingIdentifiers - } - - return null -} - -export function buildWhereUniqueInput(data: RecordUnknown, uniqueIdentifiers: string[]): RecordUnknown { - if (uniqueIdentifiers.length === 1) { - return pickFromRecord(data, uniqueIdentifiers) - } - - const compoundName = uniqueIdentifiers.join('_') - - return { - [compoundName]: pickFromRecord(data, uniqueIdentifiers), - } -} - -function pickFromRecord(record: RecordUnknown, keys: string[]) { - const output: Record = {} - - for (const identifier of keys) { - if (record[identifier]) { - output[identifier] = record[identifier] - } - } - - return output -} diff --git a/src/generator/models/javascript.ts b/src/generator/models/javascript.ts index b0985b768..d74b2aaa3 100644 --- a/src/generator/models/javascript.ts +++ b/src/generator/models/javascript.ts @@ -1,17 +1,14 @@ import type { DMMF } from '@prisma/client/runtime' import dedent from 'dindist' -import { chain, lowerFirst } from 'lodash' +import { chain } from 'lodash' import * as Nexus from 'nexus' import { NexusEnumTypeConfig, NexusListDef, NexusNonNullDef, NexusNullDef } from 'nexus/dist/core' import { MaybePromise, RecordUnknown, Resolver } from '../../helpers/utils' import { PrismaDmmf } from '../../lib/prisma-dmmf' -import { PrismaDocumentation } from '../../lib/prisma-documnetation' +import { PrismaDocumentation } from '../../lib/prisma-documentation' +import { PrismaUtils } from '../../lib/prisma-utils' import { Gentime } from '../gentime/settingsSingleton' -import { - buildWhereUniqueInput, - findMissingUniqueIdentifiers, - resolveUniqueIdentifiers, -} from '../helpers/constraints' +import { createWhereUniqueInput } from '../../lib/prisma-utils/whereUniqueInput' import { Runtime } from '../runtime/settingsSingleton' import { ModuleSpec } from '../types' import { fieldTypeToGraphQLType } from './declaration' @@ -178,7 +175,7 @@ function createNexusObjectTypeDefConfigurations( name: field.name, type: prismaFieldToNexusType(field, settings), description: prismaNodeDocumentationToDescription({ settings, node: field }), - resolve: prismaFieldToNexusResolver(model, field, settings), + resolve: nexusResolverFromPrismaField(model, field, settings), } }) .keyBy('name') @@ -212,49 +209,45 @@ export function prismaFieldToNexusType(field: DMMF.Field, settings: Settings) { } } -export function prismaFieldToNexusResolver( +/** + * Create a GraphQL resolver for the given Prisma field. If the Prisma field is a scalar then no resolver is + * returned and instead the Nexus default is relied upon. + * + * @remarks Allow Nexus default resolver to handle resolving scalars. + * + * By using Nexus default we also affect its generated types, assuming there are not explicit + * source types setup which actually for Nexus Prisma projects there usually will be (the Prisma + * model types). Still, using the Nexus default is a bit more idiomatic and provides the better + * _default_ type generation experience of scalars being expected to come down from the source + * type (aka. parent). + * + * So: + * + * ```ts ... + * t.field(M1.Foo.bar) + * ``` + * + * where `bar` is a scalar prisma field would have NO resolve generated and thus default Nexus + * as mentioned would think that `bar` field WILL be present on the source type. This is, again, + * mostly moot since most Nexus Prisma users WILL setup the Prisma source types e.g.: + * + * ```ts ... + * sourceTypes: { modules: [{ module: '.prisma/client', alias: 'PrismaClient' }]}, + * ``` + * + * but this is overall the better way to handle this detail it seems. + */ +export function nexusResolverFromPrismaField( model: DMMF.Model, field: DMMF.Field, settings: Settings ): undefined | Resolver { - /** - * Allow Nexus default resolver to handle resolving scalars. - * - * By using Nexus default we also affect its generated types, assuming there are not explicit source types setup - * which actually for Nexus Prisma projects there usually will be (the Prisma model types). Still, using the Nexus - * default is a bit more idiomatic and provides the better _default_ type generation experience of scalars being - * expected to come down from the source type (aka. parent). - * - * So: - * - * t.field(M1.Foo.bar) - * - * where `bar` is a scalar prisma field would have NO resolve generated and thus default Nexus as mentioned would - * think that `bar` field WILL be present on the source type. This is, again, mostly moot since most Nexus Prisma - * users WILL setup the Prisma source types e.g.: - * - * sourceTypes: { - * modules: [{ module: '.prisma/client', alias: 'PrismaClient' }], - * }, - * - * but this is overall the better way to handle this detail it seems. - */ if (field.kind !== 'object') { return undefined } - return (root: RecordUnknown, _args: RecordUnknown, ctx: RecordUnknown): MaybePromise => { - const uniqueIdentifiers = resolveUniqueIdentifiers(model) - const missingIdentifiers = findMissingUniqueIdentifiers(root, uniqueIdentifiers) - - if (missingIdentifiers !== null) { - // TODO rich errors - throw new Error( - `Resolver ${model.name}.${ - field.name - } is missing the following unique identifiers: ${missingIdentifiers.join(', ')}` - ) - } + return (source: RecordUnknown, _args: RecordUnknown, ctx: RecordUnknown): MaybePromise => { + const whereUnique = createWhereUniqueInput(source, model) // eslint-disable-next-line const PrismaClientPackage = require(settings.gentime.prismaClientImportId) @@ -267,11 +260,10 @@ export function prismaFieldToNexusResolver( ) } - const propertyModelName = lowerFirst(model.name) // eslint-disable-next-line @typescript-eslint/no-explicit-any const prisma: any = ctx[settings.runtime.data.prismaClientContextField] // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access - const prismaModel = prisma[propertyModelName] + const prismaModel = prisma[PrismaUtils.typeScriptOrmModelPropertyNameFromModelName(model.name)] // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access if (typeof prismaModel.findUnique !== 'function') { @@ -283,12 +275,12 @@ export function prismaFieldToNexusResolver( const findUnique = prismaModel.findUnique as (query: unknown) => MaybePromise const result: unknown = findUnique({ - where: buildWhereUniqueInput(root, uniqueIdentifiers), + where: whereUnique, /** * * The user might have configured Prisma Client globally to rejectOnNotFound. * In the context of this Nexus Prisma managed resolver, we don't want that setting to - * be a behavioural factor. Instead, Nexus Prisma has its own documented rules about the logic + * be a behavioral factor. Instead, Nexus Prisma has its own documented rules about the logic * it uses to project nullability from the database to the api. * * More details about this design can be found in the README. diff --git a/src/lib/prisma-documnetation/PrismaDocumentation.ts b/src/lib/prisma-documentation/PrismaDocumentation.ts similarity index 100% rename from src/lib/prisma-documnetation/PrismaDocumentation.ts rename to src/lib/prisma-documentation/PrismaDocumentation.ts diff --git a/src/lib/prisma-documnetation/index.ts b/src/lib/prisma-documentation/index.ts similarity index 100% rename from src/lib/prisma-documnetation/index.ts rename to src/lib/prisma-documentation/index.ts diff --git a/src/lib/prisma-utils/index.ts b/src/lib/prisma-utils/index.ts new file mode 100644 index 000000000..49fbfcae3 --- /dev/null +++ b/src/lib/prisma-utils/index.ts @@ -0,0 +1 @@ +export * as PrismaUtils from './index_'; diff --git a/src/lib/prisma-utils/index_.ts b/src/lib/prisma-utils/index_.ts new file mode 100644 index 000000000..396eaf65f --- /dev/null +++ b/src/lib/prisma-utils/index_.ts @@ -0,0 +1,17 @@ +import { lowerFirst } from 'lodash' +export * from './whereUniqueInput' + +/** + * Convert a set of Prisma model field names to a TS ORM property name for the WHERE input. + * + * ```ts + * prismaClient.user.findUnique({ where: { some_compound_fields: ... } }) + * // ^^^^^^^^^^^^^^^^^^^^ + * ``` + */ +export const TypeScriptOrmCompoundUniquePropertyName = (fieldNames: string[]) => fieldNames.join('_') + +/** + * Convert a Prisma model name as it would appear in a PSL file to its version as it would appear in the ORM `prismaClient..(...)`. + */ +export const typeScriptOrmModelPropertyNameFromModelName = (modelName: string) => lowerFirst(modelName) diff --git a/src/lib/prisma-utils/whereUniqueInput.ts b/src/lib/prisma-utils/whereUniqueInput.ts new file mode 100644 index 000000000..9360177c9 --- /dev/null +++ b/src/lib/prisma-utils/whereUniqueInput.ts @@ -0,0 +1,73 @@ +import { DMMF } from '@prisma/client/runtime' +import { pick } from 'lodash' +import { inspect } from 'util' +import { RecordUnknown } from '../../helpers/utils' +import { TypeScriptOrmCompoundUniquePropertyName } from './index_' + +type FieldName = string + +export const createWhereUniqueInput = (source: RecordUnknown, model: DMMF.Model) => { + // TODO There is no reason to compute this every time. Memoize or move. + const uniqueIdentifierFields = getUniqueIdentifierFields(model) + const uniqueIdentifierFieldsMissingInData = uniqueIdentifierFields.filter((_) => !source[_]) + + if (uniqueIdentifierFieldsMissingInData.length > 0) { + // TODO rich errors + throw new Error( + `Cannot create Prisma Client where unique input because the source data (${inspect( + source + )}) is missing the following unique identifier fields: ${uniqueIdentifierFieldsMissingInData.join( + ', ' + )}` + ) + } + + if (uniqueIdentifierFields.length === 1) { + return pick(source, uniqueIdentifierFields) + } + + return { + [TypeScriptOrmCompoundUniquePropertyName(uniqueIdentifierFields)]: pick(source, uniqueIdentifierFields), + } +} + +/** + * Get the field name (or names) of a model that are used to uniquely identify its records. + * + * If the model has no unique fields than error is thrown. This should be impossible as Prisma requires models + * to have unique record identity setup. + * + * @remarks We support the following unique-record-identity patterns. The first one we find is used. + * + * 1. Exactly one field with an `@id` annotation. + * 2. Multiple fields targeted by an `@@id` clause. + * 3. Exactly one field with an `@unique` annotation (if multiple, use first). + * 4. Multiple fields targeted by an `@@unique` clause. + */ +function getUniqueIdentifierFields(model: DMMF.Model): FieldName[] { + // Try finding 1 + const singleIdField = model.fields.find((f) => f.isId) + + if (singleIdField) { + return [singleIdField.name] + } + + // Try finding 2 + if (model.primaryKey && model.primaryKey.fields.length > 0) { + return model.primaryKey.fields + } + + // Try finding 3 + const singleUniqueField = model.fields.find((f) => f.isUnique) + + if (singleUniqueField) { + return [singleUniqueField.name] + } + + // Try finding 4 + if (model.uniqueFields && model.uniqueFields.length > 0) { + return model.uniqueFields[0] as string[] // I don't know why typescript want a cast here + } + + throw new Error(`Unable to resolve a unique identifier for the Prisma model: ${model.name}`) +} From 14152afcda0fb0bd744e2b39adbc82cf4b5cbe33 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Wed, 8 Dec 2021 20:25:06 +0000 Subject: [PATCH 08/25] lint --- src/lib/prisma-utils/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/prisma-utils/index.ts b/src/lib/prisma-utils/index.ts index 49fbfcae3..d2bf6bc12 100644 --- a/src/lib/prisma-utils/index.ts +++ b/src/lib/prisma-utils/index.ts @@ -1 +1 @@ -export * as PrismaUtils from './index_'; +export * as PrismaUtils from './index_' From 793836dc155e24fe0fda624a7195fc2b4ffae190 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Wed, 8 Dec 2021 20:37:33 +0000 Subject: [PATCH 09/25] more deterministic test snapshots --- tests/e2e/ts-node-import-error.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/ts-node-import-error.test.ts b/tests/e2e/ts-node-import-error.test.ts index 4156dbc76..67b08100e 100644 --- a/tests/e2e/ts-node-import-error.test.ts +++ b/tests/e2e/ts-node-import-error.test.ts @@ -52,7 +52,7 @@ it('when project does not have ts-node installed nexus-prisma generator still ge const normalizeGeneratorOutput = (output: string) => output - .replaceAll(/\d+ms/g, 'ms') + .replaceAll(/\d+(ms|s)/g, '$1') .replaceAll(/ to .* in /g, ' to in ') .replaceAll(/loaded from.*/g, 'loaded from ') .replaceAll(/Generated Prisma Client \(.*\)/g, 'Generated Prisma Client ()') From b32f73c94b56e8a1d91ead911b1314a02c55f44b Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Wed, 8 Dec 2021 20:39:05 +0000 Subject: [PATCH 10/25] feat: output gentime setting --- package.json | 6 +- src/cli/nexus-prisma.ts | 14 +- src/generator/generate.ts | 170 ++++++++++++--------- src/generator/gentime/settingsSingleton.ts | 48 +++++- src/generator/models/declaration.ts | 2 +- src/generator/models/javascript.ts | 13 +- 6 files changed, 169 insertions(+), 84 deletions(-) diff --git a/package.json b/package.json index 42976a37d..b958f35cc 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,11 @@ "./generator": { "require": "./dist-cjs/entrypoints/generator.js", "import": "./dist-esm/entrypoints/generator.js" - } + }, + "./_/*": { + "require": "./dist-cjs/*.js", + "import": "./dist-esm/*.js" + } }, "types": "./dist-cjs/entrypoints/main.d.ts", "typesVersions": { diff --git a/src/cli/nexus-prisma.ts b/src/cli/nexus-prisma.ts index 3452935f6..0aed2e06b 100755 --- a/src/cli/nexus-prisma.ts +++ b/src/cli/nexus-prisma.ts @@ -28,7 +28,7 @@ generatorHandler({ }, // async required by interface // eslint-disable-next-line - async onGenerate({ dmmf, otherGenerators }) { + async onGenerate({ dmmf, otherGenerators, generator }) { const prismaClientGenerator = otherGenerators.find((g) => g.provider.value === 'prisma-client-js') // TODO test showing this pretty error in action @@ -39,6 +39,18 @@ generatorHandler({ ) } + // TODO If the user is using nexus-prisma.config.ts then that should be the preferred source for this configuration because it is type safe. Give them a warning so they are aware. + if (generator.isCustomOutput) { + if (!generator.output) { + throw new Error(`Failed to read the custom output path.`) + } + Gentime.changeSettings({ + output: { + directory: generator.output.value, + }, + }) + } + // WARNING: Make sure this logic comes before `loadUserGentimeSettings` below // otherwise we will overwrite the user's choice for this setting if they have set it. Gentime.settings.change({ diff --git a/src/generator/generate.ts b/src/generator/generate.ts index b45bc51f1..149f54259 100644 --- a/src/generator/generate.ts +++ b/src/generator/generate.ts @@ -10,80 +10,6 @@ import { ModuleSpec } from './types' const OUTPUT_SOURCE_DIR_ESM = getOutputSourceDir({ esm: true }) const OUTPUT_SOURCE_DIR_CJS = getOutputSourceDir({ esm: false }) -/** Generate the Nexus Prisma runtime files and emit them into a "hole" in the internal package source tree. */ -export function generateRuntimeAndEmit(dmmf: DMMF.Document, settings: Gentime.Settings): void { - d('start generateRuntime with configuration %j', settings) - - d('start generateRuntime') - - if (process.env.NP_DEBUG) { - fs.write('dmmf.json', dmmf) - } - - const declarationSourceFile = ModelsGenerator.TS.createModuleSpec(dmmf, settings) - - // ESM - - const esmSourceFiles: ModuleSpec[] = [ - ModelsGenerator.JS.createModuleSpec({ - gentimeSettings: settings, - esm: true, - dmmf, - }), - declarationSourceFile, - ] - - fs.remove(OUTPUT_SOURCE_DIR_ESM) - - esmSourceFiles.forEach((sf) => { - const filePath = Path.join(OUTPUT_SOURCE_DIR_ESM, sf.fileName) - fs.remove(filePath) - fs.write(filePath, sf.content) - d(`did write ${filePath}`) - }) - - // CJS - - fs.remove(OUTPUT_SOURCE_DIR_CJS) - - const cjsSourceFiles: ModuleSpec[] = [ - ModelsGenerator.JS.createModuleSpec({ - gentimeSettings: settings, - esm: false, - dmmf, - }), - declarationSourceFile, - ] - - cjsSourceFiles.forEach((sf) => { - const filePath = Path.join(OUTPUT_SOURCE_DIR_CJS, sf.fileName) - fs.remove(filePath) - fs.write(filePath, sf.content) - d(`did write ${filePath}`) - }) - - d(`done writing all emitted files`) -} - -/** Transform the given DMMF into JS source code with accompanying TS declarations. */ -export function generateRuntime(dmmf: DMMF.Document, settings: Gentime.Settings): ModuleSpec[] { - const sourceFiles: ModuleSpec[] = [ - ModelsGenerator.JS.createModuleSpec({ - gentimeSettings: settings, - esm: true, - dmmf, - }), - ModelsGenerator.JS.createModuleSpec({ - gentimeSettings: settings, - esm: false, - dmmf, - }), - ModelsGenerator.TS.createModuleSpec(dmmf, settings), - ] - - return sourceFiles -} - /** * Find the output source directory. When using the Yalc workflow some additional hacking around is required. * @@ -119,3 +45,99 @@ function getOutputSourceDir(params: { esm: boolean }): string { return outputSourceDir } + +/** Generate the Nexus Prisma runtime files and emit them into a "hole" in the internal package source tree. */ +export function generateRuntimeAndEmit(dmmf: DMMF.Document, settings: Gentime.Settings): void { + d('start generateRuntime with configuration %j', settings) + + d('start generateRuntime') + + if (process.env.NP_DEBUG) { + fs.write('dmmf.json', dmmf) + } + + const declarationSourceFile = ModelsGenerator.TS.createModuleSpec(dmmf, settings) + + if (settings.data.output) { + const outputDir = settings.data.output.directory + + const sourceFiles = [ + ModelsGenerator.JS.createModuleSpec({ + gentimeSettings: settings, + esm: settings.data.output?.moduleSystem === 'esm', + dmmf, + }), + declarationSourceFile, + ] + + fs.remove(outputDir) + + sourceFiles.forEach((sf) => { + const filePath = Path.join(outputDir, sf.fileName) + fs.remove(filePath) + fs.write(filePath, sf.content) + d(`did write ${filePath}`) + }) + } else { + // ESM + + const esmSourceFiles = [ + ModelsGenerator.JS.createModuleSpec({ + gentimeSettings: settings, + esm: true, + dmmf, + }), + declarationSourceFile, + ] + + fs.remove(OUTPUT_SOURCE_DIR_ESM) + + esmSourceFiles.forEach((sf) => { + const filePath = Path.join(OUTPUT_SOURCE_DIR_ESM, sf.fileName) + fs.remove(filePath) + fs.write(filePath, sf.content) + d(`did write ${filePath}`) + }) + + // CJS + + const cjsSourceFiles = [ + ModelsGenerator.JS.createModuleSpec({ + gentimeSettings: settings, + esm: false, + dmmf, + }), + declarationSourceFile, + ] + + fs.remove(OUTPUT_SOURCE_DIR_CJS) + + cjsSourceFiles.forEach((sf) => { + const filePath = Path.join(OUTPUT_SOURCE_DIR_CJS, sf.fileName) + fs.remove(filePath) + fs.write(filePath, sf.content) + d(`did write ${filePath}`) + }) + } + + d(`done writing all emitted files`) +} + +/** Transform the given DMMF into JS source code with accompanying TS declarations. */ +export function generateRuntime(dmmf: DMMF.Document, settings: Gentime.Settings): ModuleSpec[] { + const sourceFiles: ModuleSpec[] = [ + ModelsGenerator.JS.createModuleSpec({ + gentimeSettings: settings, + esm: true, + dmmf, + }), + ModelsGenerator.JS.createModuleSpec({ + gentimeSettings: settings, + esm: false, + dmmf, + }), + ModelsGenerator.TS.createModuleSpec(dmmf, settings), + ] + + return sourceFiles +} diff --git a/src/generator/gentime/settingsSingleton.ts b/src/generator/gentime/settingsSingleton.ts index 5dec53b21..65d6addc9 100644 --- a/src/generator/gentime/settingsSingleton.ts +++ b/src/generator/gentime/settingsSingleton.ts @@ -82,14 +82,60 @@ export namespace Gentime { * @default '@prisma/client' */ prismaClientImportId?: string + /** + * Where to output the Nexus Prisma runtime and if it should use ESM or CJS module system. + * + * By default Nexus Prisma runtime is output into its installed node_modules location and supports both ESM and CJS. + * + * When you explicitly configure this setting Nexus Prisma only supports outputting ESM OR CJS, not both. + * + * Passing `string` is shorthand for `{ directory: string }` + */ + output?: + | string + | { + /** + * The directory to output the Nexus Prisma runtime into. + * + * If a relative path is given then it is considered relative to the Prisma Schema file. + * + * By default Nexus Prisma runtime is output into its installed node_modules location. + */ + directory: string + /** + * The module system to use for the output modules. + * + * @default 'cjs' + */ + moduleSystem?: 'esm' | 'cjs' + } } - export type SettingsData = Setset.InferDataFromInput + export type SettingsData = Omit, 'output'> & { + output?: { + directory: string + moduleSystem: 'esm' | 'cjs' + } + } export type Settings = Setset.Manager export const settings = Setset.create({ fields: { + output: { + shorthand: (directory) => ({ directory }), + fields: { + directory: { + fixup: (directory) => ({ + // TODO if relative, make absolute, from PSL file + value: directory, + }), + }, + moduleSystem: { + initial: () => 'cjs', + }, + }, + }, projectIdIntToGraphQL: { initial: () => 'Int', }, diff --git a/src/generator/models/declaration.ts b/src/generator/models/declaration.ts index dc28d1c2f..155e9cbea 100644 --- a/src/generator/models/declaration.ts +++ b/src/generator/models/declaration.ts @@ -10,7 +10,7 @@ import { Gentime } from '../gentime/settingsSingleton' import { jsDocForEnum, jsDocForField, jsDocForModel } from '../helpers/JSDocTemplates' import { ModuleSpec } from '../types' -export function createModuleSpec(dmmf: DMMF.Document, settings: Gentime.Settings): ModuleSpec { +export const createModuleSpec = (dmmf: DMMF.Document, settings: Gentime.Settings): ModuleSpec => { return { fileName: 'index.d.ts', content: dedent` diff --git a/src/generator/models/javascript.ts b/src/generator/models/javascript.ts index d74b2aaa3..5c029cc9b 100644 --- a/src/generator/models/javascript.ts +++ b/src/generator/models/javascript.ts @@ -95,16 +95,17 @@ export function createModuleSpec(params: { } ` + const importSpecifierToNexusPrismaSourceDirectory = gentimeSettings.data.output ? `nexus-prisma/_` : `..` const imports = esm ? dedent` - import { getPrismaClientDmmf } from '../helpers/prisma' - import * as ModelsGenerator from '../generator/models' - import { Runtime } from '../generator/runtime/settingsSingleton' + import { getPrismaClientDmmf } from '${importSpecifierToNexusPrismaSourceDirectory}/helpers/prisma' + import * as ModelsGenerator from '${importSpecifierToNexusPrismaSourceDirectory}/generator/models' + import { Runtime } from '${importSpecifierToNexusPrismaSourceDirectory}/generator/runtime/settingsSingleton' ` : dedent` - const { getPrismaClientDmmf } = require('../helpers/prisma') - const ModelsGenerator = require('../generator/models') - const { Runtime } = require('../generator/runtime/settingsSingleton') + const { getPrismaClientDmmf } = require('${importSpecifierToNexusPrismaSourceDirectory}/helpers/prisma') + const ModelsGenerator = require('${importSpecifierToNexusPrismaSourceDirectory}/generator/models') + const { Runtime } = require('${importSpecifierToNexusPrismaSourceDirectory}/generator/runtime/settingsSingleton') ` return { From 6fc7dcc60f744bebb358f1c2ab30f01560446d3b Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Wed, 8 Dec 2021 20:56:03 +0000 Subject: [PATCH 11/25] format --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b958f35cc..9712f3b22 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "./_/*": { "require": "./dist-cjs/*.js", "import": "./dist-esm/*.js" - } + } }, "types": "./dist-cjs/entrypoints/main.d.ts", "typesVersions": { From 870c840246d83882b0d45496aa846457d92b3d6d Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Mon, 13 Dec 2021 15:00:28 +0000 Subject: [PATCH 12/25] split settings docs into own pages --- docs/pages/architecture.md | 4 +- docs/pages/features.md | 208 +++------------------------------ docs/pages/meta.json | 6 +- docs/pages/settings-gentime.md | 115 ++++++++++++++++++ docs/pages/settings-runtime.md | 63 ++++++++++ 5 files changed, 199 insertions(+), 197 deletions(-) create mode 100644 docs/pages/settings-gentime.md create mode 100644 docs/pages/settings-runtime.md diff --git a/docs/pages/architecture.md b/docs/pages/architecture.md index c29332dda..b3090c644 100644 --- a/docs/pages/architecture.md +++ b/docs/pages/architecture.md @@ -1,11 +1,13 @@ # Architecture +Understanding the following information should not be required knowledge for using Nexus Prisma. It is primarily here for internal maintenance and collaboration. But we're happy for whatever benefit you get out of it too. + ![nexus-prisma-architecture](https://user-images.githubusercontent.com/284476/118728589-70fce780-b802-11eb-8c8b-4328ef5d6fb5.png) 1. You or a script (CI, programmatic, etc.) run `$ prisma generate`. 2. Prisma generator system reads your Prisma schema file 3. Prisma generator system runs the Nexus Prisma generator passing it the "DMMF", a structured representation of your Prisma schema. 4. Nexus Prisma generator reads your Nexus Prisma generator configuration if present. -5. Nexus Prisma generator writes generated source code into its own package space in your node_modules. +5. Nexus Prisma generator writes generated source code. By default into a special place within the `nexus-prisma` package in your `node_modules`. However, you can configure this location. 6. Later when you run your code it imports `nexus-prisma` which hits the generated entrypoint. 7. The generated runtime is actually thin, making use of a larger static runtime. diff --git a/docs/pages/features.md b/docs/pages/features.md index ca520839a..a53ea60b0 100644 --- a/docs/pages/features.md +++ b/docs/pages/features.md @@ -2,7 +2,7 @@ > **Note**: ⛑ The following use abbreviated examples that skip a complete setup of passing Nexus type definition to Nexus' `makeSchema`. If you are new to Nexus, consider reading the [official Nexus tutorial](https://nxs.li/tutorial) before jumping into Nexus Prisma. -### Type-safe Generated Library Code +## Type-safe Generated Library Code Following the same philosophy as Prisma Client, Nexus Prisma uses generation to create an API that feels tailor made for your project. @@ -28,7 +28,7 @@ objectType({ }) ``` -### Project Enums +## Project Enums Every enum defined in your Prisma schema becomes importable as a Nexus enum type definition configuration. This makes it trivial to project enums from your database layer into your API layer. @@ -49,7 +49,7 @@ SomeEnum.members // ['foo', 'bar'] enumType(SomeEnum) ``` -### Project Scalars +## Project Scalars Like GraphQL, [Prisma has the concept of scalar types](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference/#model-field-scalar-types). Some of the Prisma scalars can be naturally mapped to standard GraphQL scalars. The mapping is as follows: @@ -95,7 +95,7 @@ makeSchema({ There is a [recipe below](#Supply-custom-custom-scalars-to-your-GraphQL-schema) showing how to add your own custom scalars if you want. -### Project Relations +## Project Relations You can project [relations](https://www.prisma.io/docs/concepts/components/prisma-schema/relations) into your API with Nexus Prisma. Nexus Prisma even includes the resolver you'll need at runtime to fulfill the projection by automating use of your Prisma Client instance. @@ -122,7 +122,7 @@ new ApolloServer({ }) ``` -### Project 1:1 Relation +## Project 1:1 Relation You can project [1:1 relationships](https://www.prisma.io/docs/concepts/components/prisma-schema/relations#one-to-one-relations) into your API. @@ -308,7 +308,7 @@ objectType({ }) ``` -### Project 1:n Relation +## Project 1:n Relation You can project [1:n relationships](https://www.prisma.io/docs/concepts/components/prisma-schema/relations#one-to-many-relations) into your API. @@ -431,7 +431,7 @@ query { } ``` -### Projecting Nullability +## Projecting Nullability Currently nullability projection is not configurable. This section describes how Nexus Prisma handles it. @@ -479,187 +479,7 @@ If you have a use-case for different behaviour [please open a feature request](h - [`#98` Always set rejectOnNotFound to false](https://github.com/prisma/nexus-prisma/issues/98) -### Runtime Settings - -#### Reference - -##### `prismaClientContextField: string` - -- **@summary** The name of the GraphQL context field to get an instance of Prisma Client from. -- **@remarks** The instance of Prisma Client found here is accessed in the default resolvers for relational fields. -- **@default** `"prisma"` -- **@example** - - ```ts - // src/main.ts - - import { PrismaClient } from '@prisma/client' - import { ApolloServer } from 'apollo-server' - import { makeSchema } from 'nexus' - import { User, Post, $settings } from 'nexus-prisma' - - new ApolloServer({ - schema: makeSchema({ - types: [], - }), - context() { - return { - db: new PrismaClient(), // <-- You put Prisma client on the "db" context property - } - }, - }) - - $settings({ - prismaClientContextField: 'db', // <-- Tell Nexus Prisma - }) - ``` - -##### `prismaClientImportId: string` - -- **@summary** Where Nexus Prisma will try to import your generated Prisma Client from. You should not need to configure this normally because Nexus Prisma generator automatically reads the Prisma Client generator `output` setting if you have set it. The value here will be used in a dynamic import thus following Node's path resolution rules. You can pass a node_modules package like `foo` `@prisma/client`, `@my/custom/thing` etc. or you can pass an absolute module/file path `/my/custom/thing` / `/my/custom/thing/index.js` or finally a relative path to be resolved relative to the location of Nexus Prisma source files (you probably don't want this). - -- **@default** `@prisma/client` - -- **@remarks** Nexus Prisma imports Prisma client internally for two reasons: 1) validation wherein a class reference to Prisma Client is needed for some `instanceof` checks and 2) for acquiring the DMMF as Nexus Prisma relies on some post-processing done by Prisma Client generator. - -- **@example** - - ```ts - // src/main.ts - - import { PrismaClient } from '@prisma/client' - import { ApolloServer } from 'apollo-server' - import { makeSchema } from 'nexus' - import { User, Post, $settings } from 'nexus-prisma' - - new ApolloServer({ - schema: makeSchema({ - types: [], - }), - }) - - $settings({ - prismaClientImportId: '@my/custom/thing', - }) - ``` - -### Gentime Settings - -You are able to control certain aspects of the Nexus Prisma code generation. - -#### Usage - -1. Create a configuration file named any of: - - ``` - nexusPrisma.ts / nexus-prisma.ts / nexus_prisma.ts - ``` - - In one of the following directories: - - 1. **Project Root** – The directory containing your project's package.json. Example: - - ``` - ├── nexus-prisma.ts - └── package.json - ``` - - 2. **Primsa Directory** – The directory containing your Prisma schema. Example: - - ``` - ├── prisma/nexus-prisma.ts - └── package.json - ``` - -2. If you have not already, install [`ts-node`](https://github.com/TypeStrong/ts-node) which `nexus-prisma` will use to read your configuration module. - -3. Import the settings singleton and make your desired changes. Example: - - ```ts - import { settings } from 'nexus-prisma/generator' - - settings({ - projectIdIntToGraphQL: 'ID', - }) - ``` - -#### Reference - -##### `projectIdIntToGraphQL: 'ID' | 'Int'` - -- **`@default`** `Int` -- **`@summary`** Map Prisma model fields of type `Int` with attribute `@id` to `ID` or `Int`. - -##### `jsdocPropagationDefault?: 'none' | 'guide'` - -- **`@default`** `'guide'` -- **`@summary`** - - Nexus Prisma will project your Prisma schema field/model/enum documentation into JSDoc of the generated Nexus Prisma API. - - This setting controls what Nexus Prisma should do when you have not written documentation in your Prisma Schema for a field/model/enum. - - The following modes are as follows: - - 1. `'none'` - - In this mode, no default JSDoc will be written. - - 2. `'guide'` - - In this mode, guide content into your JSDoc that looks something like the following: - - ``` - * ### ️⚠️ You have not writen documentation for ${thisItem} - - * Replace this default advisory JSDoc with your own documentation about ${thisItem} - * by documenting it in your Prisma schema. For example: - * ... - * ... - * ... - ``` - -##### `docPropagation.JSDoc: boolean` - -- **`@default`** `true` -- **`@summary`** Should Prisma Schema docs propagate as JSDoc? - -##### `docPropagation.GraphQLDocs: boolean` - -- **`@default`** `true` -- **`@summary`** Should Prisma Schema docs propagate as GraphQL docs? -- **`@remarks`** When this is disabled it will force `.description` property to be `undefined`. This is for convenience, allowing you to avoid post-generation data manipulation or consumption contortions. - -### Prisma String @id fields project as GraphQL ID fields - -All `String` fields with `@id` attribute in your Prisma Schema get projected as GraphQL `ID` types rather than `String` types. - -```prisma -model User { - id String @id -} -``` - -```ts -import { User } from 'nexus-prisma' -import { objectType } from 'nexus' - -objectType({ - name: User.$name - description: User.$description - definition(t) { - t.field(User.id) - } -}) -``` - -```graphql -type User { - id: ID -} -``` - -### Prisma Schema Docs Propagation +## Prisma Schema Docs Propagation #### As GraphQL schema doc @@ -753,7 +573,7 @@ model Foo { This formatting logic is conservative. We are open to making it less so, in order to support more expressivity. Please [open an issue](https://github.com/prisma/nexus-prisma/issues/new?assignees=&labels=type%2Ffeat&template=10-feature.md&title=Better%20extraction%20of%20Prisma%20documentation) if you have an idea. -### ESM Support +## ESM Support Nexus Prisma supports both [ESM](https://nodejs.org/api/esm.html) and CJS. There shouldn't be anything you need to "do", things should "just work". Here's the highlights of how it works though: @@ -761,20 +581,20 @@ Nexus Prisma supports both [ESM](https://nodejs.org/api/esm.html) and CJS. There - When the generator runs, it emits CJS code to the CJS build _and_ ESM code to the ESM build. - Nexus Prisma CLI exists both in the ESM and CJS builds but its built to not matter which is used. That said, the package manifest is setup to run the CJS of the CLI and so that is what ends up being used in practice. -### Refined DX +## Refined DX These are finer points that aren't perhaps worth a top-level point but none the less add up toward a thoughtful developer experience. -##### JSDoc +#### JSDoc - Generated Nexus configuration for fields and models that you _have not_ documented in your PSL get default JSDoc that teaches you how to do so. - JSDoc for Enums have their members embedded -##### Default Runtime +#### Default Runtime When your project is in a state where the generated Nexus Prisma part is missing (new repo clone, reinstalled deps, etc.) Nexus Prisma gives you a default runtime export named `PleaseRunPrismaGenerate` and will error with a clear message. -##### Peer-Dependency Validation +#### Peer-Dependency Validation When `nexus-prisma` is imported it will validate that your project has peer dependencies setup correctly. @@ -785,6 +605,6 @@ NO_PEER_DEPENDENCY_CHECK=true|1 PEER_DEPENDENCY_CHECK=false|0 ``` -##### Auto-Import Optimized +#### Auto-Import Optimized - `nexus-prisma/scalars` offers a default export you can easily auto-import by name: `NexusPrismaScalars`. diff --git a/docs/pages/meta.json b/docs/pages/meta.json index af236ae52..ab2bdd0a3 100644 --- a/docs/pages/meta.json +++ b/docs/pages/meta.json @@ -2,8 +2,10 @@ "index": "Introduction", "usage": "Usage", "roadmap": "Roadmap", - "architecture": "Architecture", "features": "Features", + "settings-gentime": "Settings (Gentime)", + "settings-runtime": "Settings (Runtime)", "recipes": "Recipes", - "notes": "Notes" + "notes": "Notes", + "architecture": "Architecture" } diff --git a/docs/pages/settings-gentime.md b/docs/pages/settings-gentime.md new file mode 100644 index 000000000..f854060c8 --- /dev/null +++ b/docs/pages/settings-gentime.md @@ -0,0 +1,115 @@ +# Gentime Settings + +You are able to control certain aspects of the Nexus Prisma code generation. + +## Usage + +1. Create a configuration file named any of: + + ``` + nexusPrisma.ts / nexus-prisma.ts / nexus_prisma.ts + ``` + + In one of the following directories: + + 1. **Project Root** – The directory containing your project's package.json. Example: + + ``` + ├── nexus-prisma.ts + └── package.json + ``` + + 2. **Primsa Directory** – The directory containing your Prisma schema. Example: + + ``` + ├── prisma/nexus-prisma.ts + └── package.json + ``` + +2. If you have not already, install [`ts-node`](https://github.com/TypeStrong/ts-node) which `nexus-prisma` will use to read your configuration module. + +3. Import the settings singleton and make your desired changes. Example: + + ```ts + import { settings } from 'nexus-prisma/generator' + + settings({ + projectIdIntToGraphQL: 'ID', + }) + ``` + +## Reference + +#### `projectIdIntToGraphQL: 'ID' | 'Int'` + +- **`@default`** `Int` +- **`@summary`** Map Prisma model fields of type `Int` with attribute `@id` to `ID` or `Int`. + +#### `jsdocPropagationDefault?: 'none' | 'guide'` + +- **`@default`** `'guide'` +- **`@summary`** + + Nexus Prisma will project your Prisma schema field/model/enum documentation into JSDoc of the generated Nexus Prisma API. + + This setting controls what Nexus Prisma should do when you have not written documentation in your Prisma Schema for a field/model/enum. + + The following modes are as follows: + + 1. `'none'` + + In this mode, no default JSDoc will be written. + + 2. `'guide'` + + In this mode, guide content into your JSDoc that looks something like the following: + + ``` + * ### ️⚠️ You have not writen documentation for ${thisItem} + + * Replace this default advisory JSDoc with your own documentation about ${thisItem} + * by documenting it in your Prisma schema. For example: + * ... + * ... + * ... + ``` + +#### `docPropagation.JSDoc: boolean` + +- **`@default`** `true` +- **`@summary`** Should Prisma Schema docs propagate as JSDoc? + +#### `docPropagation.GraphQLDocs: boolean` + +- **`@default`** `true` +- **`@summary`** Should Prisma Schema docs propagate as GraphQL docs? +- **`@remarks`** When this is disabled it will force `.description` property to be `undefined`. This is for convenience, allowing you to avoid post-generation data manipulation or consumption contortions. + +### Prisma String @id fields project as GraphQL ID fields + +All `String` fields with `@id` attribute in your Prisma Schema get projected as GraphQL `ID` types rather than `String` types. + +```prisma +model User { + id String @id +} +``` + +```ts +import { User } from 'nexus-prisma' +import { objectType } from 'nexus' + +objectType({ + name: User.$name + description: User.$description + definition(t) { + t.field(User.id) + } +}) +``` + +```graphql +type User { + id: ID +} +``` diff --git a/docs/pages/settings-runtime.md b/docs/pages/settings-runtime.md new file mode 100644 index 000000000..a3177ee3b --- /dev/null +++ b/docs/pages/settings-runtime.md @@ -0,0 +1,63 @@ +# Runtime Settings + +## Reference + +#### `prismaClientContextField: string` + +- **@summary** The name of the GraphQL context field to get an instance of Prisma Client from. +- **@remarks** The instance of Prisma Client found here is accessed in the default resolvers for relational fields. +- **@default** `"prisma"` +- **@example** + + ```ts + // src/main.ts + + import { PrismaClient } from '@prisma/client' + import { ApolloServer } from 'apollo-server' + import { makeSchema } from 'nexus' + import { User, Post, $settings } from 'nexus-prisma' + + new ApolloServer({ + schema: makeSchema({ + types: [], + }), + context() { + return { + db: new PrismaClient(), // <-- You put Prisma client on the "db" context property + } + }, + }) + + $settings({ + prismaClientContextField: 'db', // <-- Tell Nexus Prisma + }) + ``` + +#### `prismaClientImportId: string` + +- **@summary** Where Nexus Prisma will try to import your generated Prisma Client from. You should not need to configure this normally because Nexus Prisma generator automatically reads the Prisma Client generator `output` setting if you have set it. The value here will be used in a dynamic import thus following Node's path resolution rules. You can pass a node_modules package like `foo` `@prisma/client`, `@my/custom/thing` etc. or you can pass an absolute module/file path `/my/custom/thing` / `/my/custom/thing/index.js` or finally a relative path to be resolved relative to the location of Nexus Prisma source files (you probably don't want this). + +- **@default** `@prisma/client` + +- **@remarks** Nexus Prisma imports Prisma client internally for two reasons: 1) validation wherein a class reference to Prisma Client is needed for some `instanceof` checks and 2) for acquiring the DMMF as Nexus Prisma relies on some post-processing done by Prisma Client generator. + +- **@example** + + ```ts + // src/main.ts + + import { PrismaClient } from '@prisma/client' + import { ApolloServer } from 'apollo-server' + import { makeSchema } from 'nexus' + import { User, Post, $settings } from 'nexus-prisma' + + new ApolloServer({ + schema: makeSchema({ + types: [], + }), + }) + + $settings({ + prismaClientImportId: '@my/custom/thing', + }) + ``` From a97faa769016975520de65794f705ac6015c968f Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Mon, 13 Dec 2021 18:20:31 +0000 Subject: [PATCH 13/25] improve doc and config schema --- docs/pages/settings-gentime.md | 74 +------------------- docs/pages/settings-runtime.md | 60 +---------------- src/generator/gentime/settingsSingleton.ts | 78 +++++++++++++++++++--- 3 files changed, 72 insertions(+), 140 deletions(-) diff --git a/docs/pages/settings-gentime.md b/docs/pages/settings-gentime.md index f854060c8..910e20eed 100644 --- a/docs/pages/settings-gentime.md +++ b/docs/pages/settings-gentime.md @@ -40,76 +40,4 @@ You are able to control certain aspects of the Nexus Prisma code generation. ## Reference -#### `projectIdIntToGraphQL: 'ID' | 'Int'` - -- **`@default`** `Int` -- **`@summary`** Map Prisma model fields of type `Int` with attribute `@id` to `ID` or `Int`. - -#### `jsdocPropagationDefault?: 'none' | 'guide'` - -- **`@default`** `'guide'` -- **`@summary`** - - Nexus Prisma will project your Prisma schema field/model/enum documentation into JSDoc of the generated Nexus Prisma API. - - This setting controls what Nexus Prisma should do when you have not written documentation in your Prisma Schema for a field/model/enum. - - The following modes are as follows: - - 1. `'none'` - - In this mode, no default JSDoc will be written. - - 2. `'guide'` - - In this mode, guide content into your JSDoc that looks something like the following: - - ``` - * ### ️⚠️ You have not writen documentation for ${thisItem} - - * Replace this default advisory JSDoc with your own documentation about ${thisItem} - * by documenting it in your Prisma schema. For example: - * ... - * ... - * ... - ``` - -#### `docPropagation.JSDoc: boolean` - -- **`@default`** `true` -- **`@summary`** Should Prisma Schema docs propagate as JSDoc? - -#### `docPropagation.GraphQLDocs: boolean` - -- **`@default`** `true` -- **`@summary`** Should Prisma Schema docs propagate as GraphQL docs? -- **`@remarks`** When this is disabled it will force `.description` property to be `undefined`. This is for convenience, allowing you to avoid post-generation data manipulation or consumption contortions. - -### Prisma String @id fields project as GraphQL ID fields - -All `String` fields with `@id` attribute in your Prisma Schema get projected as GraphQL `ID` types rather than `String` types. - -```prisma -model User { - id String @id -} -``` - -```ts -import { User } from 'nexus-prisma' -import { objectType } from 'nexus' - -objectType({ - name: User.$name - description: User.$description - definition(t) { - t.field(User.id) - } -}) -``` - -```graphql -type User { - id: ID -} -``` +Please refer to the thorough JSDoc for reference documentation. Typically consumed in your IDE or [Paka](https://paka.dev/npm/nexus-prisma). diff --git a/docs/pages/settings-runtime.md b/docs/pages/settings-runtime.md index a3177ee3b..9347f2240 100644 --- a/docs/pages/settings-runtime.md +++ b/docs/pages/settings-runtime.md @@ -2,62 +2,4 @@ ## Reference -#### `prismaClientContextField: string` - -- **@summary** The name of the GraphQL context field to get an instance of Prisma Client from. -- **@remarks** The instance of Prisma Client found here is accessed in the default resolvers for relational fields. -- **@default** `"prisma"` -- **@example** - - ```ts - // src/main.ts - - import { PrismaClient } from '@prisma/client' - import { ApolloServer } from 'apollo-server' - import { makeSchema } from 'nexus' - import { User, Post, $settings } from 'nexus-prisma' - - new ApolloServer({ - schema: makeSchema({ - types: [], - }), - context() { - return { - db: new PrismaClient(), // <-- You put Prisma client on the "db" context property - } - }, - }) - - $settings({ - prismaClientContextField: 'db', // <-- Tell Nexus Prisma - }) - ``` - -#### `prismaClientImportId: string` - -- **@summary** Where Nexus Prisma will try to import your generated Prisma Client from. You should not need to configure this normally because Nexus Prisma generator automatically reads the Prisma Client generator `output` setting if you have set it. The value here will be used in a dynamic import thus following Node's path resolution rules. You can pass a node_modules package like `foo` `@prisma/client`, `@my/custom/thing` etc. or you can pass an absolute module/file path `/my/custom/thing` / `/my/custom/thing/index.js` or finally a relative path to be resolved relative to the location of Nexus Prisma source files (you probably don't want this). - -- **@default** `@prisma/client` - -- **@remarks** Nexus Prisma imports Prisma client internally for two reasons: 1) validation wherein a class reference to Prisma Client is needed for some `instanceof` checks and 2) for acquiring the DMMF as Nexus Prisma relies on some post-processing done by Prisma Client generator. - -- **@example** - - ```ts - // src/main.ts - - import { PrismaClient } from '@prisma/client' - import { ApolloServer } from 'apollo-server' - import { makeSchema } from 'nexus' - import { User, Post, $settings } from 'nexus-prisma' - - new ApolloServer({ - schema: makeSchema({ - types: [], - }), - }) - - $settings({ - prismaClientImportId: '@my/custom/thing', - }) - ``` +Please refer to the thorough JSDoc for reference documentation. Typically consumed in your IDE or [Paka](https://paka.dev/npm/nexus-prisma). diff --git a/src/generator/gentime/settingsSingleton.ts b/src/generator/gentime/settingsSingleton.ts index 65d6addc9..fcba201c3 100644 --- a/src/generator/gentime/settingsSingleton.ts +++ b/src/generator/gentime/settingsSingleton.ts @@ -83,19 +83,61 @@ export namespace Gentime { */ prismaClientImportId?: string /** - * Where to output the Nexus Prisma runtime and if it should use ESM or CJS module system. + * Configure various details about the Nexus Prisma generated runtime such as file location, name, type + * and module system to use. * - * By default Nexus Prisma runtime is output into its installed node_modules location and supports both ESM and CJS. + * By default is output into the installed node_modules location of Nexus Prisma itself and supports both + * ESM and CJS. * - * When you explicitly configure this setting Nexus Prisma only supports outputting ESM OR CJS, not both. + * If you explicitly configure this setting, then you can only output ESM _or_ CJS, not both, + * since as the project maintainer you will be in a position to know which one you want to use. + * + * The following files will be output into the target directory: + * + * ``` + * Description | Default Name | Default Extension | + * ---------------------------------------------------- + * A runtime file | index | .ts | + * A type file | index | .d.ts | + * ``` + * + * Passing `string` is a path to the target directory to output to, shorthand for `{ directory: string, + * moduleSystem: 'esm', type: 'ts' }` + * + * If a relative path is given then it is considered relative to the Prisma Schema file. + * + * @example + * + * // Default + * // prisma/nexus-prisma.config.ts + * import { settings } from 'nexus-prisma/generator' + * + * settings({ + * output: undefined // The default + * }) + * + * // src/schema.ts + * import { ... } from 'nexus-prisma' + * + * @example + * + * // Custom + * // prisma/nexus-prisma.config.ts + * import { settings } from 'nexus-prisma/generator' + * + * settings({ + * output: '../src/generated/nexus-prisma' + * }) + * + * // src/schema.ts + * import { ... } from './generated/nexus-prisma' * - * Passing `string` is shorthand for `{ directory: string }` */ output?: | string | { /** - * The directory to output the Nexus Prisma runtime into. + * The directory to output the generated modules into. * * If a relative path is given then it is considered relative to the Prisma Schema file. * @@ -103,9 +145,21 @@ export namespace Gentime { */ directory: string /** - * The module system to use for the output modules. + * The name to use for the generated modules. + * + * @default 'index' + */ + name?: string + /** + * The file extension to use for the generated runtime module. * - * @default 'cjs' + * @default 'ts' + */ + type?: 'ts' | 'js' + /** + * The module system to use for the generated runtime module. + * + * @default 'esm' */ moduleSystem?: 'esm' | 'cjs' } @@ -114,6 +168,8 @@ export namespace Gentime { export type SettingsData = Omit, 'output'> & { output?: { directory: string + name: string + type: 'ts' | 'js' moduleSystem: 'esm' | 'cjs' } } @@ -132,7 +188,13 @@ export namespace Gentime { }), }, moduleSystem: { - initial: () => 'cjs', + initial: () => 'esm', + }, + name: { + initial: () => 'index', + }, + type: { + initial: () => 'ts', }, }, }, From 945fad87624aeb1db506279811b639b8ad5400b1 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Mon, 13 Dec 2021 21:30:18 +0000 Subject: [PATCH 14/25] fixes --- package.json | 4 +- src/generator/generate.ts | 45 ++++++++++++---------- src/generator/gentime/settingsSingleton.ts | 16 ++++---- src/generator/models/javascript.ts | 7 +++- tests/e2e/gentime-setting-output.spec.ts | 22 +++++++++++ 5 files changed, 62 insertions(+), 32 deletions(-) create mode 100644 tests/e2e/gentime-setting-output.spec.ts diff --git a/package.json b/package.json index 9712f3b22..60b6d6eb7 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "require": "./dist-cjs/entrypoints/generator.js", "import": "./dist-esm/entrypoints/generator.js" }, - "./_/*": { + "./*": { "require": "./dist-cjs/*.js", "import": "./dist-esm/*.js" } @@ -58,7 +58,7 @@ "dev:ts": "yarn dev", "dev:yalc": "nodemon --delay 1.5 --exec 'yalc push --no-scripts' --watch 'dist-*/**/*'", "build": "yarn clean && tsc --build tsconfig.cjs.json tsconfig.esm.json", - "test": "cross-env NO_COLOR=true DEBUG=e2e jest", + "test": "cross-env NO_COLOR=true DEBUG='konn*,e2e' jest", "test:e2e": "cross-env NO_COLOR=true DEBUG=e2e jest --selectProjects e2e", "test:unit": "cross-env NO_COLOR=true jest --selectProjects unit", "test:ci": "cross-env DEBUG=e2e jest --coverage --forceExit --runInBand", diff --git a/src/generator/generate.ts b/src/generator/generate.ts index 149f54259..96163e418 100644 --- a/src/generator/generate.ts +++ b/src/generator/generate.ts @@ -57,63 +57,66 @@ export function generateRuntimeAndEmit(dmmf: DMMF.Document, settings: Gentime.Se } const declarationSourceFile = ModelsGenerator.TS.createModuleSpec(dmmf, settings) + process.stdout.write('1') + process.stdout.write(JSON.stringify(settings.data.output)) - if (settings.data.output) { - const outputDir = settings.data.output.directory + if (settings.data.output.directory === 'default') { + // ESM - const sourceFiles = [ + const esmSourceFiles = [ ModelsGenerator.JS.createModuleSpec({ gentimeSettings: settings, - esm: settings.data.output?.moduleSystem === 'esm', + esm: true, dmmf, }), declarationSourceFile, ] - fs.remove(outputDir) + // fs.remove(OUTPUT_SOURCE_DIR_ESM) - sourceFiles.forEach((sf) => { - const filePath = Path.join(outputDir, sf.fileName) + esmSourceFiles.forEach((sf) => { + const filePath = Path.join(OUTPUT_SOURCE_DIR_ESM, sf.fileName) fs.remove(filePath) fs.write(filePath, sf.content) d(`did write ${filePath}`) }) - } else { - // ESM - const esmSourceFiles = [ + // CJS + + const cjsSourceFiles = [ ModelsGenerator.JS.createModuleSpec({ gentimeSettings: settings, - esm: true, + esm: false, dmmf, }), declarationSourceFile, ] - fs.remove(OUTPUT_SOURCE_DIR_ESM) + fs.remove(OUTPUT_SOURCE_DIR_CJS) - esmSourceFiles.forEach((sf) => { - const filePath = Path.join(OUTPUT_SOURCE_DIR_ESM, sf.fileName) + cjsSourceFiles.forEach((sf) => { + const filePath = Path.join(OUTPUT_SOURCE_DIR_CJS, sf.fileName) fs.remove(filePath) fs.write(filePath, sf.content) d(`did write ${filePath}`) }) + } else { + const outputDir = settings.data.output.directory - // CJS - - const cjsSourceFiles = [ + const sourceFiles = [ ModelsGenerator.JS.createModuleSpec({ gentimeSettings: settings, - esm: false, + esm: settings.data.output?.moduleSystem === 'esm', dmmf, }), declarationSourceFile, ] - fs.remove(OUTPUT_SOURCE_DIR_CJS) + // fs.remove(outputDir) - cjsSourceFiles.forEach((sf) => { - const filePath = Path.join(OUTPUT_SOURCE_DIR_CJS, sf.fileName) + sourceFiles.forEach((sf) => { + const filePath = Path.join(outputDir, sf.fileName) + // process.stderr.write(filePath) fs.remove(filePath) fs.write(filePath, sf.content) d(`did write ${filePath}`) diff --git a/src/generator/gentime/settingsSingleton.ts b/src/generator/gentime/settingsSingleton.ts index fcba201c3..9af1aa86a 100644 --- a/src/generator/gentime/settingsSingleton.ts +++ b/src/generator/gentime/settingsSingleton.ts @@ -165,14 +165,7 @@ export namespace Gentime { } } - export type SettingsData = Omit, 'output'> & { - output?: { - directory: string - name: string - type: 'ts' | 'js' - moduleSystem: 'esm' | 'cjs' - } - } + export type SettingsData = Setset.InferDataFromInput export type Settings = Setset.Manager @@ -180,8 +173,15 @@ export namespace Gentime { fields: { output: { shorthand: (directory) => ({ directory }), + initial: () => ({ + directory: 'default', + name: 'index', + type: 'ts', + moduleSystem: 'esm', + }), fields: { directory: { + initial: () => 'default', fixup: (directory) => ({ // TODO if relative, make absolute, from PSL file value: directory, diff --git a/src/generator/models/javascript.ts b/src/generator/models/javascript.ts index 5c029cc9b..e0a2aa283 100644 --- a/src/generator/models/javascript.ts +++ b/src/generator/models/javascript.ts @@ -95,7 +95,12 @@ export function createModuleSpec(params: { } ` - const importSpecifierToNexusPrismaSourceDirectory = gentimeSettings.data.output ? `nexus-prisma/_` : `..` + const importSpecifierToNexusPrismaSourceDirectory = + gentimeSettings.data.output.directory === 'default' + ? `..` + : esm + ? `nexus-prisma/dist-esm` + : `nexus-prisma/dist-cjs` const imports = esm ? dedent` import { getPrismaClientDmmf } from '${importSpecifierToNexusPrismaSourceDirectory}/helpers/prisma' diff --git a/tests/e2e/gentime-setting-output.spec.ts b/tests/e2e/gentime-setting-output.spec.ts new file mode 100644 index 000000000..331f2b2d8 --- /dev/null +++ b/tests/e2e/gentime-setting-output.spec.ts @@ -0,0 +1,22 @@ +import { konn, providers } from 'konn' +import { Providers } from 'konn/providers' +import * as Path from 'path' +import { project } from '../__providers__/project' + +const ctx = konn() + .useBeforeEach(providers.dir()) + .useBeforeEach(providers.run()) + .useBeforeEach(project()) + .done() + +it('gentime setting output: custom directory', () => { + // ctx.fixture.use(Path.join(__dirname, 'fixtures/ncc')) + // ctx.runOrThrow(`${Path.join(process.cwd(), 'node_modules/.bin/yalc')} add ${ctx.thisPackageName}`) + // ctx.runOrThrow(`npm install --legacy-peer-deps`, { env: { PEER_DEPENDENCY_CHECK: 'false' } }) + // ctx.runOrThrowPackageScript(`build`) + // // Remove this to ensure that when the ncc build is run in the next step + // // it is truly running independent of any node_modules. + // ctx.fs.remove('node_modules') + // const result = ctx.runOrThrowPackageScript(`start:dist`, { env: { PEER_DEPENDENCY_CHECK: 'false' } }) + // expect(result.stdout).toMatchSnapshot() +}) From dcc23f8f55f595733f3ef7e02a9bdc56c96bd94c Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Mon, 13 Dec 2021 21:37:59 +0000 Subject: [PATCH 15/25] better fix, why did it work before :/ --- docs/pages/architecture.md | 30 ++++++++++++++++++++++++++++++ package.json | 3 +-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/docs/pages/architecture.md b/docs/pages/architecture.md index b3090c644..3e8105e0b 100644 --- a/docs/pages/architecture.md +++ b/docs/pages/architecture.md @@ -2,6 +2,8 @@ Understanding the following information should not be required knowledge for using Nexus Prisma. It is primarily here for internal maintenance and collaboration. But we're happy for whatever benefit you get out of it too. +## System + ![nexus-prisma-architecture](https://user-images.githubusercontent.com/284476/118728589-70fce780-b802-11eb-8c8b-4328ef5d6fb5.png) 1. You or a script (CI, programmatic, etc.) run `$ prisma generate`. @@ -11,3 +13,31 @@ Understanding the following information should not be required knowledge for usi 5. Nexus Prisma generator writes generated source code. By default into a special place within the `nexus-prisma` package in your `node_modules`. However, you can configure this location. 6. Later when you run your code it imports `nexus-prisma` which hits the generated entrypoint. 7. The generated runtime is actually thin, making use of a larger static runtime. + +## Package Exports + +When users choose a custom Nexus Prisma output directory the generated runtime needs to import the static runtime. There are a few things that need to happen in order for this to work: + +1. The output's imports needs to specify the package to import from +2. The output's imports needs to specify the subpath to import from + +For (1) we import from `'nexus-prisma'`. We just rely on the assumption that the user is outputting into a directory where eventually `node_modules/nexus-prisma` will should up in the CWD path as Node module resolution algorithm executes. + +For (2) we look if user is outputting ESM or CJS (gentime config) and based on that access either `/dist-cjs` or `/dist-esm`. In order to support this we need to break the encapsulation provided by package.json `exports` field. We need to configure in it: + +```json +"./*": { + "default": "./*.js" +} +``` + +We cannot do something slightly cleaner either like this: + +```json +"./_/*": { + "require": "./dist-cjs/*.js", + "import": "./dist-esm/*.js" +} +``` + +Because `ncc`, at least, does not support resolving `.../_/...` imports to what is specified in the package exports. diff --git a/package.json b/package.json index 60b6d6eb7..d4c3869f2 100644 --- a/package.json +++ b/package.json @@ -27,8 +27,7 @@ "import": "./dist-esm/entrypoints/generator.js" }, "./*": { - "require": "./dist-cjs/*.js", - "import": "./dist-esm/*.js" + "default": "./*.js" } }, "types": "./dist-cjs/entrypoints/main.d.ts", From 351752d0f547e148276b4fd5b2f32793f3e86754 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Tue, 14 Dec 2021 15:14:27 +0000 Subject: [PATCH 16/25] remove debug logs --- src/generator/generate.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/generator/generate.ts b/src/generator/generate.ts index 96163e418..57460ea98 100644 --- a/src/generator/generate.ts +++ b/src/generator/generate.ts @@ -57,8 +57,6 @@ export function generateRuntimeAndEmit(dmmf: DMMF.Document, settings: Gentime.Se } const declarationSourceFile = ModelsGenerator.TS.createModuleSpec(dmmf, settings) - process.stdout.write('1') - process.stdout.write(JSON.stringify(settings.data.output)) if (settings.data.output.directory === 'default') { // ESM From 5f3ce60dbd1075854b978f36710fa57715ebf108 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Tue, 14 Dec 2021 18:49:19 +0000 Subject: [PATCH 17/25] test --- package.json | 5 ++- src/cli/nexus-prisma.ts | 29 +++++++++++++++--- src/generator/generate.ts | 10 +++--- src/generator/gentime/settingsSingleton.ts | 12 +++----- src/generator/models/declaration.ts | 9 ++++-- src/generator/models/javascript.ts | 5 +-- tests/__providers__/project.ts | 7 +++++ .../gentime-setting-output.test.ts.snap | 12 ++++++++ tests/e2e/fixtures/basic/.gitignore | 1 + tests/e2e/fixtures/basic/main.ts | 26 ++++++++++++++++ tests/e2e/fixtures/basic/package.json | 17 ++++++++++ tests/e2e/fixtures/basic/prisma/db.sqlite | Bin 0 -> 20480 bytes .../e2e/fixtures/basic/prisma/nexus-prisma.ts | 7 +++++ tests/e2e/fixtures/basic/prisma/schema.prisma | 16 ++++++++++ tests/e2e/fixtures/basic/tsconfig.json | 6 ++++ tests/e2e/fixtures/ncc/package.json | 6 ++-- tests/e2e/gentime-setting-output.spec.ts | 22 ------------- tests/e2e/gentime-setting-output.test.ts | 18 +++++++++++ tests/e2e/ncc.test.ts | 1 - tsconfig.json | 3 +- 20 files changed, 164 insertions(+), 48 deletions(-) create mode 100644 tests/e2e/__snapshots__/gentime-setting-output.test.ts.snap create mode 100644 tests/e2e/fixtures/basic/.gitignore create mode 100644 tests/e2e/fixtures/basic/main.ts create mode 100644 tests/e2e/fixtures/basic/package.json create mode 100644 tests/e2e/fixtures/basic/prisma/db.sqlite create mode 100644 tests/e2e/fixtures/basic/prisma/nexus-prisma.ts create mode 100644 tests/e2e/fixtures/basic/prisma/schema.prisma create mode 100644 tests/e2e/fixtures/basic/tsconfig.json delete mode 100644 tests/e2e/gentime-setting-output.spec.ts create mode 100644 tests/e2e/gentime-setting-output.test.ts diff --git a/package.json b/package.json index d4c3869f2..e5a596c94 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "types": "./dist-cjs/entrypoints/main.d.ts", "typesVersions": { "*": { - "*": [ + "index.d.ts": [ "./dist-cjs/entrypoints/main.d.ts" ], "scalars": [ @@ -41,6 +41,9 @@ ], "generator": [ "./dist-cjs/entrypoints/generator.d.ts" + ], + "*": [ + "./*" ] } }, diff --git a/src/cli/nexus-prisma.ts b/src/cli/nexus-prisma.ts index 0aed2e06b..ac4319c06 100755 --- a/src/cli/nexus-prisma.ts +++ b/src/cli/nexus-prisma.ts @@ -28,7 +28,7 @@ generatorHandler({ }, // async required by interface // eslint-disable-next-line - async onGenerate({ dmmf, otherGenerators, generator }) { + async onGenerate({ dmmf, otherGenerators, generator, schemaPath }) { const prismaClientGenerator = otherGenerators.find((g) => g.provider.value === 'prisma-client-js') // TODO test showing this pretty error in action @@ -39,7 +39,7 @@ generatorHandler({ ) } - // TODO If the user is using nexus-prisma.config.ts then that should be the preferred source for this configuration because it is type safe. Give them a warning so they are aware. + // TODO If the user is using nexus-prisma.ts then that should be the preferred source for this configuration because it is type safe. Give them a warning so they are aware. if (generator.isCustomOutput) { if (!generator.output) { throw new Error(`Failed to read the custom output path.`) @@ -58,8 +58,25 @@ generatorHandler({ }) const internalDMMF = externalToInternalDmmf(dmmf) + loadUserGentimeSettings() + + /** + * If the output path is some explicit relative path then make it absolute relative to the Prisma Schema file directory. + */ + if ( + Gentime.settings.data.output.directory !== 'default' && + !Path.isAbsolute(Gentime.settings.data.output.directory) + ) { + Gentime.settings.change({ + output: { + directory: Path.join(Path.dirname(schemaPath), Gentime.settings.data.output.directory), + }, + }) + } + generateRuntimeAndEmit(internalDMMF, Gentime.settings) + process.stdout.write( `You can now start using Nexus Prisma in your code. Reference: https://pris.ly/d/nexus-prisma\n` ) @@ -71,11 +88,11 @@ generatorHandler({ */ /** - * Get the appropiate import ID for Prisma Client. + * Get the appropriate import ID for Prisma Client. * * When generator output is set to its default location within node_modules, then we return the import ID of just its npm moniker "@prisma/client". * - * Othewise we return an import ID as an absolute path to the output location. + * Otherwise we return an import ID as an absolute path to the output location. */ function getPrismaClientImportIdForItsGeneratorOutputConfig( prismaClientGeneratorConfig: GeneratorConfig @@ -142,3 +159,7 @@ function getPrismaClientImportIdForItsGeneratorOutputConfig( return prismaClientGeneratorConfig.output.value } + +const absoluteify = (path: string, prefixAbsolutePath: string) => { + return Path.isAbsolute(path) ? path : Path.join(prefixAbsolutePath, path) +} diff --git a/src/generator/generate.ts b/src/generator/generate.ts index 57460ea98..7a9d976b5 100644 --- a/src/generator/generate.ts +++ b/src/generator/generate.ts @@ -99,8 +99,6 @@ export function generateRuntimeAndEmit(dmmf: DMMF.Document, settings: Gentime.Se d(`did write ${filePath}`) }) } else { - const outputDir = settings.data.output.directory - const sourceFiles = [ ModelsGenerator.JS.createModuleSpec({ gentimeSettings: settings, @@ -113,8 +111,12 @@ export function generateRuntimeAndEmit(dmmf: DMMF.Document, settings: Gentime.Se // fs.remove(outputDir) sourceFiles.forEach((sf) => { - const filePath = Path.join(outputDir, sf.fileName) - // process.stderr.write(filePath) + const filePath = Path.join( + settings.data.output.directory, + sf.fileName.endsWith('d.ts') + ? `${settings.data.output.name}.d.ts` + : `${settings.data.output.name}.${settings.data.output.type}` + ) fs.remove(filePath) fs.write(filePath, sf.content) d(`did write ${filePath}`) diff --git a/src/generator/gentime/settingsSingleton.ts b/src/generator/gentime/settingsSingleton.ts index 9af1aa86a..4f96935af 100644 --- a/src/generator/gentime/settingsSingleton.ts +++ b/src/generator/gentime/settingsSingleton.ts @@ -153,13 +153,13 @@ export namespace Gentime { /** * The file extension to use for the generated runtime module. * - * @default 'ts' + * @default 'js' */ type?: 'ts' | 'js' /** * The module system to use for the generated runtime module. * - * @default 'esm' + * @default 'cjs' */ moduleSystem?: 'esm' | 'cjs' } @@ -182,19 +182,15 @@ export namespace Gentime { fields: { directory: { initial: () => 'default', - fixup: (directory) => ({ - // TODO if relative, make absolute, from PSL file - value: directory, - }), }, moduleSystem: { - initial: () => 'esm', + initial: () => 'cjs', }, name: { initial: () => 'index', }, type: { - initial: () => 'ts', + initial: () => 'js', }, }, }, diff --git a/src/generator/models/declaration.ts b/src/generator/models/declaration.ts index 155e9cbea..130296217 100644 --- a/src/generator/models/declaration.ts +++ b/src/generator/models/declaration.ts @@ -36,7 +36,6 @@ export function renderTypeScriptDeclarationForDocumentModels( return ( dedent` - import * as Nexus from 'nexus' import * as NexusCore from 'nexus/dist/core' // @@ -125,7 +124,13 @@ export function renderTypeScriptDeclarationForDocumentModels( // // - import { Runtime } from '../generator/runtime/settingsSingleton' + import { Runtime } from ${ + settings.data.output.directory === 'default' + ? `'../generator/runtime/settingsSingleton'` + : settings.data.output.moduleSystem === 'esm' + ? `'nexus-prisma/dist-esm/generator/runtime/settingsSingleton'` + : `'nexus-prisma/dist-cjs/generator/runtime/settingsSingleton'` + } /** * Adjust Nexus Prisma's [runtime settings](https://pris.ly/nexus-prisma/docs/settings/runtime). diff --git a/src/generator/models/javascript.ts b/src/generator/models/javascript.ts index e0a2aa283..e95ff2bcc 100644 --- a/src/generator/models/javascript.ts +++ b/src/generator/models/javascript.ts @@ -104,16 +104,17 @@ export function createModuleSpec(params: { const imports = esm ? dedent` import { getPrismaClientDmmf } from '${importSpecifierToNexusPrismaSourceDirectory}/helpers/prisma' - import * as ModelsGenerator from '${importSpecifierToNexusPrismaSourceDirectory}/generator/models' + import * as ModelsGenerator from '${importSpecifierToNexusPrismaSourceDirectory}/generator/models/index' import { Runtime } from '${importSpecifierToNexusPrismaSourceDirectory}/generator/runtime/settingsSingleton' ` : dedent` const { getPrismaClientDmmf } = require('${importSpecifierToNexusPrismaSourceDirectory}/helpers/prisma') - const ModelsGenerator = require('${importSpecifierToNexusPrismaSourceDirectory}/generator/models') + const ModelsGenerator = require('${importSpecifierToNexusPrismaSourceDirectory}/generator/models/index') const { Runtime } = require('${importSpecifierToNexusPrismaSourceDirectory}/generator/runtime/settingsSingleton') ` return { + // TODO this is no longer used, just return content fileName: 'index.js', content: dedent` ${imports} diff --git a/tests/__providers__/project.ts b/tests/__providers__/project.ts index 249dec0df..ab9f208e2 100644 --- a/tests/__providers__/project.ts +++ b/tests/__providers__/project.ts @@ -5,6 +5,7 @@ import { merge } from 'lodash' import readPkgUp from 'read-pkg-up' import { PackageJson, TsConfigJson } from 'type-fest' import { assertBuildPresent } from '../__helpers__/helpers' +import * as Package from '../../package.json' type Project = { thisPackageName: string @@ -47,6 +48,12 @@ export const project = () => ctx.fs.copy(path, ctx.fs.cwd(), { overwrite: true, }) + api.packageJson.merge({ + dependencies: { + '@prisma/client': Package.devDependencies['@prisma/client'], + prisma: Package.devDependencies.prisma, + }, + }) }, }, packageJson: { diff --git a/tests/e2e/__snapshots__/gentime-setting-output.test.ts.snap b/tests/e2e/__snapshots__/gentime-setting-output.test.ts.snap new file mode 100644 index 000000000..ab4ed9d0c --- /dev/null +++ b/tests/e2e/__snapshots__/gentime-setting-output.test.ts.snap @@ -0,0 +1,12 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`gentime setting output: custom directory 1`] = ` +"type Foo { + id: ID! +} + +type Query { + foos: [Foo] +} +" +`; diff --git a/tests/e2e/fixtures/basic/.gitignore b/tests/e2e/fixtures/basic/.gitignore new file mode 100644 index 000000000..3c3629e64 --- /dev/null +++ b/tests/e2e/fixtures/basic/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/tests/e2e/fixtures/basic/main.ts b/tests/e2e/fixtures/basic/main.ts new file mode 100644 index 000000000..f66acd4ac --- /dev/null +++ b/tests/e2e/fixtures/basic/main.ts @@ -0,0 +1,26 @@ +import { printSchema } from 'graphql' +import { makeSchema, objectType, queryType } from 'nexus' +import { Foo } from './generated/nexus-prisma' + +const schema = makeSchema({ + types: [ + objectType({ + name: Foo.$name, + definition(t) { + t.field(Foo.id) + }, + }), + queryType({ + definition(t) { + t.list.field('foos', { + type: 'Foo', + resolve(_, __, ctx) { + return ctx.prisma.foo.findMany() + }, + }) + }, + }), + ], +}) + +console.log(printSchema(schema)) diff --git a/tests/e2e/fixtures/basic/package.json b/tests/e2e/fixtures/basic/package.json new file mode 100644 index 000000000..6490992a4 --- /dev/null +++ b/tests/e2e/fixtures/basic/package.json @@ -0,0 +1,17 @@ +{ + "name": "nexus-prisma-fixture-basic", + "version": "0.0.0", + "scripts": { + "build": "npm run build:prisma", + "build:prisma": "prisma generate", + "dev": "ts-node main" + }, + "dependencies": { + "@prisma/client": "__dynamic__", + "graphql": "15.5.1", + "nexus": "1.1.0", + "prisma": "__dynamic__", + "ts-node": "10.2.1", + "typescript": "4.3.5" + } +} diff --git a/tests/e2e/fixtures/basic/prisma/db.sqlite b/tests/e2e/fixtures/basic/prisma/db.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..697f34514d38df8b5e77794ea38f320cd85aeaec GIT binary patch literal 20480 zcmeI&K}*9h6u|MM?TQXY20QE;3W8pQ;mMm-D#)sHvw}NFsjR|aTGS495WM&W{WgLZ zU&X;ZOgwog|3_Y$hLVt9P9eP*#?vylx5eXKR@yz)R$8kAYn4*IWJ7Wpjx@aGi#+v8 zdtK94yMyPJc~_okEAwjJOxs+q`=Q*9<=9Gcbo>Z=QZd9f% zNo_uq6aoPR5I_I{1Q0*~0R#|0009K*C*W$wWKCHY=l}X`E-OL+0R#|0009ILKmY** z5J2Etz;n%JR^9*0PyYl02q1s}0tg_000IagfB*sr)L5Xp|L6Q);|*qM2q1s}0tg_0 O00IagfB*srh`=ZKt55>~ literal 0 HcmV?d00001 diff --git a/tests/e2e/fixtures/basic/prisma/nexus-prisma.ts b/tests/e2e/fixtures/basic/prisma/nexus-prisma.ts new file mode 100644 index 000000000..d4ff2a0f6 --- /dev/null +++ b/tests/e2e/fixtures/basic/prisma/nexus-prisma.ts @@ -0,0 +1,7 @@ +import { settings } from 'nexus-prisma/generator' + +settings({ + output: { + directory: '../generated/nexus-prisma', + }, +}) diff --git a/tests/e2e/fixtures/basic/prisma/schema.prisma b/tests/e2e/fixtures/basic/prisma/schema.prisma new file mode 100644 index 000000000..2b9672a1c --- /dev/null +++ b/tests/e2e/fixtures/basic/prisma/schema.prisma @@ -0,0 +1,16 @@ +datasource db { + provider = "sqlite" + url = "file:./db.sqlite" +} + +generator client { + provider = "prisma-client-js" +} + +generator nexusPrisma { + provider = "nexus-prisma" +} + +model Foo { + id String @id @default(cuid()) +} diff --git a/tests/e2e/fixtures/basic/tsconfig.json b/tests/e2e/fixtures/basic/tsconfig.json new file mode 100644 index 000000000..d4e2d7632 --- /dev/null +++ b/tests/e2e/fixtures/basic/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "moduleResolution": "node" + }, + "include": ["."] +} diff --git a/tests/e2e/fixtures/ncc/package.json b/tests/e2e/fixtures/ncc/package.json index 789f050b8..433125b5c 100644 --- a/tests/e2e/fixtures/ncc/package.json +++ b/tests/e2e/fixtures/ncc/package.json @@ -1,5 +1,5 @@ { - "name": "nexus-prisma-ncc-test", + "name": "nexus-prisma-fixture-ncc", "version": "0.0.0", "scripts": { "build": "npm run build:prisma && npm run build:ncc", @@ -9,11 +9,11 @@ "start:ts": "ts-node main" }, "dependencies": { - "@prisma/client": "2.30", + "@prisma/client": "__dynamic__", "@vercel/ncc": "0.29.2", "graphql": "15.5.1", "nexus": "1.1.0", - "prisma": "2.30.0", + "prisma": "__dynamic__", "ts-node": "10.2.1", "typescript": "4.3.5" } diff --git a/tests/e2e/gentime-setting-output.spec.ts b/tests/e2e/gentime-setting-output.spec.ts deleted file mode 100644 index 331f2b2d8..000000000 --- a/tests/e2e/gentime-setting-output.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { konn, providers } from 'konn' -import { Providers } from 'konn/providers' -import * as Path from 'path' -import { project } from '../__providers__/project' - -const ctx = konn() - .useBeforeEach(providers.dir()) - .useBeforeEach(providers.run()) - .useBeforeEach(project()) - .done() - -it('gentime setting output: custom directory', () => { - // ctx.fixture.use(Path.join(__dirname, 'fixtures/ncc')) - // ctx.runOrThrow(`${Path.join(process.cwd(), 'node_modules/.bin/yalc')} add ${ctx.thisPackageName}`) - // ctx.runOrThrow(`npm install --legacy-peer-deps`, { env: { PEER_DEPENDENCY_CHECK: 'false' } }) - // ctx.runOrThrowPackageScript(`build`) - // // Remove this to ensure that when the ncc build is run in the next step - // // it is truly running independent of any node_modules. - // ctx.fs.remove('node_modules') - // const result = ctx.runOrThrowPackageScript(`start:dist`, { env: { PEER_DEPENDENCY_CHECK: 'false' } }) - // expect(result.stdout).toMatchSnapshot() -}) diff --git a/tests/e2e/gentime-setting-output.test.ts b/tests/e2e/gentime-setting-output.test.ts new file mode 100644 index 000000000..afdd60f0c --- /dev/null +++ b/tests/e2e/gentime-setting-output.test.ts @@ -0,0 +1,18 @@ +import { konn, providers } from 'konn' +import * as Path from 'path' +import { project } from '../__providers__/project' + +const ctx = konn() + .useBeforeEach(providers.dir()) + .useBeforeEach(providers.run()) + .useBeforeEach(project()) + .done() + +it('gentime setting output: custom directory', () => { + ctx.fixture.use(Path.join(__dirname, 'fixtures/basic')) + ctx.runOrThrow(`${Path.join(process.cwd(), 'node_modules/.bin/yalc')} add ${ctx.thisPackageName}`) + ctx.runOrThrow(`npm install --legacy-peer-deps`, { env: { PEER_DEPENDENCY_CHECK: 'false' } }) + ctx.runOrThrow(`npx prisma generate`) + const result = ctx.runOrThrowPackageScript(`dev`, { env: { PEER_DEPENDENCY_CHECK: 'false' } }) + expect(result.stdout).toMatchSnapshot() +}) diff --git a/tests/e2e/ncc.test.ts b/tests/e2e/ncc.test.ts index 642b99fd6..3d95711ff 100644 --- a/tests/e2e/ncc.test.ts +++ b/tests/e2e/ncc.test.ts @@ -1,5 +1,4 @@ import { konn, providers } from 'konn' -import { Providers } from 'konn/providers' import * as Path from 'path' import { project } from '../__providers__/project' diff --git a/tsconfig.json b/tsconfig.json index 9bf7108a2..bf74c8458 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,7 +21,8 @@ // Only enable this for applications. // Packages doing this force their consumers to. // for pluralize which we will remove once @prisma/client exports externalToInternal DMMF transformer - "esModuleInterop": true + "esModuleInterop": true, + "resolveJsonModule": true }, "include": ["src", "tests", "scripts"], "exclude": ["dist-*", "tests/e2e/fixtures", "docs"] From 699bc83121ac00ea5a46ddc234f8306b4bf49b32 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Tue, 14 Dec 2021 20:20:43 +0000 Subject: [PATCH 18/25] add test showing config via psl file works --- .../e2e/__snapshots__/psl-output.test.ts.snap | 12 ++++++ tests/e2e/psl-output.test.ts | 43 +++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 tests/e2e/__snapshots__/psl-output.test.ts.snap create mode 100644 tests/e2e/psl-output.test.ts diff --git a/tests/e2e/__snapshots__/psl-output.test.ts.snap b/tests/e2e/__snapshots__/psl-output.test.ts.snap new file mode 100644 index 000000000..ab4ed9d0c --- /dev/null +++ b/tests/e2e/__snapshots__/psl-output.test.ts.snap @@ -0,0 +1,12 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`gentime setting output: custom directory 1`] = ` +"type Foo { + id: ID! +} + +type Query { + foos: [Foo] +} +" +`; diff --git a/tests/e2e/psl-output.test.ts b/tests/e2e/psl-output.test.ts new file mode 100644 index 000000000..8d25d5b22 --- /dev/null +++ b/tests/e2e/psl-output.test.ts @@ -0,0 +1,43 @@ +import { konn, providers } from 'konn' +import * as Path from 'path' +import { project } from '../__providers__/project' + +const ctx = konn() + .useBeforeEach(providers.dir()) + .useBeforeEach(providers.run()) + .useBeforeEach(project()) + .done() + +it('gentime setting output: custom directory', () => { + console.log(ctx.fs.cwd()) + ctx.fixture.use(Path.join(__dirname, 'fixtures/basic')) + ctx.fs.remove('prisma/nexus-prisma.ts') + ctx.fs.write( + 'prisma/schema.prisma', + ` + datasource db { + provider = "sqlite" + url = "file:./db.sqlite" + } + + generator client { + provider = "prisma-client-js" + } + + generator nexusPrisma { + provider = "nexus-prisma" + // Testing this. + output = "../generated/nexus-prisma" + } + + model Foo { + id String @id @default(cuid()) + } + ` + ) + ctx.runOrThrow(`${Path.join(process.cwd(), 'node_modules/.bin/yalc')} add ${ctx.thisPackageName}`) + ctx.runOrThrow(`npm install --legacy-peer-deps`, { env: { PEER_DEPENDENCY_CHECK: 'false' } }) + ctx.runOrThrow(`npx prisma generate`) + const result = ctx.runOrThrowPackageScript(`dev`, { env: { PEER_DEPENDENCY_CHECK: 'false' } }) + expect(result.stdout).toMatchSnapshot() +}) From f08854e5afff48235f2126200a931cca960f092f Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Wed, 15 Dec 2021 01:54:04 +0000 Subject: [PATCH 19/25] fix tests --- src/generator/generate.ts | 6 ++--- src/generator/gentime/settingsSingleton.ts | 20 -------------- src/generator/models/declaration.ts | 2 -- .../__snapshots__/enum.test.ts.snap | 3 +-- .../enumDocumentation.test.ts.snap | 12 +++------ .../modelDocumentation.test.ts.snap | 18 +++++-------- .../modelRelationFields.test.ts.snap | 3 +-- .../modelScalarFields.test.ts.snap | 27 +++++++------------ 8 files changed, 23 insertions(+), 68 deletions(-) diff --git a/src/generator/generate.ts b/src/generator/generate.ts index 7a9d976b5..5bb4fc777 100644 --- a/src/generator/generate.ts +++ b/src/generator/generate.ts @@ -102,7 +102,7 @@ export function generateRuntimeAndEmit(dmmf: DMMF.Document, settings: Gentime.Se const sourceFiles = [ ModelsGenerator.JS.createModuleSpec({ gentimeSettings: settings, - esm: settings.data.output?.moduleSystem === 'esm', + esm: false, dmmf, }), declarationSourceFile, @@ -113,9 +113,7 @@ export function generateRuntimeAndEmit(dmmf: DMMF.Document, settings: Gentime.Se sourceFiles.forEach((sf) => { const filePath = Path.join( settings.data.output.directory, - sf.fileName.endsWith('d.ts') - ? `${settings.data.output.name}.d.ts` - : `${settings.data.output.name}.${settings.data.output.type}` + sf.fileName.endsWith('d.ts') ? `${settings.data.output.name}.d.ts` : `${settings.data.output.name}.js` ) fs.remove(filePath) fs.write(filePath, sf.content) diff --git a/src/generator/gentime/settingsSingleton.ts b/src/generator/gentime/settingsSingleton.ts index 4f96935af..d323fc7e0 100644 --- a/src/generator/gentime/settingsSingleton.ts +++ b/src/generator/gentime/settingsSingleton.ts @@ -150,18 +150,6 @@ export namespace Gentime { * @default 'index' */ name?: string - /** - * The file extension to use for the generated runtime module. - * - * @default 'js' - */ - type?: 'ts' | 'js' - /** - * The module system to use for the generated runtime module. - * - * @default 'cjs' - */ - moduleSystem?: 'esm' | 'cjs' } } @@ -176,22 +164,14 @@ export namespace Gentime { initial: () => ({ directory: 'default', name: 'index', - type: 'ts', - moduleSystem: 'esm', }), fields: { directory: { initial: () => 'default', }, - moduleSystem: { - initial: () => 'cjs', - }, name: { initial: () => 'index', }, - type: { - initial: () => 'js', - }, }, }, projectIdIntToGraphQL: { diff --git a/src/generator/models/declaration.ts b/src/generator/models/declaration.ts index 130296217..6a775f9c2 100644 --- a/src/generator/models/declaration.ts +++ b/src/generator/models/declaration.ts @@ -127,8 +127,6 @@ export function renderTypeScriptDeclarationForDocumentModels( import { Runtime } from ${ settings.data.output.directory === 'default' ? `'../generator/runtime/settingsSingleton'` - : settings.data.output.moduleSystem === 'esm' - ? `'nexus-prisma/dist-esm/generator/runtime/settingsSingleton'` : `'nexus-prisma/dist-cjs/generator/runtime/settingsSingleton'` } diff --git a/tests/unit/typescriptDeclarationFile/__snapshots__/enum.test.ts.snap b/tests/unit/typescriptDeclarationFile/__snapshots__/enum.test.ts.snap index 0155074bc..50e68632c 100644 --- a/tests/unit/typescriptDeclarationFile/__snapshots__/enum.test.ts.snap +++ b/tests/unit/typescriptDeclarationFile/__snapshots__/enum.test.ts.snap @@ -1,8 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`An enum maps to a Nexus enum type definition: index.d.ts 1`] = ` -"import * as Nexus from 'nexus' -import * as NexusCore from 'nexus/dist/core' +"import * as NexusCore from 'nexus/dist/core' // // diff --git a/tests/unit/typescriptDeclarationFile/__snapshots__/enumDocumentation.test.ts.snap b/tests/unit/typescriptDeclarationFile/__snapshots__/enumDocumentation.test.ts.snap index da54056bb..512918310 100644 --- a/tests/unit/typescriptDeclarationFile/__snapshots__/enumDocumentation.test.ts.snap +++ b/tests/unit/typescriptDeclarationFile/__snapshots__/enumDocumentation.test.ts.snap @@ -1,8 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`When an enum has a documentation comment across lines, then they are joined and then used for the JSDoc of that field and its $description field: index.d.ts 1`] = ` -"import * as Nexus from 'nexus' -import * as NexusCore from 'nexus/dist/core' +"import * as NexusCore from 'nexus/dist/core' // // @@ -114,8 +113,7 @@ export const $settings: typeof Runtime.changeSettings `; exports[`When an enum has a documentation comment, then it is used for the JSDoc of that enum and its $description field: index.d.ts 1`] = ` -"import * as Nexus from 'nexus' -import * as NexusCore from 'nexus/dist/core' +"import * as NexusCore from 'nexus/dist/core' // // @@ -227,8 +225,7 @@ export const $settings: typeof Runtime.changeSettings `; exports[`When an enum has no documentation comment, and \`jsdocPropagationDefault\` is set to "none", then it does not get any default JSDoc and its description field is null: index.d.ts 1`] = ` -"import * as Nexus from 'nexus' -import * as NexusCore from 'nexus/dist/core' +"import * as NexusCore from 'nexus/dist/core' // // @@ -338,8 +335,7 @@ export const $settings: typeof Runtime.changeSettings `; exports[`When an enum has no documentation comment, then it gets the default JSDoc and its description field is null: index.d.ts 1`] = ` -"import * as Nexus from 'nexus' -import * as NexusCore from 'nexus/dist/core' +"import * as NexusCore from 'nexus/dist/core' // // diff --git a/tests/unit/typescriptDeclarationFile/__snapshots__/modelDocumentation.test.ts.snap b/tests/unit/typescriptDeclarationFile/__snapshots__/modelDocumentation.test.ts.snap index 9dfd875d9..26759b6df 100644 --- a/tests/unit/typescriptDeclarationFile/__snapshots__/modelDocumentation.test.ts.snap +++ b/tests/unit/typescriptDeclarationFile/__snapshots__/modelDocumentation.test.ts.snap @@ -1,8 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`When a model field has a documentation comment across lines, then they are joined and then used for the JSDoc of that field and its $description field: index.d.ts 1`] = ` -"import * as Nexus from 'nexus' -import * as NexusCore from 'nexus/dist/core' +"import * as NexusCore from 'nexus/dist/core' // // @@ -158,8 +157,7 @@ export const $settings: typeof Runtime.changeSettings `; exports[`When a model field has a documentation comment, then it is used for the JSDoc of that field and its $description field: index.d.ts 1`] = ` -"import * as Nexus from 'nexus' -import * as NexusCore from 'nexus/dist/core' +"import * as NexusCore from 'nexus/dist/core' // // @@ -327,8 +325,7 @@ export const $settings: typeof Runtime.changeSettings `; exports[`When a model field has no documentation comment, then it gets the default JSDoc and its description field is null: index.d.ts 1`] = ` -"import * as Nexus from 'nexus' -import * as NexusCore from 'nexus/dist/core' +"import * as NexusCore from 'nexus/dist/core' // // @@ -507,8 +504,7 @@ export const $settings: typeof Runtime.changeSettings `; exports[`When a model has a documentation comment, then it is used for the JSDoc of that model and its $description field: index.d.ts 1`] = ` -"import * as Nexus from 'nexus' -import * as NexusCore from 'nexus/dist/core' +"import * as NexusCore from 'nexus/dist/core' // // @@ -675,8 +671,7 @@ export const $settings: typeof Runtime.changeSettings `; exports[`When a model has no documentation comment, then it gets the default JSDoc and its description field is null: index.d.ts 1`] = ` -"import * as Nexus from 'nexus' -import * as NexusCore from 'nexus/dist/core' +"import * as NexusCore from 'nexus/dist/core' // // @@ -855,8 +850,7 @@ export const $settings: typeof Runtime.changeSettings `; exports[`When a model or model field has no documentation comment, and \`jsdocPropagationDefault\` is set to "none", then it does not get any default JSDoc and its description field is null: index.d.ts 1`] = ` -"import * as Nexus from 'nexus' -import * as NexusCore from 'nexus/dist/core' +"import * as NexusCore from 'nexus/dist/core' // // diff --git a/tests/unit/typescriptDeclarationFile/__snapshots__/modelRelationFields.test.ts.snap b/tests/unit/typescriptDeclarationFile/__snapshots__/modelRelationFields.test.ts.snap index 2b22feeff..f856073ea 100644 --- a/tests/unit/typescriptDeclarationFile/__snapshots__/modelRelationFields.test.ts.snap +++ b/tests/unit/typescriptDeclarationFile/__snapshots__/modelRelationFields.test.ts.snap @@ -1,8 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`A model relation field projects a default resolve function: index.d.ts 1`] = ` -"import * as Nexus from 'nexus' -import * as NexusCore from 'nexus/dist/core' +"import * as NexusCore from 'nexus/dist/core' // // diff --git a/tests/unit/typescriptDeclarationFile/__snapshots__/modelScalarFields.test.ts.snap b/tests/unit/typescriptDeclarationFile/__snapshots__/modelScalarFields.test.ts.snap index d496788d2..5367ef6fe 100644 --- a/tests/unit/typescriptDeclarationFile/__snapshots__/modelScalarFields.test.ts.snap +++ b/tests/unit/typescriptDeclarationFile/__snapshots__/modelScalarFields.test.ts.snap @@ -1,8 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`A model field with type BigInt maps to GraphQL BigInt custom scalar: index.d.ts 1`] = ` -"import * as Nexus from 'nexus' -import * as NexusCore from 'nexus/dist/core' +"import * as NexusCore from 'nexus/dist/core' // // @@ -233,8 +232,7 @@ export const $settings: typeof Runtime.changeSettings `; exports[`A model field with type Boolean maps to GraphQL Boolean scalar: index.d.ts 1`] = ` -"import * as Nexus from 'nexus' -import * as NexusCore from 'nexus/dist/core' +"import * as NexusCore from 'nexus/dist/core' // // @@ -465,8 +463,7 @@ export const $settings: typeof Runtime.changeSettings `; exports[`A model field with type Bytes maps to GraphQL Bytes custom scalar: index.d.ts 1`] = ` -"import * as Nexus from 'nexus' -import * as NexusCore from 'nexus/dist/core' +"import * as NexusCore from 'nexus/dist/core' // // @@ -697,8 +694,7 @@ export const $settings: typeof Runtime.changeSettings `; exports[`A model field with type DateTime maps to GraphQL DateTime custom scalar: index.d.ts 1`] = ` -"import * as Nexus from 'nexus' -import * as NexusCore from 'nexus/dist/core' +"import * as NexusCore from 'nexus/dist/core' // // @@ -929,8 +925,7 @@ export const $settings: typeof Runtime.changeSettings `; exports[`A model field with type Float maps to GraphQL Float scalar: index.d.ts 1`] = ` -"import * as Nexus from 'nexus' -import * as NexusCore from 'nexus/dist/core' +"import * as NexusCore from 'nexus/dist/core' // // @@ -1161,8 +1156,7 @@ export const $settings: typeof Runtime.changeSettings `; exports[`A model field with type Int maps to GraphQL Int scalar: index.d.ts 1`] = ` -"import * as Nexus from 'nexus' -import * as NexusCore from 'nexus/dist/core' +"import * as NexusCore from 'nexus/dist/core' // // @@ -1393,8 +1387,7 @@ export const $settings: typeof Runtime.changeSettings `; exports[`A model field with type Int, attribute @id, maps to GraphQL Int scalar: index.d.ts 1`] = ` -"import * as Nexus from 'nexus' -import * as NexusCore from 'nexus/dist/core' +"import * as NexusCore from 'nexus/dist/core' // // @@ -1573,8 +1566,7 @@ export const $settings: typeof Runtime.changeSettings `; exports[`A model field with type Json maps to GraphQL Json custom scalar: index.d.ts 1`] = ` -"import * as Nexus from 'nexus' -import * as NexusCore from 'nexus/dist/core' +"import * as NexusCore from 'nexus/dist/core' // // @@ -1805,8 +1797,7 @@ export const $settings: typeof Runtime.changeSettings `; exports[`A model field with type String, attribute @id, maps to GraphQL ID scalar: index.d.ts 1`] = ` -"import * as Nexus from 'nexus' -import * as NexusCore from 'nexus/dist/core' +"import * as NexusCore from 'nexus/dist/core' // // From 0c86054ea0aad08bc399be3d559a9086a4791094 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Wed, 15 Dec 2021 02:02:04 +0000 Subject: [PATCH 20/25] remove unused code --- src/cli/nexus-prisma.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/cli/nexus-prisma.ts b/src/cli/nexus-prisma.ts index ac4319c06..7a1e238b6 100755 --- a/src/cli/nexus-prisma.ts +++ b/src/cli/nexus-prisma.ts @@ -159,7 +159,3 @@ function getPrismaClientImportIdForItsGeneratorOutputConfig( return prismaClientGeneratorConfig.output.value } - -const absoluteify = (path: string, prefixAbsolutePath: string) => { - return Path.isAbsolute(path) ? path : Path.join(prefixAbsolutePath, path) -} From b69062458b56a476f2b23f791ac02fd7969af5cb Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Wed, 15 Dec 2021 02:21:18 +0000 Subject: [PATCH 21/25] update docs to mention gen block based config --- docs/pages/settings-gentime.md | 29 +++++++++++++++++++++++++++++ src/cli/nexus-prisma.ts | 10 +++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/docs/pages/settings-gentime.md b/docs/pages/settings-gentime.md index 910e20eed..70e37ec38 100644 --- a/docs/pages/settings-gentime.md +++ b/docs/pages/settings-gentime.md @@ -41,3 +41,32 @@ You are able to control certain aspects of the Nexus Prisma code generation. ## Reference Please refer to the thorough JSDoc for reference documentation. Typically consumed in your IDE or [Paka](https://paka.dev/npm/nexus-prisma). + +## Notes + +### Prisma Schema File Generator Config + +Nexus Prisma supports custom configuration of the output directory within the generator block within your Prisma Schema file like so: + +``` +// prisma/schema.prisma + +generator nexusPrisma { + provider = "nexus-prisma" + output = "../generated/nexus-prisma" +} +``` + +The above is equivalent to the following: + +```ts +// prisma/nexus-prisma.ts + +import { settings } from 'nexus-prisma/generator' + +settings.change({ + output: '../generated/nexus-prisma', +}) +``` + +It is considered idiomatic to use the Nexus Prisma configuration file instead of inline generator block configuration. Inline generator block configuration lacks autocomplete and inline JSDoc. The only reason `output` is supported is to be [symmetrical with Prisma Client](https://www.prisma.io/docs/concepts/components/prisma-client/working-with-prismaclient/generating-prisma-client#the-location-of-prisma-client) and thus ease onboarding. diff --git a/src/cli/nexus-prisma.ts b/src/cli/nexus-prisma.ts index 7a1e238b6..aefc4a434 100755 --- a/src/cli/nexus-prisma.ts +++ b/src/cli/nexus-prisma.ts @@ -13,6 +13,7 @@ import { Gentime } from '../generator/gentime/settingsSingleton' import { d } from '../helpers/debugNexusPrisma' import { externalToInternalDmmf } from '../helpers/prismaExternalToInternalDMMF' import { resolveGitHubActionsWindowsPathTilde } from '../helpers/utils' +import { renderWarning } from '../lib/diagnostic' // todo by default error in ci and warn in local // enforceValidPeerDependencies({ @@ -39,7 +40,6 @@ generatorHandler({ ) } - // TODO If the user is using nexus-prisma.ts then that should be the preferred source for this configuration because it is type safe. Give them a warning so they are aware. if (generator.isCustomOutput) { if (!generator.output) { throw new Error(`Failed to read the custom output path.`) @@ -49,6 +49,14 @@ generatorHandler({ directory: generator.output.value, }, }) + console.log( + renderWarning({ + code: `nexus_prisma_prefer_config_file`, + title: `It is preferred to use the Nexus Prisma configuration file to set the output directory.`, + reason: `Using the Nexus Prisma configuration file gives you access to autocomplete, type safety, and inline JSDoc documentation.`, + consequence: `Your developer experience may be degraded.`, + }) + ) } // WARNING: Make sure this logic comes before `loadUserGentimeSettings` below From 255ea4cf641f202d20936b88c6304a7c16f02b85 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Wed, 15 Dec 2021 02:49:31 +0000 Subject: [PATCH 22/25] output warning when using psl config --- src/cli/nexus-prisma.ts | 22 ++++++-- src/generator/gentime/settingsLoader.ts | 52 ++++++++++++------- src/lib/diagnostic.ts | 28 +++++++--- ...> gentime-setting-output-psl.test.ts.snap} | 0 ....ts => gentime-setting-output-psl.test.ts} | 1 - 5 files changed, 71 insertions(+), 32 deletions(-) rename tests/e2e/__snapshots__/{psl-output.test.ts.snap => gentime-setting-output-psl.test.ts.snap} (100%) rename tests/e2e/{psl-output.test.ts => gentime-setting-output-psl.test.ts} (97%) diff --git a/src/cli/nexus-prisma.ts b/src/cli/nexus-prisma.ts index aefc4a434..9fbbd6c2d 100755 --- a/src/cli/nexus-prisma.ts +++ b/src/cli/nexus-prisma.ts @@ -5,15 +5,16 @@ process.env.DEBUG_COLORS = 'true' process.env.DEBUG_HIDE_DATE = 'true' import { GeneratorConfig, generatorHandler } from '@prisma/generator-helper' +import dindist from 'dindist' import expandTilde from 'expand-tilde' import * as Path from 'path' import { generateRuntimeAndEmit } from '../generator' -import { loadUserGentimeSettings } from '../generator/gentime/settingsLoader' +import { loadUserGentimeSettings, supportedSettingsModulePaths } from '../generator/gentime/settingsLoader' import { Gentime } from '../generator/gentime/settingsSingleton' import { d } from '../helpers/debugNexusPrisma' import { externalToInternalDmmf } from '../helpers/prismaExternalToInternalDMMF' import { resolveGitHubActionsWindowsPathTilde } from '../helpers/utils' -import { renderWarning } from '../lib/diagnostic' +import { renderCodeBlock, renderList, renderWarning } from '../lib/diagnostic' // todo by default error in ci and warn in local // enforceValidPeerDependencies({ @@ -44,18 +45,29 @@ generatorHandler({ if (!generator.output) { throw new Error(`Failed to read the custom output path.`) } + Gentime.changeSettings({ output: { directory: generator.output.value, }, }) - console.log( + + // TODO capture this output in a test + process.stdout.write( + // prettier-ignore renderWarning({ code: `nexus_prisma_prefer_config_file`, title: `It is preferred to use the Nexus Prisma configuration file to set the output directory.`, - reason: `Using the Nexus Prisma configuration file gives you access to autocomplete, type safety, and inline JSDoc documentation.`, + reason: `Using the Nexus Prisma configuration file gives you access to autocomplete and inline JSDoc documentation.`, consequence: `Your developer experience may be degraded.`, - }) + solution: `Create a configuration file in one of the following locations:\n\n${renderList(supportedSettingsModulePaths)}\n\nThen add the following code:\n\n${renderCodeBlock(dindist` + import { settings } from 'nexus-prisma/generator' + + settings.change({ + output: '${generator.output.value}' + }) + `)}`, + }) + '\n' ) } diff --git a/src/generator/gentime/settingsLoader.ts b/src/generator/gentime/settingsLoader.ts index 5ef4b6775..3c140c73b 100644 --- a/src/generator/gentime/settingsLoader.ts +++ b/src/generator/gentime/settingsLoader.ts @@ -1,20 +1,40 @@ import * as fs from 'fs' +import * as Path from 'path' import kleur from 'kleur' import type * as TSNode from 'ts-node' import { d } from '../../helpers/debugNexusPrisma' -import { renderError } from '../../lib/diagnostic' +import { renderError, renderWarning } from '../../lib/diagnostic' + +export const supportedSettingsModulePaths = [ + 'nexus-prisma.ts', + 'nexusPrisma.ts', + 'nexus_prisma.ts', + 'prisma/nexus-prisma.ts', + 'prisma/nexusPrisma.ts', + 'prisma/nexus_prisma.ts', +] export function loadUserGentimeSettings(): void { - const userSettingsModulePath = pickFirstExisting( - [ - 'nexus-prisma.ts', - 'nexusPrisma.ts', - 'nexus_prisma.ts', - 'prisma/nexus-prisma.ts', - 'prisma/nexusPrisma.ts', - 'prisma/nexus_prisma.ts', - ].map((path) => `${process.cwd()}/${path}`) - ) + const relativeToPath = process.cwd() + const userSettingsModulePaths = supportedSettingsModulePaths + .map((relativePath) => `${relativeToPath}/${relativePath}`) + .filter((absolutePath) => fs.existsSync(absolutePath)) + + const userSettingsModulePath = userSettingsModulePaths[0] + + // if (userSettingsModulePaths.length > 1) { + // console.log( + // // prettier-ignore + // renderWarning({ + // code: `nexus_prisma_multiple_configuration_files`, + // title: `Found multiple configuration files`, + // reason: `Nexus Prisma looks for an optional configuration file in the following places: ${supportedSettingsModulePaths.join(', ')}. You can only have zero or one of these files present, but you had multiple: ${userSettingsModulePaths.map((_) => Path.relative(relativeToPath, _)).join(', ')}.`, + // // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- We know there are multiple in this branch so a first must have been found. + // consequence: `Nexus Prisma is only looking at ${Path.relative(relativeToPath, userSettingsModulePath!)} and ignoring all others.`, + // solution: `Remove all or but one of the configuration files.` + // }) + // ) + // } if (userSettingsModulePath) { // Now that we know a TS config file is present, try loading ts-node @@ -29,13 +49,13 @@ export function loadUserGentimeSettings(): void { const tsNode = `${kleur.yellow(`ts-node`)}` console.log( renderError({ + code: 'nexus_prisma_ts_node_import', title: `Failed to read configuration module`, reason: `${nexusPrisma} uses ${tsNode} to read your generator configuration module, but there was an error while trying to import ${tsNode}: ${ error instanceof Error ? error.message : String(error) }`, consequence: `${nexusPrisma} will stop generation.`, solution: `Fix the ${tsNode} import error (missing dependency?) or stop using ${nexusPrisma} generator configuration module.`, - code: 'nexus_prisma_ts_node_import', }) ) @@ -55,11 +75,3 @@ export function loadUserGentimeSettings(): void { require(userSettingsModulePath) } } - -function pickFirstExisting(paths: string[]): null | string { - return ( - paths.find((path) => { - return fs.existsSync(path) - }) ?? null - ) -} diff --git a/src/lib/diagnostic.ts b/src/lib/diagnostic.ts index 5c258eccb..93a05797c 100644 --- a/src/lib/diagnostic.ts +++ b/src/lib/diagnostic.ts @@ -9,16 +9,32 @@ type DiagnosticInfo = { disable?: string } +export const renderList = (items: string[]): string => { + return items.map((item) => `→ ${item}`).join('\n') +} + +export const renderTitle = (title: string) => { + return `${kleur.bold(title.toUpperCase())}:` +} + export function renderError(params: DiagnosticInfo): string { - const solution = params.solution ? `\n\nSOLUTION: ${params.solution}` : '' - const disable = params.disable ? `\n\nHOW TO DISABLE: ${params.disable}` : '' + const solution = params.solution ? `\n\n${renderTitle('solution')} ${params.solution}` : '' + const disable = params.disable ? `\n\n${renderTitle('how to disable')} ${params.disable}` : '' // prettier-ignore - return `${kleur.red('ERROR:')} ${params.title}\n\nREASON: ${params.reason}\n\nCONSEQUENCE: ${params.consequence}${solution}${disable}\n\nCODE: ${params.code}` + return `${kleur.red(renderTitle('error'))} ${params.title}\n\n${renderTitle('reason')} ${params.reason}\n\n${renderTitle('consequence')} ${params.consequence}${solution}${disable}\n\n${renderTitle('code')}: ${params.code}` } export function renderWarning(params: DiagnosticInfo): string { - const solution = params.solution ? `\n\nSOLUTION: ${params.solution}` : '' - const disable = params.disable ? `\n\nHOW TO DISABLE: ${params.disable}` : '' + const solution = params.solution ? `\n\n${renderTitle('solution')} ${params.solution}` : '' + const disable = params.disable ? `\n\n${renderTitle('how to disable')} ${params.disable}` : '' // prettier-ignore - return `${kleur.yellow('WARNING:')} ${params.title}\n\nREASON: ${params.reason}\n\nCONSEQUENCE: ${params.consequence}${solution}${disable}\n\nCODE: ${params.code}` + return `${kleur.yellow(renderTitle('warning'))} ${params.title}\n\n${renderTitle('reason')}: ${params.reason}\n\n${renderTitle('consequence')} ${params.consequence}${solution}${disable}\n\n${renderTitle('code')} ${params.code}` +} + +export const renderCodeInline = (code: string): string => { + return `\`${kleur.cyan(code)}\`` +} + +export const renderCodeBlock = (code: string): string => { + return `\`\`\`\n${kleur.cyan(code)}\n\`\`\`` } diff --git a/tests/e2e/__snapshots__/psl-output.test.ts.snap b/tests/e2e/__snapshots__/gentime-setting-output-psl.test.ts.snap similarity index 100% rename from tests/e2e/__snapshots__/psl-output.test.ts.snap rename to tests/e2e/__snapshots__/gentime-setting-output-psl.test.ts.snap diff --git a/tests/e2e/psl-output.test.ts b/tests/e2e/gentime-setting-output-psl.test.ts similarity index 97% rename from tests/e2e/psl-output.test.ts rename to tests/e2e/gentime-setting-output-psl.test.ts index 8d25d5b22..7e9ef0617 100644 --- a/tests/e2e/psl-output.test.ts +++ b/tests/e2e/gentime-setting-output-psl.test.ts @@ -9,7 +9,6 @@ const ctx = konn() .done() it('gentime setting output: custom directory', () => { - console.log(ctx.fs.cwd()) ctx.fixture.use(Path.join(__dirname, 'fixtures/basic')) ctx.fs.remove('prisma/nexus-prisma.ts') ctx.fs.write( From 11c5e834d1ee32389cb29e8f79535cd0fe16f20e Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Wed, 15 Dec 2021 02:53:51 +0000 Subject: [PATCH 23/25] fix lint --- src/generator/gentime/settingsLoader.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/generator/gentime/settingsLoader.ts b/src/generator/gentime/settingsLoader.ts index 3c140c73b..ee0ac16f0 100644 --- a/src/generator/gentime/settingsLoader.ts +++ b/src/generator/gentime/settingsLoader.ts @@ -1,9 +1,8 @@ import * as fs from 'fs' -import * as Path from 'path' import kleur from 'kleur' import type * as TSNode from 'ts-node' import { d } from '../../helpers/debugNexusPrisma' -import { renderError, renderWarning } from '../../lib/diagnostic' +import { renderError } from '../../lib/diagnostic' export const supportedSettingsModulePaths = [ 'nexus-prisma.ts', @@ -22,6 +21,7 @@ export function loadUserGentimeSettings(): void { const userSettingsModulePath = userSettingsModulePaths[0] + // TODO // if (userSettingsModulePaths.length > 1) { // console.log( // // prettier-ignore From f02391bad0f7abeef66286859362e338eb614ccf Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Wed, 15 Dec 2021 03:09:43 +0000 Subject: [PATCH 24/25] fix rendering --- src/lib/diagnostic.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/diagnostic.ts b/src/lib/diagnostic.ts index 93a05797c..33e7a4993 100644 --- a/src/lib/diagnostic.ts +++ b/src/lib/diagnostic.ts @@ -21,14 +21,14 @@ export function renderError(params: DiagnosticInfo): string { const solution = params.solution ? `\n\n${renderTitle('solution')} ${params.solution}` : '' const disable = params.disable ? `\n\n${renderTitle('how to disable')} ${params.disable}` : '' // prettier-ignore - return `${kleur.red(renderTitle('error'))} ${params.title}\n\n${renderTitle('reason')} ${params.reason}\n\n${renderTitle('consequence')} ${params.consequence}${solution}${disable}\n\n${renderTitle('code')}: ${params.code}` + return `${kleur.red(renderTitle('error'))} ${params.title}\n\n${renderTitle('reason')} ${params.reason}\n\n${renderTitle('consequence')} ${params.consequence}${solution}${disable}\n\n${renderTitle('code')} ${params.code}` } export function renderWarning(params: DiagnosticInfo): string { const solution = params.solution ? `\n\n${renderTitle('solution')} ${params.solution}` : '' const disable = params.disable ? `\n\n${renderTitle('how to disable')} ${params.disable}` : '' // prettier-ignore - return `${kleur.yellow(renderTitle('warning'))} ${params.title}\n\n${renderTitle('reason')}: ${params.reason}\n\n${renderTitle('consequence')} ${params.consequence}${solution}${disable}\n\n${renderTitle('code')} ${params.code}` + return `${kleur.yellow(renderTitle('warning'))} ${params.title}\n\n${renderTitle('reason')} ${params.reason}\n\n${renderTitle('consequence')} ${params.consequence}${solution}${disable}\n\n${renderTitle('code')} ${params.code}` } export const renderCodeInline = (code: string): string => { From 1c2a861af208b68e686a5cd8e509f6f90c4b7ecf Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Wed, 15 Dec 2021 03:22:52 +0000 Subject: [PATCH 25/25] fix jsdoc --- src/generator/gentime/settingsSingleton.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/generator/gentime/settingsSingleton.ts b/src/generator/gentime/settingsSingleton.ts index d323fc7e0..d3c452c05 100644 --- a/src/generator/gentime/settingsSingleton.ts +++ b/src/generator/gentime/settingsSingleton.ts @@ -83,26 +83,21 @@ export namespace Gentime { */ prismaClientImportId?: string /** - * Configure various details about the Nexus Prisma generated runtime such as file location, name, type - * and module system to use. + * Configure various details about the Nexus Prisma generated runtime such as file name and location. * * By default is output into the installed node_modules location of Nexus Prisma itself and supports both * ESM and CJS. * - * If you explicitly configure this setting, then you can only output ESM _or_ CJS, not both, - * since as the project maintainer you will be in a position to know which one you want to use. - * * The following files will be output into the target directory: * * ``` - * Description | Default Name | Default Extension | + * Description | Default Name | Extension | * ---------------------------------------------------- - * A runtime file | index | .ts | + * A runtime file | index | .js | * A type file | index | .d.ts | * ``` * - * Passing `string` is a path to the target directory to output to, shorthand for `{ directory: string, - * moduleSystem: 'esm', type: 'ts' }` + * Passing `string` is a path to the target directory to output to, shorthand for `{ directory: string }` * * If a relative path is given then it is considered relative to the Prisma Schema file. *