create-cttq
Version: 
CTTQ大前端脚手架项目
95 lines (85 loc) • 3.06 kB
JavaScript
/**
 * 项目生成输出器,用于输出最终的项目文件和内容
 */
const fs = require("fs-extra");
const path = require("path");
const slash = require('slash');
const { red, green, bold } = require("kolorist");
const GerenatorAPI = require("./GeneratorAPI");
const sortPkg = require("./util/sortPkg");
const { loadPlugins } = require("./util/plugins");
const writeFileTree = require("./util/writeFileTree");
const TemplateManager = require("./TemplateManager");
const { logWithSpinner, failSpinner } = require("./util/spinner");
const ModuleName = "generate";
function normalizeFilePaths (files) {
    Object.keys(files).forEach(file => {
        const normalized = slash(file)
        if (file !== normalized) {
            files[normalized] = files[file]
            delete files[file]
        }
    });
    return files
}
module.exports = class Generator {
    /**
     * 构造器
     * @param {*} context 项目上下文地址
     * @param {*} plugins 要加载的插件
     * @param {*} pkg pkg信息
     * @param {*} answers 交互式命令结果
     */
    constructor(context, plugins, pkg, answers) {
        this.context = context;
        this.plugins = plugins;
        this.pkg = Object.assign({}, pkg);
        this.answers = answers;
        this.template = "";
        this.files = {};
        this.fileMiddlewares = [];
        this.pluginModules = loadPlugins(plugins, ModuleName);
        this.beforeCreateCallbacks = [];
        this.createdCallbacks = [];
        // dependencies 和 devDependencies 冲突源
        this.conflictDepSources = {};
        this.templateManager = new TemplateManager(this.context, pkg.engines.template);
    }
    /**
     * 生成项目
     */
    async generate() {
        logWithSpinner("下载模版库...");
        await this.templateManager.download().catch(() => {
            failSpinner("模版库下载失败, 无法连接Gitlab");
            this.templateManager.delete();
            throw new Error("项目创建失败");
        });
        this.pkg.engines.template = this.templateManager.realVersion;
        // 生成数据
        for (const module of this.pluginModules) {
            let generatorAPI = new GerenatorAPI(module.moduleName, this);
            await module(generatorAPI, this.answers);
        }
        logWithSpinner("生成项目文件...");
        await this.resolveFiles();
        // 把文件内容写入本地
        writeFileTree(this.context, this.files);
        this.templateManager.delete();
    }
    /**
     * 最终项目文件内容生成方法
     */
    async resolveFiles () {
        const files = this.files
        for (const middleware of this.fileMiddlewares) {
            await middleware(files, this.templateManager.rootPath)
        }
        this.pkg = sortPkg(this.pkg);
        this.files['package.json'] = JSON.stringify(this.pkg, null, 2) + '\n';
        normalizeFilePaths(files)
        for (const beforeCreate of this.beforeCreateCallbacks) {
            await beforeCreate(files)
        }
    }
}