Skip to content

Commit

Permalink
feat: add @adminjs/nestjs handler
Browse files Browse the repository at this point in the history
  • Loading branch information
dziraf committed Dec 1, 2023
1 parent e1b84ed commit 2087820
Show file tree
Hide file tree
Showing 29 changed files with 324 additions and 38 deletions.
5 changes: 5 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ module.exports = {
ecmaVersion: 2020,
sourceType: 'module',
},
ignorePatterns: [
'lib',
'src/commands/create/templates/**/*',
],
rules: {
indent: ['error', 2],
'max-len': ['error', 120],
Expand All @@ -18,6 +22,7 @@ module.exports = {
semi: ['error', 'always'],
'no-underscore-dangle': 'off',
'no-shadow': 'off',
'class-methods-use-this': 'off',
'@typescript-eslint/no-shadow': 'error',
'import/prefer-default-export': 'off',
'import/no-unresolved': 'off',
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"clean": "rimraf lib types",
"build": "tsc && yarn copy-templates",
"copy-templates": "copyfiles -u 3 \"./src/commands/create/templates/**/*\" \"./lib/commands/create/\"",
"lint": "eslint \"src\"",
"register:local": "yarn global add file:$PWD",
"dev": "yarn clean && yarn build && yarn register:local"
},
Expand All @@ -26,6 +27,7 @@
"copyfiles": "^2.4.1",
"eslint": "^8.38.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-prettier": "^5.0.1",
Expand Down
13 changes: 12 additions & 1 deletion src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
#! /usr/bin/env node
import chalk from 'chalk';

import { CliCommand } from './types.js';

const command = process.argv[2];

if (command === CliCommand.Create) {
await import('./commands/create/cli.js');
} else if (command === CliCommand.Help) {
// eslint-disable-next-line no-console
console.log(`${chalk.underline.blue(`${chalk.yellow('@adminjs/cli')} Commands List`)}
${chalk.underline('create')} Create an AdminJS project
${chalk.underline('help')} List available CLI commands
`);
} else {
console.log('unknown command', command);
// eslint-disable-next-line no-console
console.log(chalk.red(`Unknown command: ${command}`));
// eslint-disable-next-line no-console
console.log(chalk.cyan(`Run ${chalk.yellow('adminjs help')} to see available commands.`));
}
9 changes: 4 additions & 5 deletions src/commands/create/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { unflatten } from 'flat';
import {
adapterOptions, packageManagerOptions, pluginOptions, databaseDriversForAdapter, environmentVariablesPrompts,
} from './options.js';
import { CreateCommandHandler } from './handlers/CreateCommand.handler.js';
import { CreateCommandPromptsAnswers } from './types.js';
import { CreateCommand } from './command.js';
import { CreateCommandInput } from './types.js';

const questions: prompts.PromptObject[] = [
{
Expand Down Expand Up @@ -53,7 +53,6 @@ const questions: prompts.PromptObject[] = [
...environmentVariablesPrompts,
];

const response = (await prompts(questions)) as unknown as CreateCommandPromptsAnswers;

const handler = new CreateCommandHandler(unflatten(response));
const response = (await prompts(questions)) as unknown as CreateCommandInput;
const handler = new CreateCommand(unflatten(response));
await handler.run();
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,25 @@ import path from 'path';

import chalk from 'chalk';

import {
CreateCommandPromptsAnswers,
} from '../types.js';
import { BaseCommandHandler } from '../utils/BaseCommandHandler.js';
import logger from '../../../utils/logger.js';
import { asyncExec } from '../utils/async-exec.js';
import logger from '../../utils/logger.js';
import {
displayRstInformation, displayWhatsNextTips, reportIssuesTip,
} from '../../../instructions.js';
import { displayStartTips } from '../instructions.js';
} from '../../instructions.js';

import { BaseSetupHandler } from './BaseSetup.handler.js';
import { LibrarySetupHandler, LibraryType } from './LibrarySetup.handler.js';
import { EnvironmentVariablesHandler } from './EnvironmentVariables.handler.js';
import { DatabaseDriverSetupHandler } from './DatabaseDriverSetup.handler.js';
import { BaseCommandHandler } from './utils/BaseCommandHandler.js';
import { asyncExec } from './utils/async-exec.js';
import { displayStartTips } from './instructions.js';
import { BaseSetupHandler } from './handlers/BaseSetup.handler.js';
import { LibrarySetupHandler, LibraryType } from './handlers/LibrarySetup.handler.js';
import { EnvironmentVariablesHandler } from './handlers/EnvironmentVariables.handler.js';
import { DatabaseDriverSetupHandler } from './handlers/DatabaseDriverSetup.handler.js';
import { NestSetupHandler } from './handlers/NestSetup.handler.js';
import {
AdminJSPlugin,
CreateCommandInput,
} from './types.js';

export class CreateCommandHandler extends BaseCommandHandler<CreateCommandPromptsAnswers> {
export class CreateCommand extends BaseCommandHandler<CreateCommandInput> {
public async run() {
const cwd = path.join(process.cwd(), this.options.projectName);
const environmentVariablesHandler = new EnvironmentVariablesHandler(this.options);
Expand All @@ -28,10 +30,21 @@ export class CreateCommandHandler extends BaseCommandHandler<CreateCommandPrompt
const adapterSetupHandler = new LibrarySetupHandler(this.options, LibraryType.Adapter);
const databaseDriverSetupHandler = new DatabaseDriverSetupHandler(this.options, environmentVariablesHandler);

let nestSetupHandler: NestSetupHandler;
if (this.options.plugin === AdminJSPlugin.NestJS) {
nestSetupHandler = new NestSetupHandler(this.options, LibraryType.Plugin);
}

try {
await baseSetupHandler.run();
await pluginSetupHandler.run();
await adapterSetupHandler.run();

if (this.options.plugin === AdminJSPlugin.NestJS) {
await nestSetupHandler.run();
} else {
await pluginSetupHandler.run();
await adapterSetupHandler.run();
}

await databaseDriverSetupHandler.run();
await environmentVariablesHandler.run();

Expand All @@ -41,8 +54,13 @@ export class CreateCommandHandler extends BaseCommandHandler<CreateCommandPrompt

logger.info('Running post-setup scripts.');
const driverInfo = databaseDriverSetupHandler.getDriverInfo();
await pluginSetupHandler.postSetup(driverInfo);
await adapterSetupHandler.postSetup(driverInfo);

if (this.options.plugin === AdminJSPlugin.NestJS) {
await nestSetupHandler.postSetup(driverInfo);
} else {
await pluginSetupHandler.postSetup(driverInfo);
await adapterSetupHandler.postSetup(driverInfo);
}

const buildCommand = `${this.options.packageManager} run build`;
logger.info(`Building: ${chalk.gray(buildCommand)}`);
Expand Down
4 changes: 2 additions & 2 deletions src/commands/create/handlers/BaseSetup.handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import chalk from 'chalk';
import { copy } from 'fs-extra/esm';

import logger from '../../../utils/logger.js';
import { CreateCommandPromptsAnswers } from '../types.js';
import { CreateCommandInput } from '../types.js';
import { templatesDir } from '../utils/templates-dir.js';
import { BaseCommandHandler } from '../utils/BaseCommandHandler.js';
import { CONTENT_DIR_NAME, DOTFILES_DIR_NAME } from '../constants.js';

export class BaseSetupHandler extends BaseCommandHandler<CreateCommandPromptsAnswers> {
export class BaseSetupHandler extends BaseCommandHandler<CreateCommandInput> {
public async run() {
logger.info(`Setting up ${chalk.yellow(this.options.projectName)} project's base template.`);
await this.copyBaseContents();
Expand Down
6 changes: 3 additions & 3 deletions src/commands/create/handlers/DatabaseDriverSetup.handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import fs from 'fs/promises';
import chalk from 'chalk';

import logger from '../../../utils/logger.js';
import { AdminJSAdapter, CreateCommandPromptsAnswers } from '../types.js';
import { AdminJSAdapter, CreateCommandInput } from '../types.js';
import { BaseCommandHandler } from '../utils/BaseCommandHandler.js';

import { EnvironmentVariablesHandler } from './EnvironmentVariables.handler.js';
Expand Down Expand Up @@ -67,14 +67,14 @@ export interface DriverInfo {
dialectName: string;
}

export class DatabaseDriverSetupHandler extends BaseCommandHandler<CreateCommandPromptsAnswers> {
export class DatabaseDriverSetupHandler extends BaseCommandHandler<CreateCommandInput> {
protected driverLibrary: typeof DB_DRIVERS_LIBRARIES[keyof typeof DB_DRIVERS_LIBRARIES];

protected dialectName: string;

private environmentVariablesHandler: EnvironmentVariablesHandler;

constructor(options: CreateCommandPromptsAnswers, environmentVariablesHandler: EnvironmentVariablesHandler) {
constructor(options: CreateCommandInput, environmentVariablesHandler: EnvironmentVariablesHandler) {
super(options);

this.environmentVariablesHandler = environmentVariablesHandler;
Expand Down
6 changes: 3 additions & 3 deletions src/commands/create/handlers/EnvironmentVariables.handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import randomstring from 'randomstring';
import chalk from 'chalk';

import logger from '../../../utils/logger.js';
import { CreateCommandPromptsAnswers } from '../types.js';
import { CreateCommandInput } from '../types.js';
import { BaseCommandHandler } from '../utils/BaseCommandHandler.js';

const DEFAULT_ENVS = {
Expand All @@ -19,10 +19,10 @@ const DEFAULT_ENVS = {
PORT: 3000,
};

export class EnvironmentVariablesHandler extends BaseCommandHandler<CreateCommandPromptsAnswers> {
export class EnvironmentVariablesHandler extends BaseCommandHandler<CreateCommandInput> {
protected environmentVariables: Record<string, unknown>;

constructor(options: CreateCommandPromptsAnswers) {
constructor(options: CreateCommandInput) {
super(options);

this.environmentVariables = DEFAULT_ENVS;
Expand Down
6 changes: 3 additions & 3 deletions src/commands/create/handlers/LibrarySetup.handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { copy } from 'fs-extra/esm';
import chalk from 'chalk';

import logger from '../../../utils/logger.js';
import { AdminJSAdapter, AdminJSPlugin, CreateCommandPromptsAnswers } from '../types.js';
import { AdminJSAdapter, AdminJSPlugin, CreateCommandInput } from '../types.js';
import { templatesDir } from '../utils/templates-dir.js';
import { BaseCommandHandler } from '../utils/BaseCommandHandler.js';
import { CONFIG_DIR_NAME, CONTENT_DIR_NAME, SCRIPTS_DIR_NAME } from '../constants.js';
Expand All @@ -22,12 +22,12 @@ export interface LibrarySetupHandlerConfiguration {
type: LibraryType;
}

export class LibrarySetupHandler extends BaseCommandHandler<CreateCommandPromptsAnswers> {
export class LibrarySetupHandler extends BaseCommandHandler<CreateCommandInput> {
protected libraryType: LibraryType;

protected libraryName: AdminJSAdapter | AdminJSPlugin;

constructor(options: CreateCommandPromptsAnswers, libraryType: LibraryType) {
constructor(options: CreateCommandInput, libraryType: LibraryType) {
super(options);

this.libraryType = libraryType;
Expand Down
22 changes: 22 additions & 0 deletions src/commands/create/handlers/NestSetup.handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import chalk from 'chalk';

import { logger } from '../../../index.js';

import { LibrarySetupHandler } from './LibrarySetup.handler.js';

export class NestSetupHandler extends LibrarySetupHandler {
public async run() {
await super.run();
await this.setupAdapter();
}

public async setupAdapter() {
logger.info(chalk.red('--------------- IMPORTANT ---------------'));
logger.info(`The CLI does not support adapter setup for: ${chalk.yellow('@adminjs/nestjs')}`);
// eslint-disable-next-line max-len
logger.info(`${chalk.yellow('@adminjs/cli')} will bootstrap a ${chalk.yellow('NestJS + AdminJS')} application, but you will have to set up the adapter manually.`);
// eslint-disable-next-line max-len
logger.info(`Please refer to ${chalk.underline.magenta(`https://docs.adminjs.co/installation/adapters/${this.options.adapter}`)} for instructions.`);
logger.info(chalk.red('-----------------------------------------'));
}
}
2 changes: 1 addition & 1 deletion src/commands/create/handlers/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export * from './BaseSetup.handler.js';
export * from './CreateCommand.handler.js';
export * from './DatabaseDriverSetup.handler.js';
export * from './EnvironmentVariables.handler.js';
export * from './LibrarySetup.handler.js';
export * from './NestSetup.handler.js';
2 changes: 1 addition & 1 deletion src/commands/create/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const pluginOptions = [
{ title: '@adminjs/fastify', value: AdminJSPlugin.Fastify },
{ title: '@adminjs/koa', value: AdminJSPlugin.Koa },
{ title: '@adminjs/hapi', value: AdminJSPlugin.Hapi },
{ title: '@adminjs/nestjs', value: AdminJSPlugin.NestJS, disabled: true },
{ title: '@adminjs/nestjs', value: AdminJSPlugin.NestJS },
];

export const adapterOptions = [
Expand Down
19 changes: 19 additions & 0 deletions src/commands/create/templates/plugin/nestjs/_config/custom.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"@adminjs/express": "^6.1.0",
"@adminjs/nestjs": "^6.1.0",
"@nestjs/common": "^10.0.0",
"@nestjs/config": "^3.1.1",
"@nestjs/core": "^10.0.0",
"@nestjs/platform-express": "^10.0.0",
"adminjs": "^7.4.0",
"express-formidable": "^1.2.0",
"express-session": "^1.17.3",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"@nestjs/cli": "^10.0.0",
"@nestjs/schematics": "^10.0.0",
"@nestjs/testing": "^10.0.0",
"@types/express": "^4.17.17",
"@types/jest": "^29.5.2",
"@types/node": "^20.3.1",
"@types/supertest": "^2.0.12",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"eslint": "^8.42.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0",
"jest": "^29.5.0",
"prettier": "^3.0.0",
"source-map-support": "^0.5.21",
"supertest": "^6.3.3",
"ts-jest": "^29.1.0",
"ts-loader": "^9.4.3",
"ts-node": "^10.9.1",
"tslib": "^2.5.0",
"tsconfig-paths": "^4.2.0"
}
13 changes: 13 additions & 0 deletions src/commands/create/templates/plugin/nestjs/_config/scripts.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"build": "nest build",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Test, TestingModule } from '@nestjs/testing';

import { AppController } from './app.controller';
import { AppService } from './app.service';

describe('AppController', () => {
let appController: AppController;

beforeEach(async () => {
const app: TestingModule = await Test.createTestingModule({
controllers: [AppController],
providers: [AppService],
}).compile();

appController = app.get<AppController>(AppController);
});

describe('root', () => {
it('should return "Hello World!"', () => {
expect(appController.getHello()).toBe('Hello World!');
});
});
});
Loading

0 comments on commit 2087820

Please sign in to comment.