Skip to content

Commit

Permalink
feat: add support for creating barrel files
Browse files Browse the repository at this point in the history
  • Loading branch information
rfermann committed Apr 23, 2021
1 parent 29b642a commit be67587
Show file tree
Hide file tree
Showing 16 changed files with 696 additions and 181 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ To use NestJS-Prisma-GraphQL-Generator, follow these steps:
2. add NestJS-Prisma-GraphQL-Generator as a subsequent generator to your prisma.schema
3. optionally configure NestJS-Prisma-GraphQL-Generator as described in the [Configuration](#configuration) section
4. run prisma generate
5. import generated types, enums and resolvers from `path/to/prisma/schema/@generated/nestjs`

## Configuration

Expand Down Expand Up @@ -76,7 +77,6 @@ Resolvers can be imported on an individual base and used within the `providers`

## Upcoming features

- barrel files for easier imports
- support for adding custom decorators to the generated objects

## Contributing to NestJS-Prisma-GraphQL-Generator
Expand Down
2 changes: 1 addition & 1 deletion src/Generator/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ describe("Generator", () => {
return 0;
});

expect([...folderList]).toStrictEqual(["enums", "Session", "shared", "User"]);
expect([...folderList]).toStrictEqual(["enums", "index.ts", "Session", "shared", "User"]);
});
it("should log the correct actions", async () => {
expect.assertions(36);
Expand Down
12 changes: 10 additions & 2 deletions src/Generator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { DMMF, GeneratorOptions } from "@prisma/generator-helper";
import Listr from "listr";

import { GeneratorConfig } from "../GeneratorConfig";
import { BarrelFileHandler } from "../Handlers/BarrelFileHandler";
import { EnumHandler } from "../Handlers/EnumHandler";
import { InputTypeHandler } from "../Handlers/InputTypeHandler";
import { ModelHandler } from "../Handlers/ModelHandler";
Expand Down Expand Up @@ -44,6 +45,8 @@ export class Generator {
title: "Generating NestJS integration",
};

private _barrelFileHandler!: BarrelFileHandler;

private readonly _config: GeneratorConfig;

private _dmmf!: DMMF.Document;
Expand Down Expand Up @@ -84,8 +87,8 @@ export class Generator {
},
{
task: async () => {
await this._enumHandler.createBarrelFile();
await this._enumHandler.createFiles();
await this._enumHandler.createBarrelFile();
},
title: Generator.messages.enums.generate,
},
Expand Down Expand Up @@ -123,6 +126,7 @@ export class Generator {
{
task: async () => {
await this._inputTypeHandler.createFiles();
await this._inputTypeHandler.createBarrelFiles();
},
title: Generator.messages.inputTypes.generate,
},
Expand All @@ -139,6 +143,7 @@ export class Generator {
{
task: async () => {
await this._outputTypeHandler.createFiles();
await this._outputTypeHandler.createBarrelFiles();
},
title: Generator.messages.outputTypes.generate,
},
Expand All @@ -155,14 +160,15 @@ export class Generator {
{
task: async () => {
await this._resolverHandler.createFiles();
await this._resolverHandler.createBarrelFiles();
},
title: Generator.messages.resolvers.generate,
},
]),
title: Generator.messages.resolvers.title,
},
],
{ concurrent: true }
{ concurrent: true, exitOnError: true }
),
title: Generator.messages.objects,
},
Expand All @@ -185,13 +191,15 @@ export class Generator {
// dmmf needs to be imported from prisma client. content differs from the dmmf passed in the generator options
this._dmmf = importDmmf(this._config.prismaClientImportPath);

this._barrelFileHandler = new BarrelFileHandler({ config: this._config, dmmf: this._dmmf });
this._enumHandler = new EnumHandler({ config: this._config, dmmf: this._dmmf });
this._modelHandler = new ModelHandler({ config: this._config, dmmf: this._dmmf });
this._inputTypeHandler = new InputTypeHandler({ config: this._config, dmmf: this._dmmf });
this._outputTypeHandler = new OutputTypeHandler({ config: this._config, dmmf: this._dmmf });
this._resolverHandler = new ResolverHandler({ config: this._config, dmmf: this._dmmf });

await this._initOutputFolder();
await this._barrelFileHandler.createBarrelFiles();
}

private async _initOutputFolder(): Promise<void> {
Expand Down
79 changes: 79 additions & 0 deletions src/Handlers/BarrelFileHandler/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import type { ExportDeclarationStructure, OptionalKind } from "ts-morph";

import { BaseHandler } from "../BaseHandler";
import { compareObjectValues } from "../BaseHandler/compareFunctions";

// note: this class will only handle generic barrel files.
// barrel files for model specific files will be handled by the corresponding type handler
export class BarrelFileHandler extends BaseHandler {
async createBarrelFiles(): Promise<void> {
await Promise.all([
this._createSharedBarrelFile(),
this._createModelBarrelFiles(),
this._createTopLevelBarrelFile(),
]);
}

private async _createModelBarrelFiles(): Promise<void> {
const sourceFilesPromise: Promise<void>[] = [];

// eslint-disable-next-line no-restricted-syntax
for (const model of this.baseParser.modelsList) {
const sourceFile = this.baseFileGenerator.createSourceFile(`${model}/index`);

sourceFile.addExportDeclarations([
{
moduleSpecifier: `./${this.config.paths.inputTypes}`,
},
{
moduleSpecifier: `./${this.config.paths.model}`,
},
{
moduleSpecifier: `./${this.config.paths.outputTypes}`,
},
{
moduleSpecifier: `./${this.config.paths.resolvers}`,
},
]);

sourceFilesPromise.push(sourceFile.save());
}

await Promise.all(sourceFilesPromise);
}

private async _createSharedBarrelFile(): Promise<void> {
const sourceFile = this.baseFileGenerator.createSourceFile("shared/index");

sourceFile.addExportDeclarations([
{
moduleSpecifier: `./${this.config.paths.inputTypes}`,
},
{
moduleSpecifier: `./${this.config.paths.outputTypes}`,
},
]);

await sourceFile.save();
}

private async _createTopLevelBarrelFile(): Promise<void> {
const sourceFile = this.baseFileGenerator.createSourceFile("index");
const exportDeclarations: OptionalKind<ExportDeclarationStructure>[] = [];

exportDeclarations.push({
moduleSpecifier: `./shared`,
});

// eslint-disable-next-line no-restricted-syntax
for (const model of this.baseParser.modelsList) {
exportDeclarations.push({ moduleSpecifier: `./${model}` });
}

sourceFile.addExportDeclarations(
exportDeclarations.sort((a, b) => compareObjectValues({ a, b, field: "moduleSpecifier" }))
);

await sourceFile.save();
}
}
86 changes: 63 additions & 23 deletions src/Handlers/BaseHandler/BaseFileGenerator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,29 @@ export class BaseFileGenerator {
sourceFile: SourceFile;
types: string[];
}): void {
const inputTypeImports: Record<string, string[]> = {};

types.sort(comparePrimitiveValues).forEach((type) => {
let currentModel = this._baseParser.getModelName(type);

if (!currentModel) {
currentModel = "shared";
}

if (!inputTypeImports[currentModel]) {
inputTypeImports[currentModel] = [];
}

if (type !== model) {
inputTypeImports[currentModel].push(type);
}
});

const models = Object.keys(inputTypeImports);

// eslint-disable-next-line no-restricted-syntax
for (const currentModel of models) {
let moduleSpecifier = "";
const currentModel = this._baseParser.getModelName(type);

if (model && model === currentModel) {
moduleSpecifier = `.`;
Expand All @@ -82,7 +102,7 @@ export class BaseFileGenerator {
moduleSpecifier = `../../${currentModel}/${this._config.paths.inputTypes}`;
}

if (!model && !currentModel) {
if (!model && currentModel === "shared") {
moduleSpecifier = `.`;
}

Expand All @@ -94,11 +114,13 @@ export class BaseFileGenerator {
moduleSpecifier = `../${this._config.paths.inputTypes}`;
}

sourceFile.addImportDeclaration({
moduleSpecifier: `${moduleSpecifier}/${type}`,
namedImports: [type],
});
});
if (inputTypeImports[currentModel].length) {
sourceFile.addImportDeclaration({
moduleSpecifier: `${moduleSpecifier}`,
namedImports: inputTypeImports[currentModel],
});
}
}
}

// eslint-disable-next-line class-methods-use-this
Expand All @@ -119,11 +141,11 @@ export class BaseFileGenerator {
let moduleSpecifier = "";

if (type === TypeEnum.InputType || type === TypeEnum.ModelType) {
moduleSpecifier = `../${model}/model`;
moduleSpecifier = `../${model}`;
}

if (type === TypeEnum.Resolver) {
moduleSpecifier = `../../${model}/model`;
moduleSpecifier = `../../${model}`;
}

sourceFile.addImportDeclaration({
Expand Down Expand Up @@ -164,31 +186,49 @@ export class BaseFileGenerator {
sourceFile: SourceFile;
types: string[];
}): void {
const outputTypeImports: Record<string, string[]> = {};

types.sort(comparePrimitiveValues).forEach((type) => {
if (type === model) {
return;
let currentModel = this._baseParser.getModelName(type);

if (!currentModel) {
currentModel = "shared";
}

if (!outputTypeImports[currentModel]) {
outputTypeImports[currentModel] = [];
}

if (type !== model) {
outputTypeImports[currentModel].push(type);
}
});

const models = Object.keys(outputTypeImports);

// eslint-disable-next-line no-restricted-syntax
for (const currentModel of models) {
let moduleSpecifier = "";
const currentModel = this._baseParser.getModelName(type);

if (model && model === currentModel) {
if (isResolver) {
moduleSpecifier = `../${this._config.paths.outputTypes}`;
moduleSpecifier = `.`;
}

if (isResolver) {
if (currentModel === "shared") {
moduleSpecifier = `../../${this._config.paths.shared}/${this._config.paths.outputTypes}`;
} else {
moduleSpecifier = `.`;
moduleSpecifier = `../${this._config.paths.outputTypes}`;
}
}

if (model && !currentModel) {
moduleSpecifier = `../../${this._config.paths.shared}/${this._config.paths.outputTypes}`;
if (outputTypeImports[currentModel].length) {
sourceFile.addImportDeclaration({
moduleSpecifier: `${moduleSpecifier}`,
namedImports: outputTypeImports[currentModel],
});
}

sourceFile.addImportDeclaration({
moduleSpecifier: `${moduleSpecifier}/${type}`,
namedImports: [type],
});
});
}
}

createSourceFile(name: string): SourceFile {
Expand Down

0 comments on commit be67587

Please sign in to comment.