Skip to content

Commit 2087820

Browse files
committed
feat: add @adminjs/nestjs handler
1 parent e1b84ed commit 2087820

29 files changed

+324
-38
lines changed

.eslintrc.cjs

+5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ module.exports = {
1010
ecmaVersion: 2020,
1111
sourceType: 'module',
1212
},
13+
ignorePatterns: [
14+
'lib',
15+
'src/commands/create/templates/**/*',
16+
],
1317
rules: {
1418
indent: ['error', 2],
1519
'max-len': ['error', 120],
@@ -18,6 +22,7 @@ module.exports = {
1822
semi: ['error', 'always'],
1923
'no-underscore-dangle': 'off',
2024
'no-shadow': 'off',
25+
'class-methods-use-this': 'off',
2126
'@typescript-eslint/no-shadow': 'error',
2227
'import/prefer-default-export': 'off',
2328
'import/no-unresolved': 'off',

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"clean": "rimraf lib types",
1414
"build": "tsc && yarn copy-templates",
1515
"copy-templates": "copyfiles -u 3 \"./src/commands/create/templates/**/*\" \"./lib/commands/create/\"",
16+
"lint": "eslint \"src\"",
1617
"register:local": "yarn global add file:$PWD",
1718
"dev": "yarn clean && yarn build && yarn register:local"
1819
},
@@ -26,6 +27,7 @@
2627
"copyfiles": "^2.4.1",
2728
"eslint": "^8.38.0",
2829
"eslint-config-airbnb": "^19.0.4",
30+
"eslint-config-prettier": "^9.0.0",
2931
"eslint-plugin-import": "^2.27.5",
3032
"eslint-plugin-jsx-a11y": "^6.7.1",
3133
"eslint-plugin-prettier": "^5.0.1",

src/cli.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
#! /usr/bin/env node
2+
import chalk from 'chalk';
23

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

56
const command = process.argv[2];
67

78
if (command === CliCommand.Create) {
89
await import('./commands/create/cli.js');
10+
} else if (command === CliCommand.Help) {
11+
// eslint-disable-next-line no-console
12+
console.log(`${chalk.underline.blue(`${chalk.yellow('@adminjs/cli')} Commands List`)}
13+
14+
${chalk.underline('create')} Create an AdminJS project
15+
${chalk.underline('help')} List available CLI commands
16+
`);
917
} else {
10-
console.log('unknown command', command);
18+
// eslint-disable-next-line no-console
19+
console.log(chalk.red(`Unknown command: ${command}`));
20+
// eslint-disable-next-line no-console
21+
console.log(chalk.cyan(`Run ${chalk.yellow('adminjs help')} to see available commands.`));
1122
}

src/commands/create/cli.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import { unflatten } from 'flat';
44
import {
55
adapterOptions, packageManagerOptions, pluginOptions, databaseDriversForAdapter, environmentVariablesPrompts,
66
} from './options.js';
7-
import { CreateCommandHandler } from './handlers/CreateCommand.handler.js';
8-
import { CreateCommandPromptsAnswers } from './types.js';
7+
import { CreateCommand } from './command.js';
8+
import { CreateCommandInput } from './types.js';
99

1010
const questions: prompts.PromptObject[] = [
1111
{
@@ -53,7 +53,6 @@ const questions: prompts.PromptObject[] = [
5353
...environmentVariablesPrompts,
5454
];
5555

56-
const response = (await prompts(questions)) as unknown as CreateCommandPromptsAnswers;
57-
58-
const handler = new CreateCommandHandler(unflatten(response));
56+
const response = (await prompts(questions)) as unknown as CreateCommandInput;
57+
const handler = new CreateCommand(unflatten(response));
5958
await handler.run();

src/commands/create/handlers/CreateCommand.handler.ts renamed to src/commands/create/command.ts

+35-17
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,25 @@ import path from 'path';
33

44
import chalk from 'chalk';
55

6-
import {
7-
CreateCommandPromptsAnswers,
8-
} from '../types.js';
9-
import { BaseCommandHandler } from '../utils/BaseCommandHandler.js';
10-
import logger from '../../../utils/logger.js';
11-
import { asyncExec } from '../utils/async-exec.js';
6+
import logger from '../../utils/logger.js';
127
import {
138
displayRstInformation, displayWhatsNextTips, reportIssuesTip,
14-
} from '../../../instructions.js';
15-
import { displayStartTips } from '../instructions.js';
9+
} from '../../instructions.js';
1610

17-
import { BaseSetupHandler } from './BaseSetup.handler.js';
18-
import { LibrarySetupHandler, LibraryType } from './LibrarySetup.handler.js';
19-
import { EnvironmentVariablesHandler } from './EnvironmentVariables.handler.js';
20-
import { DatabaseDriverSetupHandler } from './DatabaseDriverSetup.handler.js';
11+
import { BaseCommandHandler } from './utils/BaseCommandHandler.js';
12+
import { asyncExec } from './utils/async-exec.js';
13+
import { displayStartTips } from './instructions.js';
14+
import { BaseSetupHandler } from './handlers/BaseSetup.handler.js';
15+
import { LibrarySetupHandler, LibraryType } from './handlers/LibrarySetup.handler.js';
16+
import { EnvironmentVariablesHandler } from './handlers/EnvironmentVariables.handler.js';
17+
import { DatabaseDriverSetupHandler } from './handlers/DatabaseDriverSetup.handler.js';
18+
import { NestSetupHandler } from './handlers/NestSetup.handler.js';
19+
import {
20+
AdminJSPlugin,
21+
CreateCommandInput,
22+
} from './types.js';
2123

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

33+
let nestSetupHandler: NestSetupHandler;
34+
if (this.options.plugin === AdminJSPlugin.NestJS) {
35+
nestSetupHandler = new NestSetupHandler(this.options, LibraryType.Plugin);
36+
}
37+
3138
try {
3239
await baseSetupHandler.run();
33-
await pluginSetupHandler.run();
34-
await adapterSetupHandler.run();
40+
41+
if (this.options.plugin === AdminJSPlugin.NestJS) {
42+
await nestSetupHandler.run();
43+
} else {
44+
await pluginSetupHandler.run();
45+
await adapterSetupHandler.run();
46+
}
47+
3548
await databaseDriverSetupHandler.run();
3649
await environmentVariablesHandler.run();
3750

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

4255
logger.info('Running post-setup scripts.');
4356
const driverInfo = databaseDriverSetupHandler.getDriverInfo();
44-
await pluginSetupHandler.postSetup(driverInfo);
45-
await adapterSetupHandler.postSetup(driverInfo);
57+
58+
if (this.options.plugin === AdminJSPlugin.NestJS) {
59+
await nestSetupHandler.postSetup(driverInfo);
60+
} else {
61+
await pluginSetupHandler.postSetup(driverInfo);
62+
await adapterSetupHandler.postSetup(driverInfo);
63+
}
4664

4765
const buildCommand = `${this.options.packageManager} run build`;
4866
logger.info(`Building: ${chalk.gray(buildCommand)}`);

src/commands/create/handlers/BaseSetup.handler.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import chalk from 'chalk';
55
import { copy } from 'fs-extra/esm';
66

77
import logger from '../../../utils/logger.js';
8-
import { CreateCommandPromptsAnswers } from '../types.js';
8+
import { CreateCommandInput } from '../types.js';
99
import { templatesDir } from '../utils/templates-dir.js';
1010
import { BaseCommandHandler } from '../utils/BaseCommandHandler.js';
1111
import { CONTENT_DIR_NAME, DOTFILES_DIR_NAME } from '../constants.js';
1212

13-
export class BaseSetupHandler extends BaseCommandHandler<CreateCommandPromptsAnswers> {
13+
export class BaseSetupHandler extends BaseCommandHandler<CreateCommandInput> {
1414
public async run() {
1515
logger.info(`Setting up ${chalk.yellow(this.options.projectName)} project's base template.`);
1616
await this.copyBaseContents();

src/commands/create/handlers/DatabaseDriverSetup.handler.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import fs from 'fs/promises';
44
import chalk from 'chalk';
55

66
import logger from '../../../utils/logger.js';
7-
import { AdminJSAdapter, CreateCommandPromptsAnswers } from '../types.js';
7+
import { AdminJSAdapter, CreateCommandInput } from '../types.js';
88
import { BaseCommandHandler } from '../utils/BaseCommandHandler.js';
99

1010
import { EnvironmentVariablesHandler } from './EnvironmentVariables.handler.js';
@@ -67,14 +67,14 @@ export interface DriverInfo {
6767
dialectName: string;
6868
}
6969

70-
export class DatabaseDriverSetupHandler extends BaseCommandHandler<CreateCommandPromptsAnswers> {
70+
export class DatabaseDriverSetupHandler extends BaseCommandHandler<CreateCommandInput> {
7171
protected driverLibrary: typeof DB_DRIVERS_LIBRARIES[keyof typeof DB_DRIVERS_LIBRARIES];
7272

7373
protected dialectName: string;
7474

7575
private environmentVariablesHandler: EnvironmentVariablesHandler;
7676

77-
constructor(options: CreateCommandPromptsAnswers, environmentVariablesHandler: EnvironmentVariablesHandler) {
77+
constructor(options: CreateCommandInput, environmentVariablesHandler: EnvironmentVariablesHandler) {
7878
super(options);
7979

8080
this.environmentVariablesHandler = environmentVariablesHandler;

src/commands/create/handlers/EnvironmentVariables.handler.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import randomstring from 'randomstring';
55
import chalk from 'chalk';
66

77
import logger from '../../../utils/logger.js';
8-
import { CreateCommandPromptsAnswers } from '../types.js';
8+
import { CreateCommandInput } from '../types.js';
99
import { BaseCommandHandler } from '../utils/BaseCommandHandler.js';
1010

1111
const DEFAULT_ENVS = {
@@ -19,10 +19,10 @@ const DEFAULT_ENVS = {
1919
PORT: 3000,
2020
};
2121

22-
export class EnvironmentVariablesHandler extends BaseCommandHandler<CreateCommandPromptsAnswers> {
22+
export class EnvironmentVariablesHandler extends BaseCommandHandler<CreateCommandInput> {
2323
protected environmentVariables: Record<string, unknown>;
2424

25-
constructor(options: CreateCommandPromptsAnswers) {
25+
constructor(options: CreateCommandInput) {
2626
super(options);
2727

2828
this.environmentVariables = DEFAULT_ENVS;

src/commands/create/handlers/LibrarySetup.handler.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { copy } from 'fs-extra/esm';
55
import chalk from 'chalk';
66

77
import logger from '../../../utils/logger.js';
8-
import { AdminJSAdapter, AdminJSPlugin, CreateCommandPromptsAnswers } from '../types.js';
8+
import { AdminJSAdapter, AdminJSPlugin, CreateCommandInput } from '../types.js';
99
import { templatesDir } from '../utils/templates-dir.js';
1010
import { BaseCommandHandler } from '../utils/BaseCommandHandler.js';
1111
import { CONFIG_DIR_NAME, CONTENT_DIR_NAME, SCRIPTS_DIR_NAME } from '../constants.js';
@@ -22,12 +22,12 @@ export interface LibrarySetupHandlerConfiguration {
2222
type: LibraryType;
2323
}
2424

25-
export class LibrarySetupHandler extends BaseCommandHandler<CreateCommandPromptsAnswers> {
25+
export class LibrarySetupHandler extends BaseCommandHandler<CreateCommandInput> {
2626
protected libraryType: LibraryType;
2727

2828
protected libraryName: AdminJSAdapter | AdminJSPlugin;
2929

30-
constructor(options: CreateCommandPromptsAnswers, libraryType: LibraryType) {
30+
constructor(options: CreateCommandInput, libraryType: LibraryType) {
3131
super(options);
3232

3333
this.libraryType = libraryType;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import chalk from 'chalk';
2+
3+
import { logger } from '../../../index.js';
4+
5+
import { LibrarySetupHandler } from './LibrarySetup.handler.js';
6+
7+
export class NestSetupHandler extends LibrarySetupHandler {
8+
public async run() {
9+
await super.run();
10+
await this.setupAdapter();
11+
}
12+
13+
public async setupAdapter() {
14+
logger.info(chalk.red('--------------- IMPORTANT ---------------'));
15+
logger.info(`The CLI does not support adapter setup for: ${chalk.yellow('@adminjs/nestjs')}`);
16+
// eslint-disable-next-line max-len
17+
logger.info(`${chalk.yellow('@adminjs/cli')} will bootstrap a ${chalk.yellow('NestJS + AdminJS')} application, but you will have to set up the adapter manually.`);
18+
// eslint-disable-next-line max-len
19+
logger.info(`Please refer to ${chalk.underline.magenta(`https://docs.adminjs.co/installation/adapters/${this.options.adapter}`)} for instructions.`);
20+
logger.info(chalk.red('-----------------------------------------'));
21+
}
22+
}

src/commands/create/handlers/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export * from './BaseSetup.handler.js';
2-
export * from './CreateCommand.handler.js';
32
export * from './DatabaseDriverSetup.handler.js';
43
export * from './EnvironmentVariables.handler.js';
54
export * from './LibrarySetup.handler.js';
5+
export * from './NestSetup.handler.js';

src/commands/create/options.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export const pluginOptions = [
1414
{ title: '@adminjs/fastify', value: AdminJSPlugin.Fastify },
1515
{ title: '@adminjs/koa', value: AdminJSPlugin.Koa },
1616
{ title: '@adminjs/hapi', value: AdminJSPlugin.Hapi },
17-
{ title: '@adminjs/nestjs', value: AdminJSPlugin.NestJS, disabled: true },
17+
{ title: '@adminjs/nestjs', value: AdminJSPlugin.NestJS },
1818
];
1919

2020
export const adapterOptions = [
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"jest": {
3+
"moduleFileExtensions": [
4+
"js",
5+
"json",
6+
"ts"
7+
],
8+
"rootDir": "src",
9+
"testRegex": ".*\\.spec\\.ts$",
10+
"transform": {
11+
"^.+\\.(t|j)s$": "ts-jest"
12+
},
13+
"collectCoverageFrom": [
14+
"**/*.(t|j)s"
15+
],
16+
"coverageDirectory": "../coverage",
17+
"testEnvironment": "node"
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"@adminjs/express": "^6.1.0",
3+
"@adminjs/nestjs": "^6.1.0",
4+
"@nestjs/common": "^10.0.0",
5+
"@nestjs/config": "^3.1.1",
6+
"@nestjs/core": "^10.0.0",
7+
"@nestjs/platform-express": "^10.0.0",
8+
"adminjs": "^7.4.0",
9+
"express-formidable": "^1.2.0",
10+
"express-session": "^1.17.3",
11+
"reflect-metadata": "^0.1.13",
12+
"rxjs": "^7.8.1"
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"@nestjs/cli": "^10.0.0",
3+
"@nestjs/schematics": "^10.0.0",
4+
"@nestjs/testing": "^10.0.0",
5+
"@types/express": "^4.17.17",
6+
"@types/jest": "^29.5.2",
7+
"@types/node": "^20.3.1",
8+
"@types/supertest": "^2.0.12",
9+
"@typescript-eslint/eslint-plugin": "^6.0.0",
10+
"@typescript-eslint/parser": "^6.0.0",
11+
"eslint": "^8.42.0",
12+
"eslint-config-prettier": "^9.0.0",
13+
"eslint-plugin-prettier": "^5.0.0",
14+
"jest": "^29.5.0",
15+
"prettier": "^3.0.0",
16+
"source-map-support": "^0.5.21",
17+
"supertest": "^6.3.3",
18+
"ts-jest": "^29.1.0",
19+
"ts-loader": "^9.4.3",
20+
"ts-node": "^10.9.1",
21+
"tslib": "^2.5.0",
22+
"tsconfig-paths": "^4.2.0"
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"build": "nest build",
3+
"start": "nest start",
4+
"start:dev": "nest start --watch",
5+
"start:debug": "nest start --debug --watch",
6+
"start:prod": "node dist/main",
7+
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
8+
"test": "jest",
9+
"test:watch": "jest --watch",
10+
"test:cov": "jest --coverage",
11+
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
12+
"test:e2e": "jest --config ./test/jest-e2e.json"
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"$schema": "https://json.schemastore.org/nest-cli",
3+
"collection": "@nestjs/schematics",
4+
"sourceRoot": "src",
5+
"compilerOptions": {
6+
"deleteOutDir": true
7+
}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Test, TestingModule } from '@nestjs/testing';
2+
3+
import { AppController } from './app.controller';
4+
import { AppService } from './app.service';
5+
6+
describe('AppController', () => {
7+
let appController: AppController;
8+
9+
beforeEach(async () => {
10+
const app: TestingModule = await Test.createTestingModule({
11+
controllers: [AppController],
12+
providers: [AppService],
13+
}).compile();
14+
15+
appController = app.get<AppController>(AppController);
16+
});
17+
18+
describe('root', () => {
19+
it('should return "Hello World!"', () => {
20+
expect(appController.getHello()).toBe('Hello World!');
21+
});
22+
});
23+
});

0 commit comments

Comments
 (0)