"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.writeLowCodeFiles = exports.generateConfig = exports.generateWxMp = void 0;
const chalk_1 = __importDefault(require("chalk"));
const path_1 = __importDefault(require("path"));
const util_1 = require("util");
const fs = __importStar(require("fs-extra"));
const weapps_core_1 = require("@cloudbase/lowcode-generator/lib/weapps-core");
const config_1 = require("../config");
const mp_1 = require("@cloudbase/lowcode-generator/lib/generator/config/mp");
const generateFiles_1 = __importStar(require("../util/generateFiles"));
const materials_1 = require("./materials");
const webpack_1 = require("../service/webpack");
const util_2 = require("./util");
const wxml_1 = require("./wxml");
const lowcode_1 = require("./lowcode");
const mp_config_1 = require("./mp_config");
const plugin_1 = require("./plugin");
const plugin_2 = require("../core/plugin");
const util_3 = require("../util");
const lowcode_generator_1 = require("@cloudbase/lowcode-generator");
const types_1 = require("../../types");
const common_1 = require("../types/common");
const lodash_1 = require("lodash");
const junk = __importStar(require("../util/junk"));
const net_1 = require("../util/net");
const cals_1 = require("@cloudbase/cals");
const core_1 = require("../core");
const theme_1 = require("../../utils/theme");
const templateDir = `${config_1.appTemplateDir}/mp/`;
const em = chalk_1.default.blue.bold;
const error = chalk_1.default.redBright;
function patchBuildContext(ctx, calses) {
    var _a, _b, _c;
    const { mainAppData } = ctx;
    if ((_b = (_a = calses === null || calses === void 0 ? void 0 : calses[0]) === null || _a === void 0 ? void 0 : _a.templates) === null || _b === void 0 ? void 0 : _b.length) {
        ctx.materialLibs = [...ctx.materialLibs, (0, cals_1.processTemplatesToDependiencies)((_c = calses === null || calses === void 0 ? void 0 : calses[0]) === null || _c === void 0 ? void 0 : _c.templates)];
    }
    const used = (0, cals_1.getUsedComps)(calses, ctx.materialLibs, { streamline: false, withAction: true });
    /**
     * 修改 buildContext 进行 miniprogramPlugins 精简
     */
    ctx.miniprogramPlugins = (mainAppData.miniprogramPlugins || []).filter((plugin) => used.component[plugin.name] || used.action[plugin.name]);
    return { used: used };
}
async function generateWxMp({ buildContext, weapps, calses, plugins, deployOptions, options, buildTypeList, ignoreInstall = false, cdnEndpoints = {}, }) {
    var _a, _b, _c, _d;
    const operationLabel = em('Wexin MiniProgram Generated');
    console.time(operationLabel);
    console.log(`Generating ${em('Wexin MiniProgram')} to ${buildContext.projDir}`);
    /**
     * 此函数具有副作用，用于补充修正小程序特殊的buildContext
     * 注意一定在入口进行处理，应当尽可能提前，后续逻辑不应该更新buildContext
     */
    const { used } = patchBuildContext(buildContext, calses);
    const { uin = '', appId, projDir, materialLibs: materials, isProduction, mainAppData, domain, isPrivateMode = false, endpointType = '', isBrowserMpBuilder = false, } = buildContext;
    // 安装依赖库，生成 materials 目录
    await (0, materials_1.installMaterials)(buildContext, projDir, used, weapps);
    const wxmlDataPrefix = (0, mp_1.getWxmlDataPrefix)(!isProduction);
    const { projConfig, appConfig, pageConfigs } = (0, mp_config_1.generateMpConfig)(buildContext, weapps, { mpAppId: options.mpAppId });
    const hasLowcodePkg = weapps.find((item) => !item.mpPkgUrl);
    // #1 generate project files
    if (!mainAppData.mpPkgUrl) {
        const projectFileData = {
            'project.config.json': { content: projConfig },
        };
        console.log(`Generating ${em('project')} files`);
        await (0, generateFiles_1.default)(projectFileData, templateDir, projDir);
    }
    // #2 生成主包
    await generatePkg({ ...buildContext, rootPath: mainAppData.rootPath }, { cals: calses[0], weapp: mainAppData }, path_1.default.join(projDir, '/'), pageConfigs[0]);
    const projectConfigJsonPath = path_1.default.join(projDir, mainAppData.rootPath || '', 'project.config.json');
    let projectConfigJson = await fs.readJSON(projectConfigJsonPath);
    const miniprogramRoot = path_1.default.join(projDir, projectConfigJson.miniprogramRoot || '/');
    await generateFramework(buildContext, mainAppData, miniprogramRoot, { deployOptions });
    // #3 生成主包根路径文件
    let appFileData = {};
    if (hasLowcodePkg) {
        await generateFramework(buildContext, mainAppData, miniprogramRoot, { deployOptions });
        // 有了 framework app 之后，并且是源码的方式,追加 app 引用
        if (mainAppData.mpPkgUrl) {
            let appJsPath = path_1.default.join(miniprogramRoot, 'app.js');
            let appJsContent = await fs.readFile(appJsPath);
            await (0, generateFiles_1.writeFile)(appJsPath, `import { app as wedaApp } from './app/weapps-api'\n${appJsContent}`);
        }
        await generateConfig({
            domain,
            isPrivateMode,
            endpointType,
        }, miniprogramRoot);
        const expirationStartTimesnap = buildContext.enableExpiredTag ? Date.now() : 0;
        const cssVarList = Object.entries((0, theme_1.mergeCssVarConfig)((_b = (_a = calses[0]) === null || _a === void 0 ? void 0 : _a.theme) === null || _b === void 0 ? void 0 : _b.cssVarConfig, 'MP'))
            .map(([key, _value]) => {
            const value = _value || '';
            return `${key}: ${value}${/;$/.test(value) ? '' : ';'}`;
        })
            .filter((str) => !!str) || [];
        appFileData = {
            ...appFileData,
            'common/style.js': {},
            'common/util.js': {
                isAdminPortal: (0, common_1.buildAsAdminPortalByBuildType)(buildTypeList),
                expirationStartTimesnap,
            },
            'common/widget.js': {},
            'common/weapp-page.js': {
                expirationStartTimesnap,
                pageStyle: cssVarList.join(''),
            },
            'common/weapp-component.js': {},
            'common/merge-renderer.js': {
                dataPropNames: wxmlDataPrefix,
                debug: buildContext.debugMode,
            },
            'common/data-patch.js': {},
            'common/event-emitter.js': {},
            'common/watch.js': {},
            'common/constant.js': {
                REPEATER: JSON.stringify(config_1.REPEATER, undefined, 2),
            },
            'common/query.js': {},
            'common/flow.js': {},
            'common/info': {},
            /**
             * 使用微信的 modal
             * 暂时保留内部实现待之后使用
             */
            // 'common/privacyModal': {},
            // 'common/modal': {},
            /**
             * 调试用
             */
            // 'common/behaviors.js': {},
        };
        if (buildContext.enableAsyncMaterials && !appFileData['common/placeholder']) {
            appFileData['common/placeholder'] = {};
        }
    }
    if (mainAppData.mpPkgUrl) {
        // 合并 project 和 app json，复写 appId
        projectConfigJson.appId = projConfig.appId;
        projectConfigJson.setting = {
            ...projectConfigJson.setting,
            ...projConfig.setting,
        };
        const projectMpRoot = projectConfigJson.miniprogramRoot || '/';
        if (!projectConfigJson.setting.packNpmManually) {
            projectConfigJson.setting.packNpmManually = true;
        }
        if (!projectConfigJson.setting.packNpmRelationList) {
            projectConfigJson.setting.packNpmRelationList = [];
        }
        projectConfigJson.setting.packNpmRelationList = [
            ...projectConfigJson.setting.packNpmRelationList.filter((item) => item.packageJsonPath === './package.json' || item.packageJsonPath === './packages/$wd_system/package.json'),
            {
                packageJsonPath: path_1.default.posix.join(projectMpRoot, 'package.json'),
                miniprogramNpmDistDir: projectMpRoot,
            },
            {
                packageJsonPath: path_1.default.posix.join(projectMpRoot, 'packages', '$wd_system', 'package.json'),
                miniprogramNpmDistDir: path_1.default.posix.join(projectMpRoot, 'packages', '$wd_system'),
            },
        ];
        await (0, generateFiles_1.writeFile)(projectConfigJsonPath, JSON.stringify(projectConfigJson, undefined, 2));
        let appJsonPath = path_1.default.join(miniprogramRoot, 'app.json');
        let appJson = await fs.readJson(appJsonPath);
        appJson.subpackages = (0, mp_config_1.mergeSubPackages)(appJson.subpackages, appConfig.subpackages);
        await (0, generateFiles_1.writeFile)(appJsonPath, JSON.stringify(appJson, undefined, 2));
    }
    else {
        const importor = (0, util_3.generateLowcodeImportor)(mainAppData.lowCodes || []);
        appFileData = {
            ...appFileData,
            'app.js': { appConfig, importor, materialSubPackagePath: config_1.materialsDirName },
            'app.json': { content: appConfig },
            'app.wxss': {
                importStyles: materials
                    .reduce((styles, lib) => {
                    styles = styles.concat((lib.styles || []).map((stylePath) => stylePath && !stylePath.startsWith('/') ? `/${config_1.materialsDirName}/${lib.name}/${stylePath}` : stylePath) || []);
                    return styles;
                }, [])
                    .concat(importor.styles.map((mod) => path_1.default.posix.join('lowcode', (0, weapps_core_1.getCodeModuleFilePath)('global', mod, { style: '.wxss' })))),
            },
            'package.json': {
                appId,
                importJSSDK: endpointType === 'tcb-api',
                extraDeps: resolveNpmDeps(weapps, materials),
                cdnEndpoints,
            },
        };
    }
    console.log(`Generating ${em('miniprogramRoot')} files`);
    await (0, generateFiles_1.default)(appFileData, templateDir, miniprogramRoot);
    // 若项目目录与小程序根目录不同，则拷贝素材到小程序根目录
    if (miniprogramRoot !== path_1.default.join(projDir, '/') && fs.existsSync(path_1.default.join(projDir, config_1.materialsDirName))) {
        console.log(`Move ${em(config_1.materialsDirName)} from` + `${projDir} to ${miniprogramRoot}`);
        await fs.move(path_1.default.join(projDir, config_1.materialsDirName), path_1.default.join(miniprogramRoot, config_1.materialsDirName));
    }
    // 生成数据源
    if (hasLowcodePkg) {
        const officialLib = materials.find((item) => item.name === cals_1.OFFICIAL_LIB_KEY);
        const datasourceFileData = {
            'datasources/index.js.tpl': {
                cdnEndpoints,
            },
            'datasources/config.js.tpl': {
                envID: mainAppData.envId,
                appID: appId,
                resourceAppid: !!options.isCrossAccount ? options.resourceAppId : '',
                isProd: (deployOptions === null || deployOptions === void 0 ? void 0 : deployOptions.mode) === types_1.DEPLOY_MODE.UPLOAD,
                clientID: ((_c = mainAppData.extra) === null || _c === void 0 ? void 0 : _c.enableLoginStatusShare)
                    ? mainAppData.envId
                    : (_d = mainAppData.extra) === null || _d === void 0 ? void 0 : _d.clientId,
                cdnEndpoints,
                builderVersion: core_1.version || '',
                officialLibVersion: (officialLib === null || officialLib === void 0 ? void 0 : officialLib.version) || '',
                uin,
            },
            'datasources/datasource-profiles.js.tpl': {
                datasourceProfiles: (0, util_3.JsonToStringWithVariableName)([], { EOL: false }),
            },
            'datasources/dataset-profiles.js.tpl': {
                datasetProfiles: (0, util_3.JsonToStringWithVariableName)((0, lowcode_generator_1.getDatasetProfiles)(mainAppData, weapps), { EOL: true }),
            },
        };
        console.log(`Generating ${em('datasources')} files`);
        await (0, generateFiles_1.default)(datasourceFileData, templateDir, miniprogramRoot);
    }
    // 生成上报 & 系统子包模块模块
    if (hasLowcodePkg) {
        const subpackageRootPath = path_1.default.join(miniprogramRoot, 'packages', '$wd_system');
        const sysSubpackageFileData = {
            'package.json': { cdnEndpoints },
            'index.js.tpl': { cdnEndpoints },
        };
        console.log(`Generating ${em('system subpackage')} files`);
        await (0, generateFiles_1.default)(sysSubpackageFileData, path_1.default.join(templateDir, 'packages/$wd_system'), subpackageRootPath);
    }
    // 生成子包
    await Promise.all(weapps.map(async (app, index) => {
        if (index == 0) {
            return;
        }
        else {
            const subpackageRootPath = path_1.default.join(miniprogramRoot, 'packages', app.rootPath || '/');
            let subpackageBuildCtx = {
                ...buildContext,
                rootPath: app.rootPath,
            };
            await generatePkg(subpackageBuildCtx, { cals: calses[index], weapp: app }, subpackageRootPath, pageConfigs[index]);
            await generateFramework(subpackageBuildCtx, app, subpackageRootPath, { deployOptions });
            // 生成package.json
            let packageJsonPath = path_1.default.join(subpackageRootPath, 'package.json');
            if (!fs.existsSync(packageJsonPath)) {
                await (0, generateFiles_1.default)({
                    'package.json': {
                        appId,
                        importJSSDK: endpointType === 'tcb-api',
                        extraDeps: resolveNpmDeps(weapps, materials),
                        cdnEndpoints,
                    },
                }, templateDir, subpackageRootPath);
            }
        }
    }));
    if (!isBrowserMpBuilder) {
        if (fs.existsSync(path_1.default.join(miniprogramRoot, 'package.json'))) {
            await (0, webpack_1.installDependencies)(miniprogramRoot, {
                ignoreInstall,
                fixNodeModulesMap: { '@cloudbase/js-sdk': endpointType !== 'tcb-api', mobx: true },
            });
        }
        const wdSystemSubRoot = path_1.default.join(miniprogramRoot, 'packages', '$wd_system');
        if (fs.existsSync(path_1.default.join(wdSystemSubRoot, 'package.json'))) {
            await (0, webpack_1.installDependencies)(wdSystemSubRoot, {
                ignoreInstall,
            });
        }
    }
    await handleMpPlugins();
    console.timeEnd(operationLabel);
    // web端的builder不需要清除
    if (!isBrowserMpBuilder) {
        cleanProj(weapps, miniprogramRoot);
        cleanMaterils(path_1.default.join(miniprogramRoot, config_1.materialsDirName), used);
    }
    return { miniprogramRoot };
    // SDK 插件
    async function handleMpPlugins() {
        // 编译后置原生小程序类的安装
        const mpPlugins = (await (0, plugin_1.getPluginType)(miniprogramRoot, plugins)).filter((item) => item.type === 'mp');
        await (0, plugin_2.runHandleMpPlugin)(miniprogramRoot, mpPlugins);
    }
}
exports.generateWxMp = generateWxMp;
function resolveNpmDeps(weapps, materials, extra = {}) {
    var _a;
    const deps = [
        {
            deps: ((_a = weapps.find((a) => !a.rootPath)) === null || _a === void 0 ? void 0 : _a.npmDependencies) || {},
            name: '主包',
        },
    ];
    deps.push(...weapps
        .filter((app) => !!app.rootPath)
        .map((app) => ({
        deps: app.npmDependencies,
        name: `子包：${app.rootPath}`,
    })));
    deps.push(...materials
        .filter((lib) => lib.isComposite && lib.compLibCommonResource)
        .map((lib) => {
        var _a;
        return ({
            deps: ((_a = lib.compLibCommonResource) === null || _a === void 0 ? void 0 : _a.npm) || {},
            name: `组件库级别${lib.name}`,
        });
    }));
    deps.push(...materials.map((lib) => ({
        deps: lib.dependencies || {},
        name: `组件库${lib.name}`,
    })));
    return deps.reduce((result, cur) => {
        Object.keys(cur.deps || {}).map((npmPkgName) => {
            if (!result[npmPkgName]) {
                result[npmPkgName] = cur.deps[npmPkgName];
            }
            else if (result[npmPkgName] != cur.deps[npmPkgName]) {
                console.error(error(`${cur.name}的Npm依赖${npmPkgName}已在其他地方定义，将被忽略`));
            }
        });
        return result;
    }, extra);
}
async function generateConfig(data, root) {
    const { domain = '', isPrivateMode = false, endpointType = '' } = data;
    await (0, generateFiles_1.default)({
        'common/config.js': {
            domain,
            isPrivateMode,
            endpointType,
        },
    }, templateDir, root);
}
exports.generateConfig = generateConfig;
async function generatePkg(ctx, { cals, weapp }, appRoot, pageConfigs) {
    var _a;
    const wxmlDataPrefix = (0, mp_1.getWxmlDataPrefix)(!ctx.isProduction);
    console.log(`Generating ${em(weapp.rootPath ? 'subApp' : 'app')} to ${appRoot}`);
    const { processCssUnit = 'rpx' } = ctx;
    if (weapp.mpPkgUrl) {
        // 清空历史文件，使用zip覆盖
        console.log(`Removing ${appRoot}`);
        await (0, generateFiles_1.cleanDir)(appRoot, ['materials']);
        await (0, net_1.downloadZip)(weapp.mpPkgUrl, appRoot, ctx.isBrowserMpBuilder);
        if (fs.existsSync(path_1.default.join(appRoot, '__MACOSX'))) {
            await fs.remove(path_1.default.join(appRoot, '__MACOSX'));
        }
    }
    else {
        // #2 generate page files
        console.log(`Generating ${em('page')} files`);
        (0, generateFiles_1.cleanDir)(path_1.default.join(appRoot, 'pages'), []);
        const CALS_PAGE_MAP = (_a = cals.items) === null || _a === void 0 ? void 0 : _a.reduce((map, page) => {
            map[page.id] = page;
            return map;
        }, {});
        await Promise.all(weapp.pageInstanceList.map(async (page, index) => {
            var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
            // # Generating page
            const rootPath = weapp.rootPath || '';
            const usingComponents = {};
            const componentGenerics = {};
            const componentInstances = (0, util_2.processRepeaterSchema)(ctx, page.componentInstances);
            const allAppUsedComps = (0, cals_1.getUsedComps)([
                {
                    ...cals,
                    items: CALS_PAGE_MAP[page.id] ? [CALS_PAGE_MAP[page.id]] : [],
                },
            ], ctx.materialLibs);
            const wxml = (0, wxml_1.generateWxml)({ ...ctx, rootPath, pageUUID: rootPath ? `${rootPath}/${page.id}` : page.id }, componentInstances, `Page ${rootPath ? path_1.default.join('packages', rootPath, 'pages') : ''}/${page.id}`, wxmlDataPrefix, usingComponents, componentGenerics);
            const importor = (0, util_3.generateLowcodeImportor)(page.lowCodes);
            const pageFileName = (0, lodash_1.get)(pageConfigs, `${page.id}.pageFileName`, 'index');
            const subLevelPath = rootPath ? `${path_1.default.posix.relative(`packages/${rootPath}`, '')}/` : '';
            const pageDataBinds = {};
            Object.entries(page.data || {}).forEach(([prop, val]) => {
                if (prop === null || prop === void 0 ? void 0 : prop.startsWith('appShareMessage')) {
                    (0, util_2.setDataBind)(pageDataBinds, prop, val);
                }
            });
            /**
             * 使用最终的 usingComponents 生成一份 componentPlaceholder
             */
            let componentPlaceholder;
            if (usingComponents[wxml_1.WD_EMPTY_PLACEHOLDER] && ctx.enableAsyncMaterials) {
                componentPlaceholder = Object.keys(usingComponents).reduce((map, key) => {
                    if (!wxml_1.WD_RUNTIME_TAG.includes(key)) {
                        map[key] = wxml_1.WD_EMPTY_PLACEHOLDER;
                    }
                    return map;
                }, {});
            }
            const pageFileData = {
                [`api.js|api.js`]: {
                    subLevelPath,
                    packageName: rootPath || '',
                    uuid: rootPath ? `${rootPath}/${page.id}` : page.id,
                    label: ((_b = (_a = page === null || page === void 0 ? void 0 : page.data) === null || _a === void 0 ? void 0 : _a.navigationBarTitleText) === null || _b === void 0 ? void 0 : _b.value) || ((_d = (_c = page === null || page === void 0 ? void 0 : page.data) === null || _c === void 0 ? void 0 : _c.title) === null || _d === void 0 ? void 0 : _d.value),
                },
                [`data.js|data.js`]: {
                    widgetProps: (0, util_2.createWidgetProps)(ctx, componentInstances),
                    stringifyObj: util_1.inspect,
                },
                [`index.js|${pageFileName}.js`]: {
                    pageNameVar: (0, lowcode_generator_1.normalizePageId)(page.id),
                    pageName: page.id,
                    pageSource: page.data.src || '',
                    eventHandlers: (0, util_2.createEventHandlers)(ctx, componentInstances, 'this', page),
                    dataBinds: (0, util_2.createDataBinds)(ctx, componentInstances),
                    pageAttributes: {
                        ...(((_e = page.data) === null || _e === void 0 ? void 0 : _e.appShareMessage) ? { appShareMessage: page.data.appShareMessage.value } : {}),
                    },
                    pageDataBinds,
                    debug: ctx.debugMode,
                    stringifyObj: util_1.inspect,
                    subLevelPath,
                    importor,
                    query: (0, util_2.createTemplateQuery)(ctx, (_f = page.dataset) === null || _f === void 0 ? void 0 : _f.query),
                    eventFlows: (0, util_2.createTemplateEventFlows)(ctx, page.eventFlows),
                    resetShare: ((_j = (_h = (_g = page === null || page === void 0 ? void 0 : page.data) === null || _g === void 0 ? void 0 : _g.appShareMessage) === null || _h === void 0 ? void 0 : _h.value) === null || _j === void 0 ? void 0 : _j.enable) ||
                        ((_k = allAppUsedComps === null || allAppUsedComps === void 0 ? void 0 : allAppUsedComps[cals_1.OFFICIAL_LIB_KEY]) === null || _k === void 0 ? void 0 : _k.has('Share')) ||
                        /* 从 enablePageRoot 的版本开始支持按需reset share
                         * 否则默认都开启
                         */ !ctx.enablePageRoot,
                },
                [`index.json|${pageFileName}.json`]: {
                    usingComponents,
                    componentGenerics,
                    componentPlaceholder,
                    extra: getAppendableJson(pageConfigs[page.id]),
                },
                [`index.wxml|${pageFileName}.wxml`]: {
                    content: wxml,
                },
                [`index.wxss|${pageFileName}.wxss`]: {
                    subWxss: rootPath && !((_l = ctx.mainAppData) === null || _l === void 0 ? void 0 : _l.mpPkgUrl)
                        ? `@import "${path_1.default.posix.relative(`/packages/${rootPath}/pages/${page.id}`, '/lowcode')}/style.wxss";`
                        : '',
                    content: [
                        (0, weapps_core_1.toCssText)((0, cals_1.processCommonStyle2CSSProperties)(page.commonStyle, {
                            defaultUnit: processCssUnit,
                        }), 'page'),
                        (0, util_2.generateScopedStyleText)(componentInstances),
                    ].join('\n'),
                    pageWxss: importor.styles.length ? `@import "../../lowcode/${page.id}/style.wxss"` : '',
                },
            };
            // Generating file by template and data
            await (0, generateFiles_1.default)(pageFileData, `${templateDir}/page`, path_1.default.join(appRoot, 'pages', page.id));
        }));
        // #3 writing lowcode files
        await writeLowCodeFiles(ctx, weapp, appRoot);
    }
}
async function generateFramework(ctx, appData, outDir, options) {
    var _a, _b;
    let fileData = {};
    if (appData.mpPkgUrl) {
        if (!appData.rootPath) {
            fileData = {
                ...fileData,
                'app/app-global.js': {},
                'app/weapps-api.js': {
                    appId: ctx.appId,
                    subLevelPath: '',
                    subPackageName: '',
                    importor: (0, util_3.generateLowcodeImportor)([]),
                    appConfig: JSON.stringify({}),
                    appQuery: {},
                    stringifyObj: util_1.inspect,
                },
            };
        }
    }
    else {
        const allCodeModules = [];
        (0, weapps_core_1.loopDealWithFn)(appData.pageInstanceList || [], (p) => {
            allCodeModules.push({
                id: p.id,
                pageNameVar: (0, lowcode_generator_1.normalizePageId)(p.id),
                lowCodes: p.lowCodes || [],
            });
        });
        fileData['app/handlers.js'] = {
            pageModules: allCodeModules,
        };
        // 子包混合模式 只在子包中生成 handlers
        const isMixSubpackage = ctx.isMixMode && appData.rootPath;
        if (!isMixSubpackage) {
            const importor = (0, util_3.generateLowcodeImportor)(appData.lowCodes);
            fileData = {
                ...fileData,
                'app/app-global.js': {},
                'app/weapps-api.js': {
                    subLevelPath: appData.rootPath ? `${path_1.default.posix.relative(`packages/${appData.rootPath}`, '')}/` : '',
                    subPackageName: appData.rootPath || '',
                    importor,
                    appConfig: (0, util_3.JsonToStringWithVariableName)({
                        id: ctx.appId,
                        label: (appData === null || appData === void 0 ? void 0 : appData.label) || '',
                        version: (_a = options === null || options === void 0 ? void 0 : options.deployOptions) === null || _a === void 0 ? void 0 : _a.version,
                        envId: appData.envId,
                        envVersion: (ctx === null || ctx === void 0 ? void 0 : ctx.isProduction) ? 'production' : 'preview',
                        pages: appData.pageInstanceList
                            .sort((item) => (item.isHome ? -1 : 1))
                            .map((item) => {
                            var _a;
                            return ({
                                id: item.id,
                                type: item.data.isCustomLoginPage
                                    ? 'login'
                                    : ((_a = appData.extra) === null || _a === void 0 ? void 0 : _a.statusPageId) === item.id
                                        ? 'status'
                                        : '',
                            });
                        }),
                    }),
                    appQuery: (0, util_2.createTemplateQuery)(ctx, (_b = appData.dataset) === null || _b === void 0 ? void 0 : _b.query),
                    stringifyObj: util_1.inspect,
                },
                'app/common.js': {
                    mods: appData.lowCodes
                        .filter((m) => m.type === cals_1.ECodeType.NORMAL_MODULE && m.name !== cals_1.ECodeName.PLACEHOLDER)
                        .map((m) => m.name)
                        .sort(),
                },
            };
        }
    }
    console.log('Generate app framework');
    await (0, generateFiles_1.default)(fileData, templateDir, outDir);
}
async function writeLowCodeFiles(ctx, appData, outDir) {
    console.log(`Writing ${em('lowcode')} files:`);
    const lowcodeRootDir = path_1.default.join(outDir, 'lowcode');
    const lowCodes = (0, cals_1.processRuntimeCodeResources)({ id: 'global' }, appData.lowCodes || appData.codeModules, 'app');
    const themeStyle = lowCodes.find((mod) => mod.type === cals_1.ECodeType.THEME);
    // 混合模式，子包不生成顶级（应用级）的 lowcodes
    if (!(ctx.isMixMode && appData.rootPath)) {
        await Promise.all(lowCodes
            .filter((mod) => mod.type !== cals_1.ECodeType.RENDERER)
            .map((m) => {
            (0, lowcode_1.writeCode2file)(ctx, m, lowcodeRootDir, { appDir: outDir }, (themeStyle === null || themeStyle === void 0 ? void 0 : themeStyle.code) || '');
        }));
    }
    await Promise.all((0, weapps_core_1.loopDealWithFn)(appData.pageInstanceList, async (page) => {
        const codes = (0, cals_1.processRuntimeCodeResources)({ id: page.id }, page.lowCodes || page.codeModules, 'page');
        await codes
            .filter((mod) => mod.type !== cals_1.ECodeType.RENDERER)
            .forEach((m) => {
            (0, lowcode_1.writeCode2file)(ctx, m, lowcodeRootDir, { pageId: page.id, appDir: outDir }, themeStyle.code);
        });
    }));
}
exports.writeLowCodeFiles = writeLowCodeFiles;
// {a: 1} -> , "a": 1
function getAppendableJson(json = {}) {
    const { namespace, appShareMessage, ...restJson } = json;
    const obj = { ...restJson };
    if (obj.reachBottomDistance) {
        obj.onReachBottomDistance = parseInt(obj.reachBottomDistance, 10) || 0;
        delete obj.reachBottomDistance;
    }
    if (obj && Object.keys(obj).length > 0) {
        let str = JSON.stringify(obj);
        str = str.substr(1, str.length - 2).trim();
        if (str) {
            return `,\n${str}`;
        }
    }
    return '';
}
// 处理使用到的组件
async function cleanProj(weapps, miniprogramRoot) {
    weapps.map((pkg) => cleanPkg(pkg, miniprogramRoot));
}
async function cleanPkg(pkg, miniprogramRoot) {
    // zip 模式跳过clean
    if (pkg.mpPkgUrl) {
        return;
    }
    const pkgDir = [miniprogramRoot, pkg.rootPath ? `packages${path_1.default.sep}${pkg.rootPath}` : '']
        .filter((p) => !!p)
        .join(path_1.default.sep);
    const pagesDir = path_1.default.join(pkgDir, 'pages');
    const lowcodesDir = path_1.default.join(pkgDir, 'lowcode');
    const existedPages = await fs.readdir(pagesDir);
    const pages = pkg.pageInstanceList.map((p) => p.id);
    existedPages.forEach((pageName) => {
        var _a, _b, _c, _d;
        const pageDir = path_1.default.join(pagesDir, pageName);
        const lowcodeDir = path_1.default.join(lowcodesDir, pageName);
        if (pages.indexOf(pageName) < 0) {
            // #1 clean page & lowcode of deleted page
            (0, generateFiles_1.removeFile)(pageDir);
            (0, generateFiles_1.removeFile)(lowcodeDir);
        }
        else {
            // #2 clean deleted handlers
            const handlersDir = path_1.default.join(lowcodeDir, 'handler');
            const handlers = ((_d = (_c = (_b = (_a = pkg === null || pkg === void 0 ? void 0 : pkg.pageInstanceList) === null || _a === void 0 ? void 0 : _a.find((p) => p.id === pageName)) === null || _b === void 0 ? void 0 : _b.lowCodes) === null || _c === void 0 ? void 0 : _c.filter((m) => m.type === cals_1.ECodeType.HANDLER_FN)) === null || _d === void 0 ? void 0 : _d.map((m) => `${m.name}.js`)) || [];
            (0, generateFiles_1.cleanDir)(handlersDir, handlers);
        }
    });
    // #3 clean deleted common modules
    const commonModules = pkg.lowCodes.filter((m) => m.type === cals_1.ECodeType.NORMAL_MODULE).map((m) => `${m.name}.js`);
    const commonDir = path_1.default.join(lowcodesDir, 'common');
    (0, generateFiles_1.cleanDir)(commonDir, commonModules);
}
/**
 * Delete unsed materials
 */
function cleanMaterils(materialsDir, used) {
    if (fs.existsSync(materialsDir)) {
        fs.readdirSync(materialsDir)
            .filter(junk.not)
            .map((libName) => {
            var _a;
            const libDir = path_1.default.join(materialsDir, libName);
            if (fs.existsSync(path_1.default.join(libDir, 'meta.json'))) {
                try {
                    (0, generateFiles_1.removeFile)(path_1.default.join(libDir, 'meta.json'));
                }
                catch (e) { }
                // Skip none-composited materials
                return;
            }
            if (!used.component[libName] && !used.action[libName]) {
                (0, generateFiles_1.removeFile)(libDir);
                return;
            }
            (0, generateFiles_1.cleanDir)(libDir, [...Array.from((_a = used.component) === null || _a === void 0 ? void 0 : _a[libName]), 'libCommonRes']);
        });
    }
}
