@notadd/cli
Version:
notadd core none dependence
946 lines (926 loc) • 36.4 kB
text/typescript
import { Command } from '@notadd/cli-core';
import { join } from 'path';
import { readFileSync, writeFileSync, ensureDirSync, readdirSync, ensureFileSync, readJSONSync, pathExistsSync } from 'fs-extra';
import { upperFirst, lowerFirst, compact } from "lodash";
import { Controller, Args } from '@notadd/core';
export class GenerateCommand {
build( merge: boolean = false) {
const entities = this._readEntities();
this._createEntities(entities);
this._createBasic(entities);
this._createDomain(entities);
if (merge) {
this._createApi(entities);
} else {
this._createApiV2(entities);
}
// this._createJestTest(entities);
}
private _readEntities() {
const fileNames = readdirSync(process.cwd()).filter((it) => it.includes('.entity.ts'));
const dirName = process.cwd().split('/').pop();
if (!dirName) throw new Error('文件夹名或位置不正确');
if (fileNames.length == 0) {
throw new Error('未找到.entity.ts文件');
}
const entities = fileNames.map((it) => {
const content = readFileSync(join(process.cwd(), it)).toString();
const entityName = content.match(/class ([^\s]*Entity)/);
if (!entityName || !entityName[1]) throw new Error(`${it}文件没有Entity结尾的class`);
const fileds = content.match(/[^\s]*\??\:\s*(number|string|any|Date|boolean|Array|Object).*/g);
if (!fileds || fileds.length == 0) throw new Error(`${it}文件没有Entity结尾的class`);
const filedNames = compact(fileds.map(it => {
const filedsMatch = it.match(/([^\s]*)\??\:\s*(number|string|any|Date|boolean|Array|Object).*/);
if (filedsMatch) {
const filedName = filedsMatch[1].replace('?', '').trim();
const type = filedsMatch[2].trim();
return filedName;
}
return null;
}))
return {
fileName: it,
content,
entityName: entityName[1].trim(),
fileds,
dirName,
filedNames
};
});
return entities;
}
private _createEntities(entities: any[]) {
// 导入文件 导入文件名 导出文件
const { importFile, exportFile } = this._importExportFileAndImportNames(entities, 'entity');
// 创建.module.ts
const moduleContent = `
import { Module } from '@notadd/core';
import { TypeormModule } from '@notadd/typeorm';${importFile}
export class ${upperFirst(entities[0].dirName)}EntitiesModule {}
`;
const entitiesModuleUrl = join(process.cwd(), `${entities[0].dirName}.module.ts`);
if (pathExistsSync(entitiesModuleUrl)) {
console.log(`entities层已存在module文件,所以未生成`)
} else {
writeFileSync(entitiesModuleUrl, moduleContent);
}
//创建此模块的index.ts 和修改模块的导出
this._createIndexTs(entities[0].dirName, process.cwd(), exportFile)
}
private _createBasic(entities: any[]) {
const dirName = entities[0].dirName;
// 获取不同层的package.json
const { basicDir, entitiesPakcageJson } = this._getPackageJsons(entities);
ensureDirSync(basicDir)
//创建basic文件
entities.forEach(it => {
const thisFileUrl = join(basicDir, it.fileName.replace('.entity.ts', '.basic.ts'))
// 如果在basic层已经存在就return
if (pathExistsSync(thisFileUrl)) {
console.log(`basic层${it.fileName.replace('.entity.ts', '.basic.ts')}已存在,所以未生成`)
return
}
const basicName = it.entityName.replace(/Entity$/, 'Basic');
const usedEntity = lowerFirst(it.entityName.replace(/Entity$/, ''))
const basicContent = `
import { Injectable, Inject } from '@notadd/core';
import { Repository } from '@notadd/typeorm';
import { Limit } from '@notadd/graphql';
import { ${it.entityName} } from '${entitiesPakcageJson.name}';
export class ${basicName} {
constructor(
public ${usedEntity}: Repository<${it.entityName}>
) {}
/**
* 查询列表
*/
async find${it.entityName.replace(/Entity$/, '')}List(
where?: any,
limit?: Limit,
order?: any
): Promise<[${it.entityName}[], number]> {
const page = limit && limit.page ? limit.page : 1;
const psize = limit && limit.psize ? limit.psize : 20;
let it = this.${usedEntity}
.createQueryBuilder('entity')
return it
.orderBy(order)
.skip((page - 1) * psize)
.take(psize)
.getManyAndCount();
}
}`
writeFileSync(thisFileUrl, basicContent);
});
// 导入文件 导入文件名 导出文件
const { importFile, importNames, exportFile } = this._importExportFileAndImportNames(entities, 'basic');
// 创建.module.ts
const moduleContent = `
import { Module } from '@notadd/core';
import { ${upperFirst(dirName)}EntitiesModule } from '${entitiesPakcageJson.name}';${importFile}
export class ${upperFirst(dirName)}BasicModule {}
`;
const basicModuleName = `${dirName}.module.ts`
const basicModuleUrl = join(basicDir, basicModuleName)
if (pathExistsSync(basicModuleUrl)) {
console.log(`basic层已存在${basicModuleName}文件,所以未生成`)
} else {
writeFileSync(basicModuleUrl, moduleContent);
}
//创建此模块的index.ts 和修改模块的导出
this._createIndexTs(dirName, basicDir, exportFile)
}
private _createDomain(entities: any[]) {
const dirName = entities[0].dirName;
// 获取不同层的package.json
const { domainDir, entitiesPakcageJson, basicPakcageJson } = this._getPackageJsons(entities);
ensureDirSync(domainDir)
//创建domain文件
entities.forEach(it => {
const thisFileUrl = join(domainDir, it.fileName.replace('.entity.ts', '.service.ts'))
// 如果在domain层已经存在就return
if (pathExistsSync(thisFileUrl)) {
console.log(`domain层${it.fileName.replace('.entity.ts', '.service.ts')}已存在,所以未生成`)
return
}
const basicName = it.entityName.replace(/Entity$/, 'Basic');
const domainName = it.entityName.replace(/Entity$/, 'Service');
const usedEntity = lowerFirst(it.entityName.replace(/Entity$/, ''))
const domainContent = `
import { TypeormError, TypeError } from '@ganker/error';
import { Limit } from '@notadd/graphql';
import { Injectable, Inject, Logger } from '@notadd/core';
import { DeepPartial, Repository } from '@notadd/typeorm';
import { ClassValidatorService } from '@notadd/class-validator';
import { ${it.entityName} } from '${entitiesPakcageJson.name}';
import { ${basicName} } from '${basicPakcageJson.name}';
export class ${domainName} {
constructor(
private ${usedEntity}: Repository<${it.entityName}>,
private readonly ${lowerFirst(basicName)}: ${basicName},
private readonly validator: ClassValidatorService,
private logger: Logger,
) {}
/**
* 添加
*/
async add(input: DeepPartial<${it.entityName}>): Promise<${it.entityName}> {
const errMessage = await this.validator.validateOrMessage(input, ${it.entityName});
if (errMessage) throw new TypeError('02', errMessage);
try {
const entity = this.${usedEntity}.create(input);
const res = await this.${usedEntity}.save(entity);
res.id = this.${usedEntity}.getId(res);
return res;
} catch (e) {
this.logger.info(e.message);
throw new TypeormError('01', e.message);
}
}
/**
* 删除
*/
async deleteById(id: number): Promise<any> {
if (!id || id <= 0) {
throw new TypeError('02', 'id不能为空');
}
const item = await this.${usedEntity}.findOne({ id });
if (!item) {
throw new TypeError('03', '此记录未找到或已删除');
}
try {
await this.${usedEntity}.delete({ id });
return item;
} catch (e) {
this.logger.info(e.message);
throw new TypeormError('01', e.message);
}
}
/**
* 修改
*/
async updateById(id: number, entity: any): Promise<any> {
if (!id || id <= 0) {
throw new TypeError('03', 'id不能为空');
}
const item = await this.${usedEntity}.findOne({ id });
if (!item) {
throw new TypeError('04', '修改失败,未找到要修改的数据或已删除');
}
const errMessage = await this.validator.validateOrMessage(entity, ${it.entityName}, {
skipMissingProperties: true,
});
if (errMessage) throw new TypeError('02', errMessage);
try {
await this.${usedEntity}.update({ id }, entity);
return item;
} catch (e) {
this.logger.info(e.message);
throw new TypeormError('01', e.message);
}
}
/**
* 列表
*/
async list(where?: any, limit?: Limit, order?: any): Promise<any> {
try {
if (order) {
order = Object.keys(order).reduce((newData, key) => {
let newKey = 'entity.' + key;
newData[newKey] = order[key];
return newData;
}, {});
} else {
order = { 'entity.createDate': 'DESC' };
}
const [list, count] = await this.${lowerFirst(basicName)}.find${it.entityName.replace(/Entity$/, '')}List(where, limit, order);
return { list, count };
} catch (e) {
this.logger.info(e.message);
throw new TypeormError('01', e.message);
}
}
/**
* 详情
*/
async detailById(id: number): Promise<${it.entityName}> {
if (!id || id <= 0) {
throw new TypeError('01', 'id不能为空');
}
const item = await this.${usedEntity}.findOne({ id });
if (!item) {
throw new TypeError('02', '查询失败,未找到要查询的数据或已删除');
}
return item;
}
}`
writeFileSync(thisFileUrl, domainContent);
});
// 导入文件 导入文件名 导出文件
const { importFile, importNames, exportFile } = this._importExportFileAndImportNames(entities, 'service');
// 创建.module.ts
const moduleContent = `
import { Module } from '@notadd/core';
import { ClassValidatorModule } from '@notadd/class-validator';
import { ${upperFirst(dirName)}BasicModule } from '${basicPakcageJson.name}';${importFile}
export class ${upperFirst(dirName)}DomainModule {}
`;
const basicModuleName = `${dirName}.module.ts`
const basicModuleUrl = join(domainDir, basicModuleName)
if (pathExistsSync(basicModuleUrl)) {
console.log(`domain层已存在${basicModuleName}文件,所以未生成`)
} else {
writeFileSync(basicModuleUrl, moduleContent);
}
//创建此模块的index.ts 和修改模块的导出
this._createIndexTs(dirName, domainDir, exportFile)
}
private _createApi(entities: any[]) {
const dirName = entities[0].dirName;
// 获取不同层的package.json
const { apiDir, entitiesPakcageJson, domainPakcageJson } = this._getPackageJsons(entities);
ensureDirSync(apiDir);
//创建api文件
entities.forEach(it => {
const filedNames: string[] = it.filedNames;
const pickList = filedNames.map((filed, filedIndex) => {
if (filedIndex == filedNames.length - 1) {
return `'${filed}'`
}
return `'${filed}' | `
}).reduce((acc, cur) => {
return (acc += cur);
}, '');
const thisFileUrl = join(apiDir, it.fileName.replace('.entity.ts', '.api.ts'))
// 如果在domain层已经存在就return
if (pathExistsSync(thisFileUrl)) {
console.log(`api层${it.fileName.replace('.entity.ts', '.api.ts')}已存在,所以未生成`)
return
}
const domainName = it.entityName.replace(/Entity$/, 'Service');
const apiName = it.entityName.replace(/Entity$/, 'ApiController');
const usedEntity = lowerFirst(it.entityName.replace(/Entity$/, ''))
const entityPre = it.entityName.replace(/Entity$/, '');
const apiContent = `
import { Mutation, Query, Limit, ListCount } from '@notadd/graphql';
import { Args, Controller } from '@notadd/core';
import { GraphqlError } from '@ganker/error';
import { ${domainName} } from '${domainPakcageJson.name}';
import { ${it.entityName} } from '${entitiesPakcageJson.name}';
export type ${entityPre}AddInput = Pick<
${it.entityName}, ${pickList}
>;
interface ${entityPre}ListInputWhere {
// TUDO
}
type ${entityPre}UpdateInputEntity = Partial<
Pick<
${it.entityName}, ${pickList}
>
>;
interface ${entityPre}ListInputOrder {
createDate?: string;
}
type ${entityPre}ListResult = Partial<
Pick<
${it.entityName}, ${pickList}
>
>;
export class ${apiName} {
constructor(private readonly ${usedEntity}: ${domainName}) {}
/**
* 添加
*/
async ${usedEntity}Add(
entity: ${entityPre}AddInput
): Promise<any> {
try {
return await this.${usedEntity}.add(entity);
} catch (e) {
throw new GraphqlError(\`B200101\${e.code}\`, e.message);
}
}
/**
* 删除
*/
async ${usedEntity}DeleteById( id: number): Promise<any> {
try {
return await this.${usedEntity}.deleteById(id);
} catch (e) {
throw new GraphqlError(\`B200102\${e.code}\`, e.message);
}
}
/**
* 列表
*/
async ${usedEntity}List(
where?: ${entityPre}ListInputWhere,
limit?: Limit,
order?: ${entityPre}ListInputOrder
): Promise<ListCount<${entityPre}ListResult>> {
try {
return await this.${usedEntity}.list(where, limit, order);
} catch (e) {
throw new GraphqlError(\`B200103\${e.code}\`, e.message);
}
}
/**
* 修改
*/
async ${usedEntity}UpdateById(
id: number,
entity: ${entityPre}UpdateInputEntity
): Promise<any> {
try {
return await this.${usedEntity}.updateById(id, entity);
} catch (e) {
throw new GraphqlError(\`B200104\${e.code}\`, e.message);
}
}
/**
* 详情
*/
async ${usedEntity}DetailById(
id: number
): Promise<${it.entityName}> {
try {
return await this.${usedEntity}.detailById(id);
} catch (e) {
throw new GraphqlError(\`B200105\${e.code}\`, e.message);
}
}
}
`
writeFileSync(thisFileUrl, apiContent);
});
// 导入文件 导入文件名 导出文件
const { importFile, importNames, exportFile } = this._importExportFileAndImportNames(entities, 'api');
// 创建.module.ts
const moduleContent = `
import { Module } from '@notadd/core';
import { ${upperFirst(dirName)}DomainModule } from '${domainPakcageJson.name}';${importFile}
export class ${upperFirst(dirName)}ApiModule {}
`;
const apiModuleName = `${dirName}.module.ts`
const apiModuleUrl = join(apiDir, apiModuleName)
if (pathExistsSync(apiModuleUrl)) {
console.log(`api层已存在${apiModuleName}文件,所以未生成`)
} else {
writeFileSync(apiModuleUrl, moduleContent);
}
//创建此模块的index.ts 和修改模块的导出
this._createIndexTs(dirName, apiDir, exportFile)
}
private _createApiV2(entities: any[]) {
const dirName = entities[0].dirName;
// 获取不同层的package.json
const { apiDir, entitiesPakcageJson, domainPakcageJson } = this._getPackageJsons(entities);
ensureDirSync(apiDir);
//创建api文件
entities.forEach(it => {
const filedNames: string[] = it.filedNames;
const pickList = filedNames.map((filed, filedIndex) => {
if (filedIndex == filedNames.length - 1) {
return `'${filed}'`
}
return `'${filed}' | `
}).reduce((acc, cur) => {
return (acc += cur);
}, '');
const entityFileName = it.fileName.replace('.entity.ts', '')
const domainName = it.entityName.replace(/Entity$/, 'Service');
const usedEntity = lowerFirst(it.entityName.replace(/Entity$/, ''))
const entityPre = it.entityName.replace(/Entity$/, '');
const addName = it.entityName.replace(/Entity$/, 'AddApiController');
const listName = it.entityName.replace(/Entity$/, 'ListApiController');
const updateName = it.entityName.replace(/Entity$/, 'UpdateApiController');
const deleteName = it.entityName.replace(/Entity$/, 'DeleteApiController');
const detailName = it.entityName.replace(/Entity$/, 'DetailApiController');
const addContent = `
import { Mutation } from '@notadd/graphql';
import { Args, Controller, EntityService } from '@notadd/core';
import { ClassValidatorService } from '@notadd/class-validator';
import { GraphqlError, TypeError } from '@ganker/error';
import { ${domainName} } from '${domainPakcageJson.name}';
import { ${it.entityName} } from '${entitiesPakcageJson.name}';
export type ${entityPre}AddInput = Pick<
${it.entityName}, ${pickList}
>;
export class ${addName} {
constructor(
private readonly entityService: EntityService,
private readonly validator: ClassValidatorService,
private readonly ${usedEntity}: ${domainName}
) {}
/**
* 添加
*/
async ${usedEntity}Add(
entity: ${entityPre}AddInput
): Promise<any> {
try {
const created = await this.entityService.createType(${it.entityName}, entity);
const errMessage = await this.validator.validateOrMessage(created, ${it.entityName});
if (errMessage) throw new TypeError('02', errMessage);
return await this.${usedEntity}.add(created);
} catch (e) {
throw new GraphqlError(\`B200101\${e.code}\`, e.message);
}
}
}
`
if (!pathExistsSync(apiDir + `/${entityFileName}-add.api.ts`)) {
writeFileSync(apiDir + `/${entityFileName}-add.api.ts`, addContent);
}
const listContent = `
import { Query, Limit, ListCount } from '@notadd/graphql';
import { Args, Controller } from '@notadd/core';
import { GraphqlError } from '@ganker/error';
import { ${domainName} } from '${domainPakcageJson.name}';
import { ${it.entityName} } from '${entitiesPakcageJson.name}';
interface ${entityPre}ListInputWhere {
ids?: number[]
}
interface ${entityPre}ListInputOrder {
createDate?: string;
}
type ${entityPre}ListResult = Partial<
Pick<
${it.entityName}, ${pickList}
>
>;
export class ${listName} {
constructor(private readonly ${usedEntity}: ${domainName}) {}
/**
* 列表
*/
async ${usedEntity}List(
where?: ${entityPre}ListInputWhere,
limit?: Limit,
order?: ${entityPre}ListInputOrder
): Promise<ListCount<${entityPre}ListResult>> {
try {
return await this.${usedEntity}.list(where, limit, order);
} catch (e) {
throw new GraphqlError(\`B200103\${e.code}\`, e.message);
}
}
}
`
if (!pathExistsSync(apiDir + `/${entityFileName}-list.api.ts`)) {
writeFileSync(apiDir + `/${entityFileName}-list.api.ts`, listContent);
}
const updateContent = `
import { Mutation } from '@notadd/graphql';
import { Args, Controller } from '@notadd/core';
import { ClassValidatorService } from '@notadd/class-validator';
import { GraphqlError, TypeError } from '@ganker/error';
import { ${domainName} } from '${domainPakcageJson.name}';
import { ${it.entityName} } from '${entitiesPakcageJson.name}';
type ${entityPre}UpdateInputEntity = Partial<
Pick<
${it.entityName}, ${pickList}
>
>;
export class ${updateName} {
constructor(
private readonly validator: ClassValidatorService,
private readonly ${usedEntity}: ${domainName}
) {}
/**
* 修改
*/
async ${usedEntity}UpdateById(
id: number,
entity: ${entityPre}UpdateInputEntity
): Promise<any> {
try {
const errMessage = await this.validator.validateOrMessage(entity, ${it.entityName}, {
skipMissingProperties: true,
});
if (errMessage) throw new TypeError('02', errMessage);
return await this.${usedEntity}.updateById(id, entity);
} catch (e) {
throw new GraphqlError(\`B200104\${e.code}\`, e.message);
}
}
}
`
if (!pathExistsSync(apiDir + `/${entityFileName}-update.api.ts`)) {
writeFileSync(apiDir + `/${entityFileName}-update.api.ts`, updateContent);
}
const deleteContent = `
import { Mutation } from '@notadd/graphql';
import { Args, Controller } from '@notadd/core';
import { GraphqlError } from '@ganker/error';
import { ${domainName} } from '${domainPakcageJson.name}';
export class ${deleteName} {
constructor(private readonly ${usedEntity}: ${domainName}) {}
/**
* 删除
*/
async ${usedEntity}DeleteById( id: number): Promise<any> {
try {
return await this.${usedEntity}.deleteById(id);
} catch (e) {
throw new GraphqlError(\`B200102\${e.code}\`, e.message);
}
}
}
`
if (!pathExistsSync(apiDir + `/${entityFileName}-delete.api.ts`)) {
writeFileSync(apiDir + `/${entityFileName}-delete.api.ts`, deleteContent);
}
const detailContent = `
import { Query } from '@notadd/graphql';
import { Args, Controller } from '@notadd/core';
import { GraphqlError } from '@ganker/error';
import { ${domainName} } from '${domainPakcageJson.name}';
import { ${it.entityName} } from '${entitiesPakcageJson.name}';
export class ${detailName} {
constructor(private readonly ${usedEntity}: ${domainName}) {}
/**
* 详情
*/
async ${usedEntity}DetailById(
id: number
): Promise<${it.entityName}> {
try {
return await this.${usedEntity}.detailById(id);
} catch (e) {
throw new GraphqlError(\`B200105\${e.code}\`, e.message);
}
}
}
`
if (!pathExistsSync(apiDir + `/${entityFileName}-detail.api.ts`)) {
writeFileSync(apiDir + `/${entityFileName}-detail.api.ts`, detailContent);
}
});
// 导入文件 导入文件名 导出文件
const importFile = entities.map(it => {
const entityFileName = it.fileName.replace('.entity.ts', '')
const addName = it.entityName.replace(/Entity$/, 'AddApiController');
const listName = it.entityName.replace(/Entity$/, 'ListApiController');
const updateName = it.entityName.replace(/Entity$/, 'UpdateApiController');
const deleteName = it.entityName.replace(/Entity$/, 'DeleteApiController');
const detailName = it.entityName.replace(/Entity$/, 'DetailApiController');
return `
import { ${addName} } from './${entityFileName}-add.api';
import { ${listName} } from './${entityFileName}-list.api';
import { ${updateName} } from './${entityFileName}-update.api';
import { ${deleteName} } from './${entityFileName}-delete.api';
import { ${detailName} } from './${entityFileName}-detail.api';`
}).reduce((acc, cur) => {
return (acc += cur);
}, '');
const importNames = entities.map(it => {
const addName = it.entityName.replace(/Entity$/, 'AddApiController');
const listName = it.entityName.replace(/Entity$/, 'ListApiController');
const updateName = it.entityName.replace(/Entity$/, 'UpdateApiController');
const deleteName = it.entityName.replace(/Entity$/, 'DeleteApiController');
const detailName = it.entityName.replace(/Entity$/, 'DetailApiController');
return `${addName},
${listName},
${updateName},
${deleteName},
${detailName},
`
}).reduce((acc, cur) => {
return (acc += cur);
}, '').trim();
const exportFile = entities.map(it => {
const entityFileName = it.fileName.replace('.entity.ts', '')
return `
export * from './${entityFileName}-add.api';
export * from './${entityFileName}-list.api';
export * from './${entityFileName}-update.api';
export * from './${entityFileName}-delete.api';
export * from './${entityFileName}-detail.api';`
}).reduce((acc, cur) => {
return (acc += cur);
}, '')
// 创建.module.ts
const moduleContent = `
import { Module } from '@notadd/core';
import { ClassValidatorModule } from '@notadd/class-validator';
import { ${upperFirst(dirName)}DomainModule } from '${domainPakcageJson.name}';${importFile}
export class ${upperFirst(dirName)}ApiModule {}
`;
const apiModuleName = `${dirName}.module.ts`
const apiModuleUrl = join(apiDir, apiModuleName)
if (pathExistsSync(apiModuleUrl)) {
console.log(`api层已存在${apiModuleName}文件,所以未生成`)
} else {
writeFileSync(apiModuleUrl, moduleContent);
}
//创建此模块的index.ts 和修改模块的导出
this._createIndexTs(dirName, apiDir, exportFile)
}
private _createJestTest(entities: any[]) {
const dirName = entities[0].dirName;
// 获取不同层的package.json
const { apiDir, apiPakcageJson, entitiesPakcageJson } = this._getPackageJsons(entities);
ensureDirSync(apiDir);
//创建api文件
entities.forEach(it => {
const thisFileUrl = join(apiDir, it.fileName.replace('.entity.ts', '.api.test.ts'))
// 如果在api层已经存在就return
if (pathExistsSync(thisFileUrl)) {
console.log(`api层${it.fileName.replace('.entity.ts', '.api.test.ts')}已存在,所以未生成`)
return
}
const apiName = it.entityName.replace(/Entity$/, 'ApiController');
const usedEntity = lowerFirst(it.entityName.replace(/Entity$/, ''))
const entityPre = it.entityName.replace(/Entity$/, '');
const apiContent = `
import { Injector, MAIN_PATH, Module, CurrentMetadataKey, CURRENT } from '@notadd/core';
import { HTTP_IP } from '@notadd/http';
import { platformNode } from '@notadd/platform-node';
import { TypeormPostgresEnvModule } from '@notadd/typeorm';
import { join } from 'path';
import { equal } from 'assert';
import { graphqlProviders } from '@notadd/graphql/lib/handlers';
import { ${it.entityName} } from '${entitiesPakcageJson.name}';
import { ${apiName}, ${entityPre}AddInput } from './${it.fileName.replace('.entity.ts', '.api')}';
import { ${upperFirst(dirName)}ApiModule } from './${dirName}.module';
export class JestApiModule {}
describe('${apiPakcageJson.name}/${dirName}/${it.fileName.replace('.entity.ts', '.api')}', () => {
let root: Injector;
let api: ${apiName};
beforeAll(async (down) => {
const ref = platformNode([
{
provide: MAIN_PATH,
useValue: join(__dirname, '../main.ts'),
},
{
provide: CURRENT,
useValue: {
openid: 'fromUser',
id: 1,
username: 'system',
domainId: 1,
departmentId: 1,
},
},
]);
const moduleRef = await ref.bootstrapModule(JestApiModule);
root = moduleRef.injector;
const req = root.create([
{
provide: HTTP_IP,
useValue: '127.0.0.1',
},
{
provide: CurrentMetadataKey,
useValue: currentHandler,
},
]);
api = req.get(${apiName});
down();
}, 1000 * 20);
it('test list', async () => {
const list = await api.${usedEntity}List();
equal(list.count >= 0, true);
const paramList = await api.${usedEntity}List({}, { page: 1, psize: 20 }, { createDate: 'DESC' });
equal(paramList.count >= 0, true);
});
// TUDO
const addOptions: ${entityPre}AddInput = { };
let seccessAdded: ${it.entityName};
it('test add', async () => {
seccessAdded = await api.${usedEntity}Add(addOptions);
});
it('test update', async () => {
try {
const item = await api.${usedEntity}UpdateById(-1, {});
} catch (e) {
equal(e.extensions.code == 'B20010403', true);
}
// TUDO
// const item = await api.${usedEntity}UpdateById(seccessAdded.id, { title: '自动化测试修改的名称' });
// equal(item.id == seccessAdded.id, true);
});
it('test detail', async () => {
try {
const item = await api.${usedEntity}DetailById(-1);
} catch (e) {
equal(e.extensions.code == 'B20010501', true);
}
const item = await api.${usedEntity}DetailById(seccessAdded.id);
equal(item.id == seccessAdded.id, true);
});
it('test delete', async () => {
try {
const del = await api.${usedEntity}DeleteById(-1);
} catch (e) {
equal(e.extensions.code == 'B20010202', true);
}
const del = await api.${usedEntity}DeleteById(seccessAdded.id);
equal(del.id == seccessAdded.id, true);
});
it('test deleted update', async () => {
try {
const item = await api.${usedEntity}UpdateById(seccessAdded.id, {});
} catch (e) {
equal(e.extensions.code == 'B20010404', true);
}
});
it('test deleted detail', async () => {
try {
const item = await api.${usedEntity}DetailById(seccessAdded.id);
} catch (e) {
equal(e.extensions.code == 'B20010502', true);
}
});
it('test deleted delete', async () => {
try {
const item = await api.${usedEntity}DeleteById(seccessAdded.id);
} catch (e) {
equal(e.extensions.code == 'B20010203', true);
}
});
});
`
writeFileSync(thisFileUrl, apiContent);
});
}
/**
* 导入/导出/导入类名 的列表
* @param {any[]} entities
* @param {string} ext
*/
private _importExportFileAndImportNames(entities: any[], ext: 'entity' | 'basic' | 'service' | 'api') {
const upperExt = upperFirst(ext);
const importFile = entities.map(it => {
const name = it.entityName.replace(/Entity$/, `${upperExt == 'Api' ? 'ApiController' : upperExt}`);
return `
import { ${name} } from './${it.fileName.replace('.entity.ts', `.${ext}`)}';`
}).reduce((acc, cur) => {
return (acc += cur);
}, '');
const exportFile = entities.map(it => {
return `
export * from './${it.fileName.replace('.entity.ts', `.${ext}`)}';`
}).reduce((acc, cur) => {
return (acc += cur);
}, '');
const importNames = entities.map(it => {
const name = it.entityName.replace(/Entity$/, `${upperExt == 'Api' ? 'ApiController' : upperExt}`);
return `
${name},`
}).reduce((acc, cur) => {
return (acc += cur);
}, '').trim();
return { importFile, exportFile, importNames }
}
/**
* 创建index.ts 并在本层导出
* @param {string} dirName 文件夹名
* @param {string} dirUrl 文件夹地址
* @param {string} exportFile 导出文件列表(string)
*/
private _createIndexTs(dirName: string, dirUrl: string, exportFile: string) {
//创建此模块的index.ts
const moduleIndex = `export * from './${dirName}.module';${exportFile}`;
writeFileSync(join(dirUrl, `index.ts`), moduleIndex);
// 本层的index.ts
ensureFileSync(join(dirUrl, '../index.ts'));
let thisIndex = readFileSync(join(dirUrl, '../index.ts')).toString();
if (!thisIndex.includes(`${dirName}`)) {
thisIndex += `
export * from './${dirName}';`;
writeFileSync(join(dirUrl, '../index.ts'), thisIndex);
}
}
/**
* 获取所有层的package.json
* @param {any[]} entities
*/
private _getPackageJsons(entities: any[]) {
const dirName = entities[0].dirName;
const libUrl = join(process.cwd(), '../../../')
const basicDir = join(libUrl, './basic/src', dirName);
const domainDir = join(libUrl, './domain/src', dirName);
const entitiesDir = join(libUrl, './entities/src', dirName);
const apiDir = join(libUrl, './api/src', dirName);
// entity
const entitiesPakcageJson = this.__getPackageByLayerName('entities');
// basic
const basicPakcageJson = this.__getPackageByLayerName('basic');
// domain
const domainPakcageJson = this.__getPackageByLayerName('domain')
// api
const apiPakcageJson = this.__getPackageByLayerName('api');
return { apiPakcageJson, domainPakcageJson, basicPakcageJson, entitiesPakcageJson, apiDir, entitiesDir, domainDir, basicDir };
}
private __getPackageByLayerName(layerName: 'entities' | 'basic' | 'domain' | 'api'): any {
const packageUrl = join(process.cwd(), '../../../', layerName, 'package.json');
if (!pathExistsSync(packageUrl)) throw new Error(`请创建${layerName}层package.json`)
const pakcageJson = readJSONSync(packageUrl)
if (!pakcageJson.name || !pakcageJson.version) throw new Error(`${layerName}层package.json没有name或version`);
return pakcageJson;
}
}