From eec4932f83065e46ff92cac75108dff3a34b15d9 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Fri, 27 Aug 2021 22:56:48 -0400 Subject: [PATCH] feat: esm support (#127) --- .eslintignore | 5 +- .eslintrc | 2 +- .gitignore | 2 +- .prettierignore | 3 +- CONTRIBUTING.md | 2 +- README.md | 10 +++ jest.config.e2e.ts | 9 ++ jest.config.ts | 21 ++--- jest.config.unit.ts | 9 ++ package.json | 63 +++++++++----- scripts/build-module-facades.ts | 52 ------------ src/{index.ts => entrypoints/main.ts} | 6 +- src/generator/generate.ts | 70 ++++++++++++--- src/generator/models/javascript.ts | 85 ++++++++++++++++--- src/helpers/prisma.ts | 2 +- src/lib/diagnostic.ts | 2 +- src/lib/peerDepValidator.ts | 2 +- tests/__helpers__/helpers.ts | 9 +- tests/__helpers__/testers.ts | 13 ++- .../__snapshots__/kitchen-sink.test.ts.snap | 6 +- tests/e2e/kitchen-sink.test.ts | 12 ++- tests/integration/json.test.ts | 2 +- tests/lib/peerDepValidator.test.ts | 5 +- tests/specs.ts | 2 +- tests/tsconfig.json | 10 --- tests/unit/graphqlSchema/json.test.ts | 2 +- tsconfig.base.json | 34 -------- tsconfig.cjs.json | 12 +++ tsconfig.esm.json | 12 +++ tsconfig.json | 30 +++++-- yarn.lock | 13 ++- 31 files changed, 318 insertions(+), 189 deletions(-) create mode 100644 jest.config.e2e.ts create mode 100644 jest.config.unit.ts delete mode 100644 scripts/build-module-facades.ts rename src/{index.ts => entrypoints/main.ts} (73%) delete mode 100644 tests/tsconfig.json delete mode 100644 tsconfig.base.json create mode 100644 tsconfig.cjs.json create mode 100644 tsconfig.esm.json diff --git a/.eslintignore b/.eslintignore index 8a6432729..39f2ed177 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,7 +2,6 @@ .vscode .github node_modules -dist -dist-esm +dist-* tests -jest.config.ts +jest.config.* diff --git a/.eslintrc b/.eslintrc index ed68158d0..df820fad8 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,7 +2,7 @@ "root": true, "parser": "@typescript-eslint/parser", "parserOptions": { - "project": ["tsconfig.json", "tests/tsconfig.json"] + "project": ["tsconfig.json"] }, "plugins": ["@typescript-eslint", "only-warn"], "extends": [ diff --git a/.gitignore b/.gitignore index d648379cc..0ea902a0d 100644 --- a/.gitignore +++ b/.gitignore @@ -80,7 +80,7 @@ typings/ # Nuxt.js build / generate output .nuxt -dist +dist-* # Gatsby files .cache/ diff --git a/.prettierignore b/.prettierignore index 009af5438..8a150da4f 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,3 @@ -dist +dist-cjs +dist-esm coverage diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c67f9f77d..880f17f59 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -47,7 +47,7 @@ Every-time: With all this in place, the chain reaction goes like this: 1. You change `Nexus Prisma` -1. `Nexus Prisma` TS in watch mode emits into `dist` +1. `Nexus Prisma` TS in watch mode emits into `dist-esm` and `dist-cjs` 1. `Nexus Prisma` `nodemon` reacts to this, runs `yalc push`, Yalc emits into `Project`'s `.yalc` dir 1. `Project` `nodemon` reacts to this, runs `prisma generate` 1. You try things out with newly generated Nexus Prisma in `Project`! diff --git a/README.md b/README.md index 1a56b4a1c..d3929a984 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Official Prisma plugin for Nexus. - [Prisma Schema Docs Propagation](#prisma-schema-docs-propagation) - [As GraphQL schema doc](#as-graphql-schema-doc) - [As JSDoc](#as-jsdoc) + - [ESM Support](#esm-support) - [Refined DX](#refined-dx) - [Recipes](#recipes) - [Project relation with custom resolver logic](#project-relation-with-custom-resolver-logic) @@ -45,6 +46,7 @@ Official Prisma plugin for Nexus. - [For users of `nexus@=<1.0`](#for-users-of-nexus10) - [Supported Versions Of Node](#supported-versions-of-node) - [Supported Versions Of `@prisma/client`](#supported-versions-of-prismaclient) + - [Supported Versions Of `ts-node`](#supported-versions-of-ts-node) - [Matrix Testing Policy](#matrix-testing-policy) - [Patch Version Support Policy](#patch-version-support-policy) @@ -796,6 +798,14 @@ User // JSDoc: A user. User.id // JSDoc: A stable identifier to find users by. ``` +### 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: + +- We publish both a CJS and ESM build to npm. +- 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 These are finer points that aren't perhaps worth a top-level point but none the less add up toward a thoughtful developer experience. diff --git a/jest.config.e2e.ts b/jest.config.e2e.ts new file mode 100644 index 000000000..0e2487f4b --- /dev/null +++ b/jest.config.e2e.ts @@ -0,0 +1,9 @@ +import type { InitialOptionsTsJest } from 'ts-jest/dist/types' + +const config: InitialOptionsTsJest = { + preset: 'ts-jest', + displayName: 'e2e', + testMatch: ['**/e2e/**/*.test.ts'], +} + +export default config diff --git a/jest.config.ts b/jest.config.ts index ac87dbb06..69884a3c4 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -2,23 +2,14 @@ import type { InitialOptionsTsJest } from 'ts-jest/dist/types' const config: InitialOptionsTsJest = { preset: 'ts-jest', - watchPlugins: ['jest-watch-typeahead/filename', 'jest-watch-typeahead/testname'], - testPathIgnorePatterns: process.env.CI ? [] : ['.*e2e.*'], - globals: { - 'ts-jest': { - diagnostics: Boolean(process.env.CI) - ? { - // For some reason we get these diagnostic errors in CI but only sometimes - // locally and never in editor. Furthermore the errors are invalid since they are - // explicit any not implicit any! Example error in CI https://github.com/prisma/nexus-prisma/runs/2613820675#step:9:408 - ignoreCodes: [7006, 7031], - } - : false, - tsconfig: '/tests/tsconfig.json', - }, - }, + watchPlugins: [ + 'jest-watch-typeahead/filename', + 'jest-watch-typeahead/testname', + 'jest-watch-select-projects', + ], collectCoverageFrom: ['src/**/*'], coverageReporters: ['lcov', 'text', 'html'], + projects: [`/jest.config.e2e.ts`, `/jest.config.unit.ts`], } export default config diff --git a/jest.config.unit.ts b/jest.config.unit.ts new file mode 100644 index 000000000..acf0373e9 --- /dev/null +++ b/jest.config.unit.ts @@ -0,0 +1,9 @@ +import type { InitialOptionsTsJest } from 'ts-jest/dist/types' + +const config: InitialOptionsTsJest = { + preset: 'ts-jest', + displayName: 'unit', + testMatch: ['**/unit/**/*.test.ts', '**/lib/**/*.test.ts', '**/integration/**/*.test.ts'], +} + +export default config diff --git a/package.json b/package.json index 2dd929c26..5523b85b7 100644 --- a/package.json +++ b/package.json @@ -1,23 +1,44 @@ { "name": "nexus-prisma", "version": "0.0.0-dripip", - "main": "dist/index.js", + "main": "./dist-cjs/entrypoints/main.js", "repository": "git@github.com:prisma/nexus-prisma.git", "author": "Jason Kuhrt", "license": "MIT", "files": [ - "dist", - "plugin.js", - "plugin.d.ts", - "scalars.js", - "scalars.d.ts", - "settings.d.ts", - "settings.js", - "generator.d.ts", - "generator.js" + "dist-cjs", + "dist-esm" ], + "exports": { + ".": { + "require": "./dist-cjs/entrypoints/main.js", + "import": "./dist-esm/entrypoints/main.js" + }, + "./scalars": { + "require": "./dist-cjs/entrypoints/scalars.js", + "import": "./dist-esm/entrypoints/scalars.js" + }, + "./generator": { + "require": "./dist-cjs/entrypoints/generator.js", + "import": "./dist-esm/entrypoints/generator.js" + } + }, + "types": "./dist-cjs/entrypoints/main.d.ts", + "typesVersions": { + "*": { + "*": [ + "./dist-cjs/entrypoints/main.d.ts" + ], + "scalars": [ + "./dist-cjs/entrypoints/scalars.d.ts" + ], + "generator": [ + "./dist-cjs/entrypoints/generator.d.ts" + ] + } + }, "bin": { - "nexus-prisma": "./dist/cli/nexus-prisma.js" + "nexus-prisma": "./dist-cjs/cli/nexus-prisma.js" }, "scripts": { "reflect:toc": "markdown-toc README.md -i --maxdepth 4 && prettier --write README.md", @@ -25,16 +46,17 @@ "format:check": "prettier --check .", "lint": "eslint . --ext .ts,.tsx --fix", "lint:check": "eslint . --ext .ts,.tsx --max-warnings 0", - "dev": "tsc --build --watch", + "dev": "yarn -s clean && tsc --build --watch tsconfig.cjs.json tsconfig.esm.json", "dev:ts": "yarn dev", - "dev:yalc": "nodemon --delay 1.5 --exec 'yalc push --no-scripts' --watch 'dist/**/*'", - "build:module-facades": "ts-node scripts/build-module-facades", - "build": "yarn clean && yarn build:module-facades && tsc", - "test": "cross-env DEBUG=e2e jest", - "test:ci": "cross-env DEBUG='e2e' jest --coverage --forceExit --runInBand", - "tdd": "jest --watch", - "tdd:e2e:debug": "cross-env test_project_reuse=true jest --watch e2e", - "clean": "rm -rf dist && rm -rf node_modules/.cache", + "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: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", + "tdd": "jest --selectProjects unit --watch", + "tdd:e2e:debug": "cross-env test_project_reuse=true jest --selectProjects e2e --watch", + "clean": "rm -rf dist-cjs dist-esm node_modules/.cache", "release:pr": "dripip pr", "release:canary": "dripip preview", "release:stable": "dripip stable", @@ -66,6 +88,7 @@ "graphql-request": "^3.5.0", "graphql-tag": "^2.12.5", "jest": "27.0.6", + "jest-watch-select-projects": "^2.0.0", "jest-watch-typeahead": "0.6.4", "markdown-toc": "^1.2.0", "nexus": "^1.1.0", diff --git a/scripts/build-module-facades.ts b/scripts/build-module-facades.ts deleted file mode 100644 index bb85203f4..000000000 --- a/scripts/build-module-facades.ts +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Module Facades - * - * This script builds the modules that will be consumed publically. They front the actual code inside ./dist. - * The problem being solved here is that it allows consumers to do e.g. this: - * - * Import { ... } from 'nexus/testing' - * - * Instead of: - * - * Import { ... } from 'nexus/dist/testing' - * - * Whatever modules are written here should be: - * - * 1. ignored in .gitignore. - * 2. added to the package.json files array - */ - -import * as fs from 'fs-jetpack' -import * as lo from 'lodash' -import * as os from 'os' -import * as path from 'path' -import { PackageJson } from 'type-fest' - -generateModuleFacades([ - ['scalars.d.ts', "export * from './dist/entrypoints/scalars'"], - ['scalars.js', "module.exports = require('./dist/entrypoints/scalars')"], - - ['generator.d.ts', "export * from './dist/entrypoints/generator'"], - ['generator.js', "module.exports = require('./dist/entrypoints/generator')"], -]) - -function generateModuleFacades(facades: ModuleFacade[]) { - // Write facade files - - for (const facade of facades) { - fs.write(facade[0], facade[1] + os.EOL) - } - - // Handle package.json files array - - const packageJsonPath = path.join(__dirname, '..', 'package.json') - const packageJson = fs.read(packageJsonPath, 'json') as PackageJson - - packageJson.files = lo.uniq([...(packageJson.files ?? []), ...facades.map((facade) => facade[0])]) - - const packageJsonString = JSON.stringify(packageJson, null, 2) + os.EOL - - fs.write(packageJsonPath, packageJsonString) -} - -type ModuleFacade = [filePath: string, fileContents: string] diff --git a/src/index.ts b/src/entrypoints/main.ts similarity index 73% rename from src/index.ts rename to src/entrypoints/main.ts index ab685ccbb..388bd8027 100644 --- a/src/index.ts +++ b/src/entrypoints/main.ts @@ -1,10 +1,10 @@ import { PackageJson } from 'type-fest' import { inspect } from 'util' -import { enforceValidPeerDependencies } from './lib/peerDepValidator' +import { enforceValidPeerDependencies } from '../lib/peerDepValidator' // Want synchronous cached require here // eslint-disable-next-line -const packageJson = require('../package.json') as PackageJson +const packageJson = require('../../package.json') as PackageJson if (!packageJson || !packageJson.version || !packageJson.name) { console.warn( @@ -18,4 +18,4 @@ if (!packageJson || !packageJson.version || !packageJson.name) { }) } -export * from './runtime' +export * from '../runtime' diff --git a/src/generator/generate.ts b/src/generator/generate.ts index 35d542b47..b45bc51f1 100644 --- a/src/generator/generate.ts +++ b/src/generator/generate.ts @@ -7,7 +7,8 @@ import { Gentime } from './gentime/settingsSingleton' import * as ModelsGenerator from './models' import { ModuleSpec } from './types' -const OUTPUT_SOURCE_DIR = getOutputSourceDir() +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 { @@ -19,15 +20,43 @@ export function generateRuntimeAndEmit(dmmf: DMMF.Document, settings: Gentime.Se fs.write('dmmf.json', dmmf) } - const sourceFiles: ModuleSpec[] = [ - ModelsGenerator.JS.createModuleSpec(settings), - ModelsGenerator.TS.createModuleSpec(dmmf, settings), + 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) + 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, + ] - sourceFiles.forEach((sf) => { - const filePath = Path.join(OUTPUT_SOURCE_DIR, 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}`) @@ -39,7 +68,16 @@ export function generateRuntimeAndEmit(dmmf: DMMF.Document, settings: Gentime.Se /** 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(settings), + ModelsGenerator.JS.createModuleSpec({ + gentimeSettings: settings, + esm: true, + dmmf, + }), + ModelsGenerator.JS.createModuleSpec({ + gentimeSettings: settings, + esm: false, + dmmf, + }), ModelsGenerator.TS.createModuleSpec(dmmf, settings), ] @@ -52,7 +90,7 @@ export function generateRuntime(dmmf: DMMF.Document, settings: Gentime.Settings) * If the Yalc issue https://github.com/wclr/yalc/issues/156 is resolved then this should be as simple as * using __dirname. */ -function getOutputSourceDir(): string { +function getOutputSourceDir(params: { esm: boolean }): string { let outputSourceDir: string if (process.env.npm_package_dependencies_nexus_prisma === 'file:.yalc/nexus-prisma') { @@ -62,9 +100,19 @@ function getOutputSourceDir(): string { `Nexus Prisma error: Could not find the project root. Project root is the nearest ancestor directory to where this module is running (${__filename}) containing a package.json. Without this information Nexus Prisma does not know where to output its generated code.` ) } - outputSourceDir = Path.join(Path.dirname(packageJsonFilePath), 'node_modules/nexus-prisma/dist/runtime') + outputSourceDir = Path.join( + Path.dirname(packageJsonFilePath), + params.esm ? 'node_modules/nexus-prisma/dist-esm/runtime' : 'node_modules/nexus-prisma/dist-cjs/runtime' + ) } else { - outputSourceDir = Path.join(__dirname, '../runtime') + /** + * At this point in the code we don't know if the CLI running is the CJS or ESM version. + * If it is the CJS version and we're doing an ESM build then we need to adjust the __dirname value. + */ + outputSourceDir = Path.join( + params.esm ? __dirname.replace('dist-cjs', 'dist-esm') : __dirname, + '../runtime' + ) } d(`found outputSourceDir ${outputSourceDir}`) diff --git a/src/generator/models/javascript.ts b/src/generator/models/javascript.ts index 932af8e1f..a866d85d9 100644 --- a/src/generator/models/javascript.ts +++ b/src/generator/models/javascript.ts @@ -1,4 +1,4 @@ -import { DMMF } from '@prisma/client/runtime' +import type { DMMF } from '@prisma/client/runtime' import dedent from 'dindist' import { chain, lowerFirst } from 'lodash' import * as Nexus from 'nexus' @@ -37,13 +37,81 @@ export type Settings = { /** * Create the module specification for the JavaScript runtime. */ -export function createModuleSpec(gentimeSettings: Gentime.Settings): ModuleSpec { +export function createModuleSpec(params: { + /** + * Resolved generator settings (whatever user supplied merged with defaults). + */ + gentimeSettings: Gentime.Settings + /** + * Should the module be generated using ESM instead of CJS? + */ + esm: boolean + /** + * Detailed data about the Prisma Schema contents and available operations over its models. + */ + dmmf: DMMF.Document +}): ModuleSpec { + const { esm, gentimeSettings, dmmf } = params + + const esmModelExports = + dmmf.datamodel.models + .map((model) => { + return dedent` + export const ${model.name} = models['${model.name}'] + ` + }) + .join('\n') || `// N/A -- You have not defined any models in your Prisma Schema.` + + const esmEnumExports = + dmmf.datamodel.enums + .map((enum_) => { + return dedent` + export const ${enum_.name} = models['${enum_.name}'] + ` + }) + .join('\n') || `// N/A -- You have not defined any enums in your Prisma Schema.` + + const exports = esm + ? dedent` + // + // Exports + // + + // Static API Exports + + export const $settings = Runtime.settings.change + + // Reflected Model Exports + + ${esmModelExports} + + // Reflected Enum Exports + + ${esmEnumExports} + ` + : dedent` + module.exports = { + $settings: Runtime.settings.change, + ...models, + } + ` + + const imports = esm + ? dedent` + import { getPrismaClientDmmf } from '../helpers/prisma' + import * as ModelsGenerator from '../generator/models' + import { Runtime } from '../generator/runtime/settingsSingleton' + ` + : dedent` + const { getPrismaClientDmmf } = require('../helpers/prisma') + const ModelsGenerator = require('../generator/models') + const { Runtime } = require('../generator/runtime/settingsSingleton') + ` + return { fileName: 'index.js', content: dedent` - const { getPrismaClientDmmf } = require('../helpers/prisma') - const ModelsGenerator = require('../generator/models') - const { Runtime } = require('../generator/runtime/settingsSingleton') + ${imports} const gentimeSettings = ${JSON.stringify(gentimeSettings.data, null, 2)} @@ -58,12 +126,7 @@ export function createModuleSpec(gentimeSettings: Gentime.Settings): ModuleSpec gentime: gentimeSettings, }) - const moduleExports = { - ...models, - $settings: Runtime.settings.change, - } - - module.exports = moduleExports + ${exports} `, } } diff --git a/src/helpers/prisma.ts b/src/helpers/prisma.ts index f57820b5a..fc97b4903 100644 --- a/src/helpers/prisma.ts +++ b/src/helpers/prisma.ts @@ -1,11 +1,11 @@ import { DMMF } from '@prisma/client/runtime' import dedent from 'dindist' +import kleur from 'kleur' import ono from 'ono' import { inspect } from 'util' import { detectProjectPackageManager, renderRunBin } from '../lib/packageManager' import { d } from './debugNexusPrisma' import { GITHUB_NEW_DISCUSSION_LINK } from './errorMessages' -import kleur = require('kleur') /** * Given a package loader, attempt to get the Prisma Client DMMF. diff --git a/src/lib/diagnostic.ts b/src/lib/diagnostic.ts index 116a7d38c..5c258eccb 100644 --- a/src/lib/diagnostic.ts +++ b/src/lib/diagnostic.ts @@ -1,4 +1,4 @@ -import kleur = require('kleur') +import kleur from 'kleur' type DiagnosticInfo = { title: string diff --git a/src/lib/peerDepValidator.ts b/src/lib/peerDepValidator.ts index cf7c60623..c2c0bb2d7 100644 --- a/src/lib/peerDepValidator.ts +++ b/src/lib/peerDepValidator.ts @@ -1,11 +1,11 @@ import dedent from 'dindist' +import kleur from 'kleur' import * as Semver from 'semver' import { PackageJson } from 'type-fest' import { d } from '../helpers/debugNexusPrisma' import { isModuleNotFoundError } from '../helpers/utils' import { renderError, renderWarning } from './diagnostic' import { detectProjectPackageManager, renderAddDeps } from './packageManager' -import kleur = require('kleur') export const envarSpecs = { NO_PEER_DEPENDENCY_CHECK: { diff --git a/tests/__helpers__/helpers.ts b/tests/__helpers__/helpers.ts index 92b051dc7..e995b4d3b 100644 --- a/tests/__helpers__/helpers.ts +++ b/tests/__helpers__/helpers.ts @@ -1,7 +1,10 @@ import * as fs from 'fs-jetpack' +import * as Path from 'path' export function assertBuildPresent() { - if (fs.exists('../../dist')) { - throw new Error(`Please build package before running this test`) - } + if (fs.exists(Path.join(__dirname, '../../dist-esm')) === false) + throw new Error(`Please run build ESM before running this test`) + + if (fs.exists(Path.join(__dirname, '../../dist-cjs')) === false) + throw new Error(`Please run build CJS before running this test`) } diff --git a/tests/__helpers__/testers.ts b/tests/__helpers__/testers.ts index 99054abb2..a0b940985 100644 --- a/tests/__helpers__/testers.ts +++ b/tests/__helpers__/testers.ts @@ -260,17 +260,24 @@ export function createPrismaSchema({ /** * For the given Prisma Schema generate the derived source code. */ -export async function generateModules(content: string): Promise<{ indexjs: string; indexdts: string }> { +export async function generateModules( + content: string +): Promise<{ indexjs_esm: string; indexjs_cjs: string; indexdts: string }> { const prismaSchemaContents = createPrismaSchema({ content }) const dmmf = await PrismaSDK.getDMMF({ datamodel: prismaSchemaContents, }) - const [indexjs, indexdts] = generateRuntime(dmmf, Gentime.settings) as [ModuleSpec, ModuleSpec] + const [indexjs_esm, indexjs_cjs, indexdts] = generateRuntime(dmmf, Gentime.settings) as [ + ModuleSpec, + ModuleSpec, + ModuleSpec + ] return { indexdts: indexdts.content, - indexjs: indexjs.content, + indexjs_esm: indexjs_esm.content, + indexjs_cjs: indexjs_cjs.content, } } diff --git a/tests/e2e/__snapshots__/kitchen-sink.test.ts.snap b/tests/e2e/__snapshots__/kitchen-sink.test.ts.snap index 8ba5abe5c..93d1d943b 100644 --- a/tests/e2e/__snapshots__/kitchen-sink.test.ts.snap +++ b/tests/e2e/__snapshots__/kitchen-sink.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`When bundled custom scalars are used the project type checks and generates expected GraphQL schema: client request 1 1`] = ` +exports[`A full-featured project type checks, generates expected GraphQL schema, and successfully resolves received GraphQL documents: client request 1 1`] = ` Object { "bars": Array [ Object { @@ -25,7 +25,7 @@ Object { } `; -exports[`When bundled custom scalars are used the project type checks and generates expected GraphQL schema: graphql schema 1`] = ` +exports[`A full-featured project type checks, generates expected GraphQL schema, and successfully resolves received GraphQL documents: graphql schema 1`] = ` "### This file was generated by Nexus Schema ### Do not make changes to this file directly @@ -82,7 +82,7 @@ enum SomeEnumA { " `; -exports[`When bundled custom scalars are used the project type checks and generates expected GraphQL schema: nexus typegen 1`] = ` +exports[`A full-featured project type checks, generates expected GraphQL schema, and successfully resolves received GraphQL documents: nexus typegen 1`] = ` "/** * This file was generated by Nexus Schema * Do not make changes to this file directly diff --git a/tests/e2e/kitchen-sink.test.ts b/tests/e2e/kitchen-sink.test.ts index 62dd33ec3..14b93b31c 100644 --- a/tests/e2e/kitchen-sink.test.ts +++ b/tests/e2e/kitchen-sink.test.ts @@ -98,7 +98,9 @@ beforeAll(() => { testProject = setupTestNexusPrismaProject() }) -it('When bundled custom scalars are used the project type checks and generates expected GraphQL schema', async () => { +// TODO add an ESM test + +it('A full-featured project type checks, generates expected GraphQL schema, and successfully resolves received GraphQL documents', async () => { const files: FileSpec[] = [ { filePath: `prisma/schema.prisma`, @@ -350,7 +352,13 @@ it('When bundled custom scalars are used the project type checks and generates e * Sanity check the Prisma Client import ID */ - expect(testProject.fs.read('node_modules/nexus-prisma/dist/runtime/index.js')).toMatch( + expect(testProject.fs.read('node_modules/nexus-prisma/dist-cjs/runtime/index.js')).toMatch( + /.*"prismaClientImportId": "@prisma\/client".*/ + ) + + // TODO once a dedicated ESM test exists, move this exlcusively to it + // For not this is a cheap sanity check + expect(testProject.fs.read('node_modules/nexus-prisma/dist-esm/runtime/index.js')).toMatch( /.*"prismaClientImportId": "@prisma\/client".*/ ) diff --git a/tests/integration/json.test.ts b/tests/integration/json.test.ts index a5ded9d06..a0187d303 100644 --- a/tests/integration/json.test.ts +++ b/tests/integration/json.test.ts @@ -1,7 +1,7 @@ import dedent from 'dindist' import gql from 'graphql-tag' import { list, objectType, queryType } from 'nexus' -import NexusPrismaScalars from '../../scalars' +import NexusPrismaScalars from '../../src/entrypoints/scalars' import { testIntegration } from '../__helpers__/testers' testIntegration({ diff --git a/tests/lib/peerDepValidator.test.ts b/tests/lib/peerDepValidator.test.ts index f02ef4928..bf58eba13 100644 --- a/tests/lib/peerDepValidator.test.ts +++ b/tests/lib/peerDepValidator.test.ts @@ -36,7 +36,10 @@ beforeAll(() => { main: 'dist/index.js', }) - testProject.fs.copy(`${process.cwd()}/dist`, `${testProject.fs.cwd()}/node_modules/${requireer.name}/dist`) + testProject.fs.copy( + `${process.cwd()}/dist-cjs`, + `${testProject.fs.cwd()}/node_modules/${requireer.name}/dist` + ) testProject.fs.write( 'validatePeerDependencies.js', diff --git a/tests/specs.ts b/tests/specs.ts index 5ae21ff53..f2b3295f9 100644 --- a/tests/specs.ts +++ b/tests/specs.ts @@ -68,7 +68,7 @@ export namespace Specs { `, } - export const relation1ToNReverseAndOptional = { + export const relation1ToNReverseAndOptional: IntegrationTestSpec = { description: 'can project user-to-posts relationship in reverse (access use via post author field). If Post.author IS optional than it IS nullable in the GraphQL API.', datasourceSchema: ` diff --git a/tests/tsconfig.json b/tests/tsconfig.json deleted file mode 100644 index 07b82a625..000000000 --- a/tests/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../tsconfig.base.json", - "references": [{ "path": ".." }], - "include": [".."], - "compilerOptions": { - "strict": true, - "tsBuildInfoFile": "node_modules/.cache/.tsbuildinfo.test", - "rootDir": ".." - } -} diff --git a/tests/unit/graphqlSchema/json.test.ts b/tests/unit/graphqlSchema/json.test.ts index 5fe34faa5..4605f4251 100644 --- a/tests/unit/graphqlSchema/json.test.ts +++ b/tests/unit/graphqlSchema/json.test.ts @@ -1,6 +1,6 @@ import dedent from 'dindist' import { objectType } from 'nexus' -import NexusPrismaScalars from '../../../scalars' +import NexusPrismaScalars from '../../../src/entrypoints/scalars' import { testGraphqlSchema } from '../../__helpers__/testers' testGraphqlSchema({ diff --git a/tsconfig.base.json b/tsconfig.base.json deleted file mode 100644 index 2ce896d32..000000000 --- a/tsconfig.base.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "compilerOptions": { - // Make the compiler stricter, catch more errors - "strict": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedIndexedAccess": true, - - // Output - "target": "ES2018", - "module": "commonjs", - "importHelpers": true, - "declaration": true, - "declarationMap": true, - "sourceMap": true, - - // Project layout - "rootDir": "src", - "outDir": "dist", - - // DX - "incremental": true, - "tsBuildInfoFile": "node_modules/.cache/.tsbuildinfo", - "noErrorTruncation": true, - - // Other - // 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 - }, - "include": ["src"], - "exclude": ["./**/*.spec.ts", "tests"] -} diff --git a/tsconfig.cjs.json b/tsconfig.cjs.json new file mode 100644 index 000000000..dee7f8cef --- /dev/null +++ b/tsconfig.cjs.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "dist-cjs", + "module": "commonjs", + "rootDir": "src", + "sourceMap": true, + "declaration": true, + "declarationMap": false + }, + "include": ["src"] +} diff --git a/tsconfig.esm.json b/tsconfig.esm.json new file mode 100644 index 000000000..1da94595d --- /dev/null +++ b/tsconfig.esm.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "dist-esm", + "module": "ES2015", + "rootDir": "src", + "sourceMap": true, + "declaration": true, + "declarationMap": true + }, + "include": ["src"] +} diff --git a/tsconfig.json b/tsconfig.json index 9ed8af298..0d6d77ac8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,10 +1,28 @@ { - "extends": "./tsconfig.base.json", "compilerOptions": { - "composite": true, - "outDir": "dist", - "rootDir": "src" + // Make the compiler stricter, catch more errors + "strict": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": true, + + // Output + "target": "ES2018", + "module": "commonjs", + "moduleResolution": "Node", + "importHelpers": true, + + // DX + "incremental": true, + "tsBuildInfoFile": "node_modules/.cache/.tsbuildinfo", + "noErrorTruncation": true, + + // Other + // 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 }, - "include": ["src"], - "exclude": ["src/**/*.spec.ts"] + "include": ["src", "tests", "scripts"], + "exclude": ["dist-*", "tests/e2e/fixtures"] } diff --git a/yarn.lock b/yarn.lock index 362b7c126..27a1f2154 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1326,7 +1326,7 @@ ansi-colors@^4.1.1: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== -ansi-escapes@^4.2.1, ansi-escapes@^4.3.1: +ansi-escapes@^4.2.1, ansi-escapes@^4.3.0, ansi-escapes@^4.3.1: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== @@ -3848,6 +3848,15 @@ jest-validate@^27.0.6: leven "^3.1.0" pretty-format "^27.0.6" +jest-watch-select-projects@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/jest-watch-select-projects/-/jest-watch-select-projects-2.0.0.tgz#4373d7e4de862aae28b46e036b669a4c913ea867" + integrity sha512-j00nW4dXc2NiCW6znXgFLF9g8PJ0zP25cpQ1xRro/HU2GBfZQFZD0SoXnAlaoKkIY4MlfTMkKGbNXFpvCdjl1w== + dependencies: + ansi-escapes "^4.3.0" + chalk "^3.0.0" + prompts "^2.2.1" + jest-watch-typeahead@0.6.4: version "0.6.4" resolved "https://registry.yarnpkg.com/jest-watch-typeahead/-/jest-watch-typeahead-0.6.4.tgz#ea70bf1bec34bd4f55b5b72d471b02d997899c3e" @@ -4812,7 +4821,7 @@ progress@^2.0.0, progress@^2.0.3: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -prompts@^2.0.1: +prompts@^2.0.1, prompts@^2.2.1: version "2.4.1" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.1.tgz#befd3b1195ba052f9fd2fde8a486c4e82ee77f61" integrity sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ==