@alova/wormhole
Version:
More modern openAPI generating solution for alova.js
232 lines (231 loc) • 9.12 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.generatorHelper = exports.GeneratorHelper = void 0;
const node_path_1 = __importDefault(require("node:path"));
const lodash_1 = require("lodash");
const zod_validation_error_1 = require("zod-validation-error");
const parser_1 = require("../../core/parser");
const getAlovaVersion_1 = __importDefault(require("../../functions/getAlovaVersion"));
const getAutoTemplateType_1 = __importDefault(require("../../functions/getAutoTemplateType"));
const helper_1 = require("../../helper");
const utils_1 = require("../../utils");
const zType_1 = require("./zType");
class GeneratorHelper {
constructor() {
this.defaultConfig = Object.freeze({
input: '',
output: '',
responseMediaType: 'application/json',
bodyMediaType: 'application/json',
type: 'auto',
global: 'Apis',
globalHost: 'globalThis',
useImportType: false,
defaultRequire: false,
});
}
static getInstance() {
if (!GeneratorHelper.instance) {
GeneratorHelper.instance = new GeneratorHelper();
}
return GeneratorHelper.instance;
}
static load(config) {
const ins = new GeneratorHelper();
return ins.load(config);
}
getConfig() {
return this.readConfig;
}
getDefaultConfig() {
return this.defaultConfig;
}
async load(config) {
// 合并配置
const mergedConfig = { ...this.defaultConfig, ...config };
// 验证配置
const validatedConfig = await GeneratorHelper.validateConfig(mergedConfig);
// 更新配置
this.config = validatedConfig;
this.readConfig = Object.freeze(this.config);
this.pluginDriver = new helper_1.PluginDriver(this.config.plugins);
helper_1.logger.debug('GeneratorConfig loaded successfully', this.config);
return this;
}
getAlovaVersion(projectPath) {
return GeneratorHelper.getAlovaVersion(this.config, projectPath);
}
getTemplateType(projectPath) {
return GeneratorHelper.getTemplateType(this.config, projectPath);
}
getPluginDriver() {
return this.pluginDriver;
}
openApiData(projectPath) {
return GeneratorHelper.openApiData(this.config, projectPath);
}
static async validateConfig(config) {
let result = config;
try {
result = zType_1.zGeneratorConfig.parse(config);
}
catch (error) {
const zError = (0, zod_validation_error_1.fromError)(error);
throw helper_1.logger.throwError(zError.message, zError.details);
}
return result;
}
static getAlovaVersion(config, projectPath) {
const configVersion = Number(config.version);
return Number.isNaN(configVersion) ? (0, getAlovaVersion_1.default)(projectPath) : `v${configVersion}`;
}
static getTemplateType(config, projectPath) {
let type;
const configType = config.type ?? 'auto';
// Determine the template type based on the type in the configuration file
switch (configType) {
case 'ts':
case 'typescript':
type = 'typescript';
break;
case 'module':
type = 'module';
break;
case 'auto':
type = (0, getAutoTemplateType_1.default)(projectPath);
break;
default:
type = 'commonjs';
break;
}
return type;
}
static openApiData(config, projectPath) {
return parser_1.openApiParser.parse(config.input, {
projectPath,
platformType: config.platform,
fetchOptions: config.fetchOptions,
});
}
static async generate(config, options) {
const pluginDriver = new helper_1.PluginDriver(config.plugins);
// plugin: handle before parse openapi
await pluginDriver.hookParallel('beforeOpenapiParse', [Object.freeze(config)]);
let document = await this.openApiData(config, options.projectPath);
if (!document) {
return false;
}
// plugin: handle after parse openapi
document = await pluginDriver.hookSeq('afterOpenapiParse', [document], (result, args) => {
return result ? [result] : args;
}) ?? document;
const output = node_path_1.default.resolve(options.projectPath, config.output);
const version = GeneratorHelper.getAlovaVersion(config, options.projectPath);
const templateHelper = helper_1.TemplateHelper.load({
type: this.getTemplateType(config, options.projectPath),
version,
});
const templateData = await new parser_1.TemplateParser().parse(document, {
projectPath: options.projectPath,
generatorConfig: config,
});
const oldTemplateData = helper_1.TemplateHelper.getData(options.projectPath, config.output);
// Transform output filename by config.fileNameCase without changing template filename
const toCase = (name) => (0, utils_1.toCase)(name, config.fileNameCase);
// Inject computed filenames into template render data for templates to reference
Object.assign(templateData, {
createApisFileName: toCase('createApis'),
apiDefinitionsFileName: toCase('apiDefinitions'),
globalsDFileName: toCase('globals.d'),
indexFileName: toCase('index'),
});
// Do you need to generate api files?
if (!options.force && (0, lodash_1.isEqual)(templateData, oldTemplateData)) {
return false;
}
if (oldTemplateData) {
await templateHelper.unlink([
// Delete old API creation file
oldTemplateData.createApisFileName ?? '',
// Delete old API definition file
oldTemplateData.apiDefinitionsFileName ?? '',
// Delete old global type declaration file (.d.ts)
{
fileName: oldTemplateData.globalsDFileName ?? '',
ext: '.ts',
},
], { output });
}
await helper_1.TemplateHelper.setData(templateData, options.projectPath, config.output);
const generateFiles = [
{
fileName: 'createApis',
outFileName: templateData.createApisFileName,
data: templateData,
output,
root: true,
hasVersion: false,
},
{
fileName: 'apiDefinitions',
outFileName: templateData.apiDefinitionsFileName,
data: templateData,
output,
root: true,
hasVersion: false,
},
{
fileName: 'globals.d',
outFileName: templateData.globalsDFileName,
data: templateData,
output,
ext: '.ts',
root: true,
hasVersion: false,
},
];
if (!(await (0, utils_1.existsPromise)(node_path_1.default.join(output, `${templateData.indexFileName}${templateHelper.getExt()}`)))) {
generateFiles.push({
fileName: 'index',
outFileName: templateData.indexFileName,
data: templateData,
output,
root: true,
hasVersion: false,
});
}
// plugin: handle before code generate
let codeGenError;
try {
const unhandledGenerateFiles = [];
for (const file of generateFiles) {
const fileName = `${file.outFileName ?? file.fileName}${file.ext ?? templateHelper.getExt()}`;
const data = await pluginDriver.hookFirst('beforeCodeGenerate', [
file.data,
fileName,
{
renderTemplate: () => templateHelper.readAndRenderTemplate(file.fileName, file.data, file),
fileName: file.fileName,
},
]);
if (!data) {
unhandledGenerateFiles.push(file);
continue;
}
await (0, utils_1.generateFile)(file.output, fileName, data);
}
await templateHelper.outputFiles(unhandledGenerateFiles);
}
catch (error) {
codeGenError = error;
}
// plugin: handle after code gen
await pluginDriver.hookParallel('afterCodeGenerate', [codeGenError]);
return true;
}
}
exports.GeneratorHelper = GeneratorHelper;
exports.generatorHelper = GeneratorHelper.getInstance();