diff --git a/README.md b/README.md index 3c0441d5..31d36eba 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,8 @@ npx prisma generate (default: `true`) - `atomicNumberOperations` - Atomic number operations, `false` - disabled (default), `true` - enabled +- `reExportAll` - create `index.ts` files for each directory with re-export, + `false` - disabled (default), `true` - enabled - `types_*` - [flatten](https://github.com/hughsk/flat) map of types - `types_{type}_fieldType` - TypeScript type name diff --git a/src/generate.spec.ts b/src/generate.spec.ts index c98eda6e..2ff25cce 100644 --- a/src/generate.spec.ts +++ b/src/generate.spec.ts @@ -1,8 +1,9 @@ import assert from 'assert'; import expect from 'expect'; -import { PropertyDeclaration, SourceFile } from 'ts-morph'; +import { Project, PropertyDeclaration, SourceFile } from 'ts-morph'; import { generate } from './generate'; +import { reexport } from './generator-pipelines'; import { generatorOptions, getImportDeclarations, stringContains } from './testing'; describe('main generate', () => { @@ -10,13 +11,15 @@ describe('main generate', () => { let sourceFile: SourceFile | undefined; let sourceFiles: SourceFile[]; let sourceText: string; + let project: Project; + let resultGeneratorOptions: any; async function getResult(args: { schema: string; options?: string[] }) { const { schema, options } = args; - const generateOptions = { + resultGeneratorOptions = { ...(await generatorOptions(schema, options)), fileExistsSync: () => false, }; - const project = await generate(generateOptions); + project = await generate(resultGeneratorOptions); sourceFiles = project.getSourceFiles(); } @@ -520,4 +523,46 @@ describe('main generate', () => { const names = classFile.getProperties().map(p => p.getName()); expect(names).toStrictEqual([...new Set(names)]); }); + + it('export all from index', async () => { + const checkpoints: any[] = []; + await getResult({ + schema: ` + model User { + id Int @id + posts Post[] + } + model Post { + id Int @id + author User? @relation(fields: [authorId], references: [id]) + authorId Int? + }`, + }); + await reexport(project); + + sourceFile = project.getSourceFile('/user/index.ts')!; + expect(sourceFile.getText()).toContain( + `export { AggregateUser } from './aggregate-user.output'`, + ); + expect(sourceFile.getText()).toContain(`export { User } from './user.model'`); + expect(sourceFile.getText()).toContain( + `export { UserCreateInput } from './user-create.input'`, + ); + + sourceFile = project.getSourceFile('/post/index.ts')!; + expect(sourceFile.getText()).toContain( + `export { AggregatePost } from './aggregate-post.output'`, + ); + expect(sourceFile.getText()).toContain(`export { Post } from './post.model'`); + expect(sourceFile.getText()).toContain( + `export { PostCreateInput } from './post-create.input'`, + ); + + sourceFile = project.getSourceFile('/index.ts')!; + expect(sourceFile.getText()).toContain( + `export { BatchPayload, IntFilter, SortOrder } from './prisma'`, + ); + expect(sourceFile.getText()).toContain(`from './user'`); + expect(sourceFile.getText()).toContain(`from './post'`); + }); }); diff --git a/src/generate.ts b/src/generate.ts index 75c5dd62..51e0bf00 100644 --- a/src/generate.ts +++ b/src/generate.ts @@ -11,7 +11,7 @@ import { generateInput } from './generate-input'; import { generateModel } from './generate-model'; import { Model } from './generate-property'; import { mutateFilters } from './mutate-filters'; -import { PrismaDMMF } from './types'; +import { GeneratorConfiguration, PrismaDMMF } from './types'; import { createConfig, featureName, @@ -25,11 +25,12 @@ import { type GenerateArgs = GeneratorOptions & { prismaClientDmmf?: PrismaDMMF.Document; fileExistsSync?: typeof existsSync; + config?: GeneratorConfiguration; }; export async function generate(args: GenerateArgs) { const { generator, otherGenerators } = args; - const config = createConfig(generator.config); + const config = args.config ?? createConfig(generator.config); assert(generator.output, 'generator.output is empty'); const fileExistsSync = args.fileExistsSync ?? existsSync; const prismaClientOutput = otherGenerators.find( diff --git a/src/generator-pipelines/index.ts b/src/generator-pipelines/index.ts index eb3f09fa..6a141948 100644 --- a/src/generator-pipelines/index.ts +++ b/src/generator-pipelines/index.ts @@ -1,2 +1,3 @@ +export { reexport } from './reexport'; export { remove } from './remove'; export { update } from './update'; diff --git a/src/generator-pipelines/reexport.ts b/src/generator-pipelines/reexport.ts new file mode 100644 index 00000000..6ff06625 --- /dev/null +++ b/src/generator-pipelines/reexport.ts @@ -0,0 +1,32 @@ +import { Project, SourceFile } from 'ts-morph'; + +// eslint-disable-next-line @typescript-eslint/require-await +export async function reexport(project: Project) { + const nextFiles = new Set(); + for (const sourceFile of project.getSourceFiles()) { + const directoryPath = sourceFile.getDirectory().getPath(); + const testIndexFile = `${directoryPath}/index.ts`; + const sourceIndexFile = + project.getSourceFile(testIndexFile) || + project.createSourceFile(testIndexFile); + sourceIndexFile.addExportDeclaration({ + namedExports: sourceFile + .getExportSymbols() + .map(s => ({ name: s.getName() })), + moduleSpecifier: `./${sourceFile.getBaseNameWithoutExtension()}`, + }); + + nextFiles.add(sourceIndexFile); + } + + const sourceIndexFile = project.createSourceFile('/index.ts'); + for (const sourceFile of nextFiles) { + const moduleSpecifier = `.${sourceFile.getDirectory().getPath()}`; + sourceIndexFile.addExportDeclaration({ + namedExports: sourceFile + .getExportSymbols() + .map(s => ({ name: s.getName() })), + moduleSpecifier, + }); + } +} diff --git a/src/index.ts b/src/index.ts index f6cfd83f..01db729d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,19 @@ -import { generatorHandler } from '@prisma/generator-helper'; +import { generatorHandler, GeneratorOptions } from '@prisma/generator-helper'; import { generate } from './generate'; -import { remove, update } from './generator-pipelines'; +import { reexport, remove, update } from './generator-pipelines'; +import { createConfig } from './utils'; generatorHandler({ - async onGenerate(options) { - const project = await generate(options); + async onGenerate(options: GeneratorOptions) { + const config = createConfig(options.generator.config); + const project = await generate({ + ...options, + config, + }); + if (config.reExportAll) { + await reexport(project); + } await remove(project, options); await update(project, options); }, diff --git a/src/types.ts b/src/types.ts index 08fd948e..57ae6502 100644 --- a/src/types.ts +++ b/src/types.ts @@ -12,4 +12,5 @@ export type GeneratorConfiguration = { combineScalarFilters: boolean; atomicNumberOperations: boolean; types: Record; + reExportAll: boolean; }; diff --git a/src/utils/create-config.ts b/src/utils/create-config.ts index a4dac62e..6e56430d 100644 --- a/src/utils/create-config.ts +++ b/src/utils/create-config.ts @@ -28,5 +28,8 @@ export function createConfig( graphqlModule: 'graphql-type-json', } as TypeRecord, }), + reExportAll: ['true', '1', 'on'].includes( + (config.reExportAll as Nullable) ?? 'false', + ), }; }