rerumaccusamus
Version:
The meta-framework suite designed from scratch for frontend-focused modern web development.
271 lines (246 loc) • 7.63 kB
text/typescript
import path from 'path';
import {
fs,
getPackageVersion,
isTsProject,
readTsConfigByFile,
} from '@modern-js/generator-utils';
import { GeneratorContext, GeneratorCore } from '@modern-js/codesmith';
import { AppAPI } from '@modern-js/codesmith-api-app';
import { JsonAPI } from '@modern-js/codesmith-api-json';
import {
BFFSchema,
BFFType,
i18n,
Framework,
Language,
FrameworkAppendTypeContent,
} from '@modern-js/generator-common';
function isEmptyApiDir(apiDir: string) {
const files = fs.readdirSync(apiDir);
if (files.length === 0) {
return true;
}
return files.every(file => {
if (fs.statSync(path.join(apiDir, file)).isDirectory()) {
const childFiles = fs.readdirSync(path.join(apiDir, file));
return childFiles.length === 0;
}
return false;
});
}
// eslint-disable-next-line max-statements
export const handleTemplateFile = async (
context: GeneratorContext,
generator: GeneratorCore,
appApi: AppAPI,
) => {
const jsonAPI = new JsonAPI(generator);
const ans = await appApi.getInputBySchema(BFFSchema, context.config);
const appDir = context.materials.default.basePath;
const apiDir = path.join(appDir, 'api');
if (fs.existsSync(apiDir) && !isEmptyApiDir(apiDir)) {
const files = fs.readdirSync(apiDir);
if (files.length > 0) {
generator.logger.warn("'api' is already exist");
throw Error("'api' is already exist");
}
}
const { bffType, framework } = ans;
const language = isTsProject(appDir) ? Language.TS : Language.JS;
if (language === Language.JS && framework === Framework.Nest) {
generator.logger.warn('nest not support js project');
throw Error('nest not support js project');
}
let updateInfo: Record<string, string> = {};
if (framework === Framework.Express || framework === Framework.Koa) {
updateInfo = {
[`devDependencies.@types/${
framework as string
}`]: `^${await getPackageVersion(`@types/${framework as string}`)}`,
};
}
if (framework === Framework.Nest) {
updateInfo = {
'dependencies.@nestjs/core': `^${await getPackageVersion(
'@nestjs/core',
)}`,
'dependencies.@nestjs/common': `^${await getPackageVersion(
'@nestjs/common',
)}`,
};
if (bffType === BFFType.Func) {
updateInfo['dependencies.express'] = `^${await getPackageVersion(
'express',
)}`;
updateInfo[
'devDependencies.@types/express'
] = `^${await getPackageVersion('@types/express')}`;
}
} else {
updateInfo = {
...updateInfo,
[`dependencies.${framework as string}`]: `^${await getPackageVersion(
framework as string,
)}`,
};
}
await jsonAPI.update(
context.materials.default.get(path.join(appDir, 'package.json')),
{
query: {},
update: {
$set: {
'dependencies.@modern-js/plugin-bff': `^${await getPackageVersion(
'@modern-js/plugin-bff',
)}`,
[`dependencies.@modern-js/plugin-${
framework as string
}`]: `^${await getPackageVersion(
`@modern-js/plugin-${framework as string}`,
)}`,
...updateInfo,
},
},
},
);
if (language === Language.TS) {
const tsconfigJSON = readTsConfigByFile(path.join(appDir, 'tsconfig.json'));
if (!(tsconfigJSON.include || []).includes('api')) {
await jsonAPI.update(
context.materials.default.get(path.join(appDir, 'tsconfig.json')),
{
query: {},
update: {
$set: {
include: [...(tsconfigJSON.include || []), 'api'],
},
},
},
);
}
} else {
await appApi.forgeTemplate(
'templates/js-template/**/*',
undefined,
resourceKey =>
resourceKey
.replace('templates/js-template/', 'api/')
.replace('.handlebars', `.${language}`),
);
}
if (bffType === BFFType.Func) {
if (language === Language.TS) {
await jsonAPI.update(
context.materials.default.get(path.join(appDir, 'tsconfig.json')),
{
query: {},
update: {
$set: {
'compilerOptions.paths.@api/*': ['./api/*'],
},
},
},
);
}
await appApi.forgeTemplate(
'templates/function/base/*',
undefined,
resourceKey =>
resourceKey
.replace('templates/function/base/', 'api/')
.replace('.handlebars', `.${language}`),
);
await appApi.forgeTemplate(
`templates/function/info/*`,
resourceKey => resourceKey.includes(language),
resourceKey =>
resourceKey
.replace('templates/function/info/', 'api/info/')
.replace('.handlebars', ``),
);
await appApi.forgeTemplate(
`templates/function/app/${language}/${
framework as string
}.${language}.handlebars`,
undefined,
resourceKey =>
resourceKey.replace(
`templates/function/app/${language}/${
framework as string
}.${language}.handlebars`,
`api/_app.${language}`,
),
);
} else {
if (language === Language.TS) {
await jsonAPI.update(
context.materials.default.get(path.join(appDir, 'tsconfig.json')),
{
query: {},
update: {
$set: {
'compilerOptions.paths.@api/*': ['./api/lambda/*'],
},
},
},
);
}
await appApi.forgeTemplate(
`templates/framework/lambda/*`,
undefined,
resourceKey =>
resourceKey
.replace(`templates/framework/`, 'api/')
.replace('.handlebars', `.${language}`),
);
await appApi.forgeTemplate(
`templates/framework/app/${framework as string}/**/*`,
resourceKey =>
framework === Framework.Egg || framework === Framework.Koa
? resourceKey.includes(language)
: true,
resourceKey =>
resourceKey
.replace(`templates/framework/app/${framework as string}/`, 'api/')
.replace(
'.handlebars',
framework === Framework.Express ? `.${language}` : '',
),
);
}
const appendTypeContent = FrameworkAppendTypeContent[framework as Framework];
if (appendTypeContent) {
const typePath = path.join(appDir, 'src', 'modern-app-env.d.ts');
if (fs.existsSync(typePath)) {
const npmrc = fs.readFileSync(typePath, 'utf-8');
if (!npmrc.includes(appendTypeContent)) {
fs.writeFileSync(typePath, `${npmrc}${appendTypeContent}\n`, 'utf-8');
}
} else {
fs.ensureFileSync(typePath);
fs.writeFileSync(typePath, appendTypeContent, 'utf-8');
}
}
};
export default async (context: GeneratorContext, generator: GeneratorCore) => {
const appApi = new AppAPI(context, generator);
const { locale } = context.config;
i18n.changeLanguage({ locale });
appApi.i18n.changeLanguage({ locale });
if (!(await appApi.checkEnvironment())) {
// eslint-disable-next-line no-process-exit
process.exit(1);
}
generator.logger.debug(`start run @modern-js/bff-generator`);
generator.logger.debug(`context=${JSON.stringify(context)}`);
generator.logger.debug(`context.data=${JSON.stringify(context.data)}`);
try {
await handleTemplateFile(context, generator, appApi);
} catch (e) {
// eslint-disable-next-line no-process-exit
process.exit(1);
}
await appApi.runInstall();
generator.logger.debug(`forge @modern-js/bff-generator succeed `);
};