"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildComposite = exports.normalizeInputs = exports.getCompileDirs = exports.downloadZip = exports.strToBuf = exports.fileToZip = exports.getFiles = exports.version = exports.cleanComponentDir = exports.buildWedaApp = exports.buildWedaConfig = exports.buildBlock = void 0;
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const util_1 = require("../util");
const common_1 = require("../types/common");
const index_1 = require("../mp/index");
const types_1 = require("../../types");
const common_2 = require("../../utils/common");
const postProcess_1 = require("../../utils/postProcess");
const cals_1 = require("@cloudbase/cals");
const net_1 = require("../util/net");
const config_1 = require("../config");
const axios_1 = __importDefault(require("axios"));
const materials_1 = require("../mp/materials");
const common_3 = require("@cloudbase/lowcode-generator/lib/generator/types/common");
var block2component_1 = require("../h5/block2component");
Object.defineProperty(exports, "buildBlock", { enumerable: true, get: function () { return block2component_1.buildBlock; } });
const pkg = require('../../../package.json');
async function buildWedaConfig({ output, domain = undefined, isPrivateMode = undefined, endpointType = undefined, buildTypeList = [common_1.BuildType.WEB], }) {
    if ((0, common_1.buildAsWebByBuildType)(buildTypeList)) {
        throw new Error('构建类型仅支持 MP');
    }
    let outDir = output === null || output === void 0 ? void 0 : output.path;
    if (!outDir) {
        throw new Error('无效的项目输出路径');
    }
    let wedaRoot = outDir;
    let projectJsonPath = path_1.default.resolve(outDir, 'project.config.json');
    if (fs_extra_1.default.existsSync(projectJsonPath)) {
        const projectConfigJson = await fs_extra_1.default.readJson(projectJsonPath);
        wedaRoot = path_1.default.join(outDir, projectConfigJson.miniprogramRoot || '/', (0, util_1.normalizeWedaRoot)(projectConfigJson.wedaRoot) || '');
    }
    const configPath = path_1.default.resolve(wedaRoot, 'common/config.js');
    let data = { domain, isPrivateMode, endpointType };
    if (fs_extra_1.default.existsSync(configPath)) {
        try {
            let config = require(configPath);
            let current = {};
            if (config.__esModule) {
                current = config.default || {};
            }
            else {
                current = config || {};
            }
            for (const key in data) {
                if (data[key] === undefined) {
                    data[key] = current[key];
                }
            }
        }
        catch (e) {
            console.error('parse current file error, overwrite current config', e);
        }
    }
    await (0, index_1.generateConfig)(data, outDir);
}
exports.buildWedaConfig = buildWedaConfig;
async function buildWedaApp({ cals, subAppCalsList: _subAppCalsList = [], dependencies = [], appKey = 'test', runtime = types_1.RUNTIME.NONE, ignoreInstall = false, buildTypeList = [common_1.BuildType.WEB], mode = common_1.WebpackModeType.PRODUCTION, devTool = 'webpack', deployOptions = { mode: types_1.DEPLOY_MODE.PREVIEW }, runtimeOptions, plugins = [], extraData = {
    isComposite: false,
    compProps: {},
}, resourceAppId = undefined, domain = '', output, isBrowserMpBuilder = false, cdnEndpoints: _cdnEndpoints, isPrivateMode = false, endpointType = undefined, enableExpiredTag = false, enableAd = false, account = {}, mpConfig = {}, privatelinkConfig = undefined, __defaultLoginType__ = 'anonymous', }, cb) {
    var _a, _b, _c, _d, _e, _f;
    const cdnEndpoints = (0, config_1.generateCdnEndpoints)(_cdnEndpoints);
    if (!cals) {
        console.error('无效的应用配置');
        return;
    }
    if (!deployOptions.mode) {
        deployOptions.mode = types_1.DEPLOY_MODE.PREVIEW;
    }
    if (!runtimeOptions) {
        runtimeOptions = {};
    }
    if (!runtimeOptions.mode) {
        runtimeOptions.mode = deployOptions.mode;
    }
    /**
     * 正规化子包数据
     * 清除冗余字段
     */
    const subAppCalsList = _subAppCalsList.map((cals) => (0, cals_1.streamlineSubApp)(cals));
    /**
     * 刷新正规化 packageName
     */
    [cals, ...subAppCalsList].forEach((app) => {
        var _a, _b;
        if (!app.extra) {
            app.extra = {};
        }
        app.extra.rootPath = (0, util_1.normalizePackageName)(app.extra.rootPath);
        /**
         * 历史登录页清理
         * 使用默认的登录
         */
        app.items = (_b = (_a = app.items) === null || _a === void 0 ? void 0 : _a.filter) === null || _b === void 0 ? void 0 : _b.call(_a, (item) => {
            var _a;
            return !((_a = item.attributes) === null || _a === void 0 ? void 0 : _a.isCustomLoginPage);
        });
    });
    let appBuildDir = (output === null || output === void 0 ? void 0 : output.path) || (runtime === types_1.RUNTIME.CI ? (_a = (0, util_1.getCompileDirs)('app')) === null || _a === void 0 ? void 0 : _a.appBuildDir : (_b = (0, util_1.getCompileDirs)(appKey)) === null || _b === void 0 ? void 0 : _b.appBuildDir);
    let runtimeDynamicConfig = {};
    if (enableExpiredTag) {
        try {
            const { data } = await axios_1.default.get(config_1.RUNTIME_CONFIG_URL, { responseType: 'json' });
            if (data) {
                runtimeDynamicConfig = data;
            }
        }
        catch (e) {
            console.log('get runtime config error', e);
        }
    }
    const officialLib = dependencies.find((item) => item.name === cals_1.OFFICIAL_LIB_KEY);
    const buildContext = {
        uin: account === null || account === void 0 ? void 0 : account.uin,
        projDir: appBuildDir,
        appId: appKey,
        isProduction: mode === common_1.WebpackModeType.PRODUCTION,
        materialLibs: dependencies,
        debugMode: mode !== common_1.WebpackModeType.PRODUCTION && !!process.env.WEAPPS_DEBUG,
        isMixMode: !!(subAppCalsList === null || subAppCalsList === void 0 ? void 0 : subAppCalsList.length),
        domain,
        isBrowserMpBuilder,
        isPrivateMode,
        endpointType,
        enableExpiredTag,
        enableAd,
        runtimeDynamicConfig,
        disabled: (_c = cals.extra) === null || _c === void 0 ? void 0 : _c.disabled,
        statusPageId: ((_d = cals.extra) === null || _d === void 0 ? void 0 : _d.statusPageId) || undefined,
        privatelinkConfig: privatelinkConfig ? { uin: account === null || account === void 0 ? void 0 : account.uin, ...privatelinkConfig } : undefined,
        enableOfficialLibNPM: !!((0, common_3.buildAsLibByBuildType)(buildTypeList) && officialLib),
    };
    console.log('domain', domain);
    console.log('应用名', appKey);
    console.log('生成模式', buildContext.isMixMode ? common_1.GenerateMpType.SUBPACKAGE : common_1.GenerateMpType.APP);
    console.log('生成路径', appBuildDir);
    try {
        const startTime = Date.now();
        function processRepeaterDisplay(cals) {
            cals.items = (cals.items || []).map((page) => {
                return JSON.parse(JSON.stringify(page, (key, value) => {
                    if ((value === null || value === void 0 ? void 0 : value.component) && !(value === null || value === void 0 ? void 0 : value.module) && (value === null || value === void 0 ? void 0 : value.type) !== 'PAGE') {
                        value.module = cals_1.OFFICIAL_LIB_KEY;
                    }
                    if (value === null || value === void 0 ? void 0 : value.component) {
                        const component = value;
                        /**
                         * TODO: 判断需要根据 componentType 来
                         * 但是此刻还没有具体的 componentInfo 信息
                         */
                        if ((value === null || value === void 0 ? void 0 : value.component) &&
                            `${component.module}:${component.component}` === `${config_1.REPEATER.MODULE_NAME}:${config_1.REPEATER.REPEATER_NAME}`) {
                            // 给 Repeater 组件加一层虚拟项组件，在虚拟项组件上挂 for 循环
                            const { items = [] } = component;
                            component.items = items.map((item) => {
                                var _a;
                                let currentDisplay = (_a = component === null || component === void 0 ? void 0 : component.directives) === null || _a === void 0 ? void 0 : _a[':display'];
                                if (currentDisplay !== undefined && currentDisplay !== 'true') {
                                    if (!item.directives) {
                                        item.directives = {};
                                    }
                                    const current = item.directives[':display'] || 'true';
                                    item.directives[':display'] = `(\n${currentDisplay}\n) && (\n${current}\n)`;
                                }
                                return item;
                            });
                        }
                    }
                    return value;
                }));
            });
            return cals;
        }
        if (buildTypeList.includes(common_1.BuildType.MP)) {
            const mainAppSerializeData = (0, common_2.processCals2WeappsData)(processRepeaterDisplay(cals), dependencies);
            const subAppSerializeDataList = (subAppCalsList === null || subAppCalsList === void 0 ? void 0 : subAppCalsList.map((item) => (0, common_2.processCals2WeappsData)(processRepeaterDisplay(item), dependencies))) || [];
            const apps = [mainAppSerializeData, ...subAppSerializeDataList];
            const calses = [cals, ...subAppCalsList];
            if (isBrowserMpBuilder) {
                // 尽早下载物料
                await (0, net_1.downloadBrowserMaterial)({ runtimeEndpointType: endpointType });
            }
            const { enablePageRoot, disablePageComponentInvoke } = (0, cals_1.parseVersion)(cals === null || cals === void 0 ? void 0 : cals.schemaVersion, dependencies);
            const mpBuildContext = {
                ...buildContext,
                privatelinkConfig: buildContext.privatelinkConfig
                    ? { ...buildContext.privatelinkConfig, jsUrl: undefined }
                    : undefined,
                projDir: (output === null || output === void 0 ? void 0 : output.path) || path_1.default.join(appBuildDir, 'mp'),
                mainAppData: mainAppSerializeData,
                processCssUnit: (calses.find((cals) => {
                    const FEATURE_MAP = (0, cals_1.parseVersion)(cals.schemaVersion, dependencies);
                    return !FEATURE_MAP.defaultDynamicCssUnit;
                })
                    ? 'px'
                    : 'rpx'),
                enablePageRoot,
                enableLoading: (_e = cals === null || cals === void 0 ? void 0 : cals.extra) === null || _e === void 0 ? void 0 : _e.enableLoading,
                enableAsyncMaterials: (_f = cals.extra) === null || _f === void 0 ? void 0 : _f.enableAsyncMaterials,
                disablePageComponentInvoke,
                __defaultLoginType__,
                // enableAsyncMaterials: true,
            };
            const result = await (0, index_1.generateWxMp)({
                buildContext: mpBuildContext,
                weapps: apps,
                calses,
                plugins,
                deployOptions,
                runtimeOptions,
                options: {
                    isCrossAccount: resourceAppId !== deployOptions.targetMpAppId,
                    mpAppId: deployOptions.mpAppId || '',
                    resourceAppId,
                },
                buildTypeList,
                ignoreInstall,
                cdnEndpoints,
                mpConfig,
            });
            const outDir = mpBuildContext.projDir;
            let projectJsonPath = path_1.default.resolve(outDir, 'project.config.json');
            await (0, postProcess_1.postprocessProjectConfig)(projectJsonPath, {
                appid: deployOptions === null || deployOptions === void 0 ? void 0 : deployOptions.mpAppId,
                cloudfunctionRoot: undefined,
            });
            // 如果是代开发的模式，则写入ext.json
            await (0, postProcess_1.postprocessDeployExtraJson)(outDir, deployOptions);
            await (cb === null || cb === void 0 ? void 0 : cb(null, {
                ...result,
                outDir,
                timeElapsed: Date.now() - startTime,
            }));
            return outDir;
        }
        else {
            // web worker build 构建时注入, H5构建目前不支持web worker，web worker build时过滤掉
            if (!process.env.IS_WEB_WORKER) {
                const { buildH5App } = require('../h5/index');
                const h5BuildDir = await buildH5App({
                    buildContext: {
                        ...buildContext,
                        isMixMode: false,
                        privatelinkConfig: buildContext.privatelinkConfig
                            ? { ...buildContext.privatelinkConfig, jsUrl: (0, config_1.getPrivatelinkJsUrl)(cdnEndpoints.cdngo) }
                            : undefined,
                    },
                    cals,
                    subAppCalsList,
                    extraData,
                    buildTypeList,
                    mode,
                    devTool,
                    runtime,
                    deployOptions,
                    runtimeOptions,
                    ignoreInstall,
                    cdnEndpoints,
                });
                await (cb === null || cb === void 0 ? void 0 : cb(null, {
                    outDir: h5BuildDir,
                    timeElapsed: Date.now() - startTime,
                }));
                return h5BuildDir;
            }
        }
    }
    catch (err) {
        if (err.length) {
            let messageList = (err[0] || '').split('\n');
            let lineIndex = 0;
            let reg = /node_modules\/@babel/;
            messageList.find((str, index) => {
                if (reg.test(str)) {
                    lineIndex = index;
                    return true;
                }
                else {
                    return false;
                }
            });
            if (lineIndex) {
                messageList = messageList.slice(0, lineIndex);
            }
            err = new Error(messageList.join('\n'));
        }
        cb === null || cb === void 0 ? void 0 : cb(err);
        throw err;
    }
}
exports.buildWedaApp = buildWedaApp;
async function cleanComponentDir() {
    return fs_extra_1.default.emptyDir((0, util_1.getCompileDirs)().materialsDir);
}
exports.cleanComponentDir = cleanComponentDir;
exports.version = pkg.version;
var generateFiles_1 = require("../util/generateFiles");
Object.defineProperty(exports, "getFiles", { enumerable: true, get: function () { return generateFiles_1.getFiles; } });
Object.defineProperty(exports, "fileToZip", { enumerable: true, get: function () { return generateFiles_1.fileToZip; } });
Object.defineProperty(exports, "strToBuf", { enumerable: true, get: function () { return generateFiles_1.strToBuf; } });
var net_2 = require("../util/net");
Object.defineProperty(exports, "downloadZip", { enumerable: true, get: function () { return net_2.downloadZip; } });
var util_2 = require("../util");
Object.defineProperty(exports, "getCompileDirs", { enumerable: true, get: function () { return util_2.getCompileDirs; } });
exports.default = buildWedaApp;
function normalizeInputs(inputs, { envId, getWebRootPath, }) {
    var _a, _b;
    const { extraData = { isComposite: false, compProps: {} } } = inputs;
    /**
     * 过滤处理 dependencies
     */
    let map = {};
    inputs.dependencies = (inputs.dependencies || []).reduce((list, item) => {
        if (!map[`${item.name}@${item.version}`]) {
            map[`${item.name}@${item.version}`] = true;
            list.push(item);
        }
        return list;
    }, []);
    const normalizeCalsOptions = {
        buildTypeList: inputs.buildTypeList,
        envId,
        deployOptions: inputs.deployOptions,
        appId: inputs.appId || inputs.appKey,
        getWebRootPath: getWebRootPath || _getWebRootPath,
        webOptions: inputs.webOptions,
    };
    if (inputs.mainAppSerializeData) {
        inputs.mainAppSerializeData = normalizeCals(inputs.mainAppSerializeData, normalizeCalsOptions);
    }
    if (inputs.cals) {
        inputs.cals = normalizeCals(inputs.cals, normalizeCalsOptions);
    }
    if (!(0, common_1.buildAsWebByBuildType)(inputs.buildTypeList)) {
        // 小程序构建
        const { mpAppId, deployOptions = { mode: types_1.DEPLOY_MODE.PREVIEW } } = inputs;
        inputs.deployOptions = {
            ...deployOptions,
            mpAppId: deployOptions.mpAppId || mpAppId,
        };
        if (!inputs.deployOptions.targetMpAppId) {
            inputs.deployOptions.targetMpAppId = inputs.deployOptions.mpAppId;
        }
    }
    else {
        // web 构建
        const { deployOptions = { mode: types_1.DEPLOY_MODE.PREVIEW } } = inputs;
        if (deployOptions.mode === types_1.DEPLOY_MODE.DYNAMIC) {
            inputs.deployOptions = {
                ...deployOptions,
                mode: types_1.DEPLOY_MODE.PREVIEW,
            };
        }
    }
    if (!inputs.runtimeOptions) {
        inputs.runtimeOptions = {};
    }
    inputs.runtimeOptions.mode =
        inputs.runtimeOptions.mode ||
            (((_a = inputs.deployOptions) === null || _a === void 0 ? void 0 : _a.mode) == types_1.DEPLOY_MODE.DYNAMIC
                ? types_1.DEPLOY_MODE.PREVIEW
                : ((_b = inputs.deployOptions) === null || _b === void 0 ? void 0 : _b.mode) || types_1.DEPLOY_MODE.PREVIEW);
    if (extraData.isComposite) {
        Object.keys(extraData.compProps.events).forEach((eName) => {
            extraData.compProps.events[eName] = `$$EVENT_${eName}$$`;
        });
    }
    return inputs;
}
exports.normalizeInputs = normalizeInputs;
function normalizeCals(cals, { buildTypeList, envId, deployOptions, appId, getWebRootPath, webOptions }) {
    var _a;
    if (!cals.extra) {
        cals.extra = {};
    }
    if (!cals.mpPkgUrl) {
        if (buildTypeList.includes(common_1.BuildType.APP) ||
            buildTypeList.includes(common_1.BuildType.XPAGE_PC) ||
            buildTypeList.includes(common_1.BuildType.ADMIN_PORTAL)) {
            cals.extra.historyType = types_1.HISTORY_TYPE.HASH;
        }
    }
    if (envId) {
        cals.extra.envId = envId;
    }
    if ((0, common_1.buildAsWebByBuildType)(buildTypeList)) {
        // web 构建不处理小程序插件
        if (cals.extra.miniprogramPlugins) {
            cals.extra.miniprogramPlugins = [];
        }
        const { gatewayConfig = {} } = webOptions || {};
        let { appConfig = {} } = cals.extra;
        let { window = {} } = appConfig;
        let path = getWebRootPath({ appId, name: cals.name, deployOptions });
        cals.extra.appConfig = {
            ...appConfig,
            window: {
                ...window,
                // Todo: 处理自定义域名逻辑
                publicPath: (0, common_1.buildAsXPageByBuildType)(buildTypeList)
                    ? (deployOptions === null || deployOptions === void 0 ? void 0 : deployOptions.publicPath) || `https://${(_a = cals.extra) === null || _a === void 0 ? void 0 : _a.domain}${path}`
                    : path,
                basename: (0, common_1.buildAsAdminPortalByBuildType)(buildTypeList)
                    ? `app/${appId}${(deployOptions === null || deployOptions === void 0 ? void 0 : deployOptions.mode) !== types_1.DEPLOY_MODE.UPLOAD ? '-preview' : ''}`
                    : (0, common_1.buildAsXPageByBuildType)(buildTypeList)
                        ? '/'
                        : gatewayConfig.path || path,
            },
        };
    }
    return cals;
}
function _getWebRootPath({ appId, name, deployOptions }) {
    const key = name || appId;
    return (deployOptions === null || deployOptions === void 0 ? void 0 : deployOptions.mode) === types_1.DEPLOY_MODE.UPLOAD ? `/${key}/production/` : `/${key}/preview/`;
}
async function buildComposite({ dependencies, output, isBrowserMpBuilder, }) {
    var _a, _b;
    const packageMiniprogramEntry = 'dist';
    const localWedaRoot = path_1.default.join(output.path, packageMiniprogramEntry);
    const { disablePageComponentInvoke } = (0, cals_1.parseVersion)('', dependencies);
    const buildContext = {
        materialLibs: dependencies.map((lib) => {
            (0, materials_1.normalizeCompositeDependienciesForBuild)(lib);
            return lib;
        }),
        isProduction: true,
        /**
         * 新版本不再默认转换
         * 则此处构建都以px为准
         */
        processCssUnit: 'px',
        isBrowserMpBuilder,
        disablePageComponentInvoke,
    };
    if (isBrowserMpBuilder) {
        // 尽早下载物料
        await (0, net_1.downloadBrowserMaterial)({ runtimeEndpointType: undefined, node_modules: false });
    }
    await (0, index_1.generateWedaRootCommonFile)({
        buildContext,
        buildTypeList: [common_1.BuildType.MP],
        localWedaRoot,
        // 组件无需生成，节省空间
        filter: (src) => {
            return !/common\/weapp-page/.test(src);
        },
    });
    let usedComps;
    const composite = dependencies.find((lib) => lib.isComposite);
    if (composite) {
        let id = 0;
        const cals = {
            items: [
                {
                    id: '$page',
                    type: 'PAGE',
                    items: ((_b = (_a = composite.components) === null || _a === void 0 ? void 0 : _a.map) === null || _b === void 0 ? void 0 : _b.call(_a, (component) => {
                        id += 1;
                        return {
                            id: `id${id}`,
                            module: composite.name,
                            component: component.name,
                            attributes: {},
                        };
                    })) || [],
                },
            ],
        };
        usedComps = (0, cals_1.getUsedComps)([cals], dependencies, { streamline: true, withAction: true });
    }
    await (0, materials_1.installMaterials)(buildContext, localWedaRoot, usedComps, 'lib');
    await Promise.all(buildContext.materialLibs.map((lib) => {
        return fs_extra_1.default.remove(path_1.default.join(localWedaRoot, config_1.materialsDirName, lib.name, 'meta.json'));
    }));
    const officialLib = buildContext.materialLibs.find((item) => item.name === cals_1.OFFICIAL_LIB_KEY);
    await patchMpComponentNPM({
        packageDir: output.path,
        name: composite === null || composite === void 0 ? void 0 : composite.name,
        version: composite === null || composite === void 0 ? void 0 : composite.version,
        packageMiniprogramEntry,
        officialLibVersion: officialLib === null || officialLib === void 0 ? void 0 : officialLib.version,
    });
    fs_extra_1.default.writeFile(path_1.default.join(output.path, 'index.js'), `import * as sdk from '@cloudbase/weda-client';\nexport * as clientSDK from '@cloudbase/weda-client';\n/* 注意取注，并填入环境ID */\n// sdk.init({\n//   envID: '<填写你的云开发环境ID>'\n// })`);
    return output.path;
    // await generateCompLibs(dependencies, rpxCalcRoot);
}
exports.buildComposite = buildComposite;
async function patchMpComponentNPM({ packageDir, name, version, packageMiniprogramEntry = '', officialLibVersion, }) {
    await fs_extra_1.default.mkdirSync(path_1.default.join(packageDir, 'scripts'));
    const packageJsonPath = path_1.default.join(packageDir, 'package.json');
    let packageJSON = {};
    if (fs_extra_1.default.existsSync(packageJsonPath)) {
        packageJSON = await fs_extra_1.default.readJSON(packageJsonPath);
    }
    const BASE_DEPS = (0, config_1.generatePackageDependencies)({ mode: 'lib', importJSSDK: false, officialLibVersion });
    if (packageJSON.dependencies) {
        for (const key in BASE_DEPS) {
            delete packageJSON.dependencies[key];
        }
    }
    packageJSON = {
        ...packageJSON,
        name: `@cloudbase-module/${name || 'components'}`,
        version: version || packageJSON.version || '0.0.1',
        miniprogram: `./${packageMiniprogramEntry}`,
        keywords: ['微搭', '小程序', '区块组件', 'cloudbase', 'cloudbase-module', 'cloudbase-component'],
        dependencies: {
            ...packageJSON.peerDependencies,
            ...BASE_DEPS,
        },
    };
    await Promise.all([fs_extra_1.default.writeFile(packageJsonPath, JSON.stringify(packageJSON, undefined, 2))]);
}
