"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 = exports.generateWedaRootCommonFile = 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 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 index_1 = require("../config/index");
const mixMode_1 = require("./mixMode");
const axios_1 = __importDefault(require("axios"));
const templateDir = `${config_1.appTemplateDir}/mp/`;
const em = chalk_1.default.blue.bold;
const error = chalk_1.default.redBright;
function patchBuildContext(ctx, calses) {
    const { mainAppData } = ctx;
    const used = (0, cals_1.getUsedComps)(calses, ctx.materialLibs, { streamline: true, withAction: true });
    /**
     * 修改 buildContext 进行 miniprogramPlugins 精简
     */
    ctx.miniprogramPlugins = (mainAppData.miniprogramPlugins || []).filter((plugin) => used.component[plugin.name] || used.action[plugin.name]);
    return { used };
}
async function generateWedaRootCommonFile({ buildContext, buildTypeList, localWedaRoot, loginConfigVersion, cssVarMap, appId, filter = () => true, }) {
    const expirationStartTimesnap = buildContext.enableExpiredTag ? Date.now() : 0;
    let customLoginConfig;
    let loginConfigPathname = loginConfigVersion
        ? (0, cals_1.generateCustomLoginConfigPathname)({ appId: appId || '', version: loginConfigVersion })
        : '';
    if (loginConfigPathname && buildContext.domain) {
        const url = `https://${buildContext.domain}${loginConfigPathname}`;
        try {
            const { data } = await axios_1.default.get(url, { responseType: 'json' });
            if (data) {
                customLoginConfig = data;
            }
        }
        catch (e) {
            console.error('预置获取登录配置失败：', url, e);
        }
    }
    const wedaRootFileData = {
        'common/util.js': {
            skipCheckAuth: process.env.SKIP_CHECK_AUTH,
            isAdminPortal: (0, common_1.buildAsAdminPortalByBuildType)(buildTypeList),
            expirationStartTimesnap,
            runtimeDynamicConfig: buildContext.runtimeDynamicConfig || {},
            RUNTIME_CONFIG_URL: index_1.RUNTIME_CONFIG_URL,
            loginConfigPathname,
            customLoginConfig: customLoginConfig ? JSON.stringify(customLoginConfig, undefined, 2) : 'null',
        },
        'common/cloud-sdk.js': {},
        'common/weapp-page.js': {
            expirationStartTimesnap,
            pageStyle: JSON.stringify(cssVarMap || {}, undefined, 2),
        },
        'common/info': {},
        /**
         * 使用微信的 modal
         * 暂时保留内部实现待之后使用
         */
        // 'common/privacyModal': {},
        // 'common/modal': {},
    };
    console.log(`Generating ${em('weda root')} files`);
    await (0, generateFiles_1.default)(wedaRootFileData, templateDir, localWedaRoot, filter);
}
exports.generateWedaRootCommonFile = generateWedaRootCommonFile;
async function generateWxMp({ buildContext: _buildContext, weapps, calses, deployOptions, options, buildTypeList, ignoreInstall = false, cdnEndpoints = {}, mpConfig = {}, }) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
    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);
    /**
     * 依据所有应用的低码配置生成默认项目json
     * 次高优先级，生成整个小程序的配置信息
     */
    const { projConfig, appConfig, pageConfigs } = await (0, mp_config_1.generateMpConfig)(_buildContext, weapps, calses, {
        mpAppId: options.mpAppId,
        mpConfig,
    });
    Object.values((appConfig === null || appConfig === void 0 ? void 0 : appConfig.usingComponents) || {}).forEach((path) => {
        var _a;
        const matched = path.match(new RegExp(`(?:\\.)?(?:\\/)?${config_1.materialsDirName}\\/\\$template\\/(.*)?\\/index`));
        if (matched) {
            const componentName = matched[1];
            if (!((_a = used.component) === null || _a === void 0 ? void 0 : _a['$template'])) {
                used.component['$template'] = new Set();
            }
            used.component['$template'].add(componentName);
        }
    });
    /**
     * 此处逻辑分离自 patchBuildContext
     * 因为 materialLibs 依赖 used 修正，used 依赖 generateMpConfig 后获取 appConfig 修正，generateMpConfig 有依赖 materialLibs 中源码组件库信息进行生成产生了循环
     * 根据当前的逻辑牺牲封装在此继续修正
     */
    if ((_a = used.component) === null || _a === void 0 ? void 0 : _a['$template']) {
        const templateLib = (0, cals_1.processTemplatesToDependiencies)((_b = calses === null || calses === void 0 ? void 0 : calses[0]) === null || _b === void 0 ? void 0 : _b.templates);
        _buildContext.materialLibs = [..._buildContext.materialLibs, templateLib];
    }
    const { uin = '', appId, projDir, materialLibs: materials, mainAppData, domain, isPrivateMode = false, endpointType = '', isBrowserMpBuilder = false, } = _buildContext;
    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);
    }
    else {
        /**
         * 若主包为代码包，则下载了基础项目代码，包涵项目 projectConfigJson
         */
        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, 'project.config.json');
    let projectConfigJson = await fs.readJSON(projectConfigJsonPath);
    const miniprogramRoot = path_1.default.join(projDir, projectConfigJson.miniprogramRoot || '/');
    const localWedaRoot = path_1.default.join(miniprogramRoot, projectConfigJson.wedaRoot || '/');
    const buildContext = {
        ..._buildContext,
        wedaRoot: (0, util_3.normalizeWedaRoot)(projectConfigJson.wedaRoot),
    };
    const cssVarMap = Object.entries((0, theme_1.mergeCssVarConfig)((_d = (_c = calses[0]) === null || _c === void 0 ? void 0 : _c.theme) === null || _d === void 0 ? void 0 : _d.cssVarConfig, 'MP'))
        .map(([key, _value]) => {
        const value = _value || '';
        return [key, value.replace(/;$/, '')];
    })
        .reduce((map, [key, value]) => {
        map[key] = value;
        return map;
    }, {}) || {};
    // #1.5 安装依赖库，生成 materials 目录副作用修改了buildContext 因此需要早于页面生成
    if (hasLowcodePkg) {
        await (0, materials_1.installMaterials)(buildContext, localWedaRoot, used);
    }
    // #2 生成主包, 若主包为代码包上游已经处理过，不再处理
    if (mainAppData.mpPkgUrl) {
    }
    else {
        await generatePkg({ ...buildContext, rootPath: mainAppData.rootPath }, { cals: calses[0], weapp: mainAppData }, localWedaRoot, pageConfigs[0], cssVarMap);
    }
    // #3 生成 wedaRoot 文件
    if (hasLowcodePkg) {
        await generateFramework(buildContext, { cals: calses[0], weapp: mainAppData }, localWedaRoot, { deployOptions });
        await generateConfig({
            domain,
            isPrivateMode,
            endpointType,
        }, localWedaRoot);
        await generateWedaRootCommonFile({
            buildContext,
            buildTypeList,
            localWedaRoot,
            appId,
            loginConfigVersion: (_f = (_e = calses[0]) === null || _e === void 0 ? void 0 : _e.extra) === null || _f === void 0 ? void 0 : _f.loginConfigVersion,
            cssVarMap,
        });
        await (0, generateFiles_1.default)({
            'package.json': {
                appId,
                extraDeps: {
                    ...(0, index_1.generatePackageDependencies)({
                        importJSSDK: endpointType === 'tcb-api',
                        mode: 'app',
                        uin: buildContext.uin,
                    }),
                    ...resolveNpmDeps(weapps, materials),
                },
            },
        }, templateDir, localWedaRoot);
        // 生成数据源
        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,
                deployMode: deployOptions === null || deployOptions === void 0 ? void 0 : deployOptions.mode,
                clientID: ((_g = mainAppData.extra) === null || _g === void 0 ? void 0 : _g.enableLoginStatusShare)
                    ? mainAppData.envId
                    : (_h = mainAppData.extra) === null || _h === void 0 ? void 0 : _h.clientId,
                cdnEndpoints,
                builderVersion: core_1.version || '',
                officialLibVersion: (officialLib === null || officialLib === void 0 ? void 0 : officialLib.version) || '',
                uin,
                privatelink: buildContext.privatelinkConfig
                    ? JSON.stringify(buildContext.privatelinkConfig, undefined, 2)
                    : undefined,
            },
            '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, /* 页面的dataset由各页面本身按需注册，不再提前注册 */ []), {
                    EOL: true,
                }),
            },
        };
        console.log(`Generating ${em('datasources')} files`);
        await (0, generateFiles_1.default)(datasourceFileData, templateDir, localWedaRoot);
        // 生成上报 & 系统子包模块模块
        const subpackageRootPath = path_1.default.join(localWedaRoot, 'packages', '$wd_system');
        const sysSubpackageFileData = {
            'package.json': { cdnEndpoints, privatelink: !!buildContext.privatelinkConfig },
            'index.js.tpl': { cdnEndpoints, privatelink: !!buildContext.privatelinkConfig },
        };
        console.log(`Generating ${em('system subpackage')} files`);
        function copyFilterTplRecursiveSync(src, dest, options) {
            return (0, generateFiles_1.copyRecursiveSync)(src, dest, {
                filter: (src) => {
                    if (/.tpl$/.test(src)) {
                        return false;
                    }
                    if (options === null || options === void 0 ? void 0 : options.filter) {
                        return options === null || options === void 0 ? void 0 : options.filter(src);
                    }
                    return true;
                },
            });
        }
        Promise.all([
            !!buildContext.privatelinkConfig
                ? copyFilterTplRecursiveSync(path_1.default.join(templateDir, 'packages/$wd_system/privatelink'), path_1.default.join(subpackageRootPath, 'privatelink'))
                : Promise.resolve(),
            copyFilterTplRecursiveSync(path_1.default.join(templateDir, 'packages/$wd_system/pages'), path_1.default.join(subpackageRootPath, 'pages'), {
                filter: (src) => {
                    var _a, _b;
                    if (/login\//.test(src)) {
                        if ((_b = (_a = calses[0]) === null || _a === void 0 ? void 0 : _a.extra) === null || _b === void 0 ? void 0 : _b.loginConfigVersion) {
                            return true;
                        }
                        else {
                            return false;
                        }
                    }
                    return true;
                },
            }),
        ]);
        await (0, generateFiles_1.default)(sysSubpackageFileData, path_1.default.join(templateDir, 'packages/$wd_system'), subpackageRootPath);
    }
    // #4 生成 miniprogramRoot 文件
    if (mainAppData.mpPkgUrl) {
        // 合并 project 和 app json，复写 appId
        projectConfigJson.appId = projConfig.appId;
        projectConfigJson.setting = {
            ...projectConfigJson.setting,
            ...projConfig.setting,
            packNpmRelationList: ((_j = projConfig.setting) === null || _j === void 0 ? void 0 : _j.packNpmRelationList) || ((_k = projectConfigJson.setting) === null || _k === void 0 ? void 0 : _k.packNpmRelationList)
                ? (0, mp_config_1.mergePackNpmRelationList)(projConfig.setting.packNpmRelationList, (_l = projectConfigJson.setting) === null || _l === void 0 ? void 0 : _l.packNpmRelationList)
                : undefined,
        };
        const wedaRoot = path_1.default.posix.join('./', projectConfigJson.miniprogramRoot || '/', projectConfigJson.wedaRoot || '');
        if (!projectConfigJson.setting.packNpmManually) {
            projectConfigJson.setting.packNpmManually = true;
        }
        if (!projectConfigJson.setting.packNpmRelationList) {
            projectConfigJson.setting.packNpmRelationList = [];
        }
        projectConfigJson.setting.packNpmRelationList = (0, mp_config_1.mergePackNpmRelationList)((0, mp_config_1.generateSystemPackNpmRelationList)(wedaRoot), projectConfigJson.setting.packNpmRelationList);
        await (0, generateFiles_1.writeFile)(projectConfigJsonPath, JSON.stringify(projectConfigJson, undefined, 2));
        // 有了 framework app 之后，并且是源码的方式,追加 app 引用
        if (hasLowcodePkg) {
            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 './${path_1.default.posix.join('./', projectConfigJson.wedaRoot, 'app/weapps-api')}'\n${appJsContent}`);
        }
        const appJsonPath = path_1.default.join(miniprogramRoot, 'app.json');
        const appJson = await fs.readJson(appJsonPath);
        appJson.subpackages = (0, mp_config_1.mergeSubPackages)(((_o = (_m = appJson.subpackages) === null || _m === void 0 ? void 0 : _m.filter) === null || _o === void 0 ? void 0 : _o.call(_m, (item) => item.name !== 'wd-sys-module' && item.name !== 'wd-sys-materials')) || [], appConfig.subpackages);
        await (0, generateFiles_1.writeFile)(appJsonPath, JSON.stringify(appJson, undefined, 2));
    }
    else {
        const importor = (0, util_3.generateLowcodeImportor)(mainAppData.lowCodes || []);
        let appFileData = {
            'app.js': {
                appConfig,
                importor,
                materialSubPackagePath: path_1.default.posix.join(buildContext.wedaRoot || '', config_1.materialsDirName),
                wedaRootRelativePath: `.${path_1.default.posix.join('/', buildContext.wedaRoot || '', '/')}`,
            },
            'app.json': { content: appConfig },
            'app.wxss': {
                importStyles: materials
                    .reduce((styles, lib) => {
                    styles = styles.concat((lib.styles || []).map((stylePath) => stylePath && !stylePath.startsWith('/')
                        ? path_1.default.posix.join('./', buildContext.wedaRoot || '', config_1.materialsDirName, lib.name, stylePath)
                        : stylePath) || []);
                    return styles;
                }, [])
                    .concat(importor.styles.map((mod) => path_1.default.posix.join('./', buildContext.wedaRoot || '', 'lowcode', (0, weapps_core_1.getCodeModuleFilePath)('global', mod, { style: '.wxss' })))),
            },
        };
        console.log(`Generating ${em('miniprogramRoot')} files`);
        await (0, generateFiles_1.default)(appFileData, templateDir, miniprogramRoot);
    }
    // 若项目目录与小程序根目录不同，则拷贝素材到小程序根目录
    // if (miniprogramRoot !== path.join(projDir, '/') && fs.existsSync(path.join(projDir, materialsDirName))) {
    //   console.log(`Move ${em(materialsDirName)} from` + `${projDir} to ${miniprogramRoot}`);
    //   await fs.move(
    //     path.join(projDir, materialsDirName),
    //     path.join(miniprogramRoot, buildContext.wedaRoot || '', materialsDirName),
    //   );
    // }
    const appJsonPath = path_1.default.join(miniprogramRoot, 'app.json');
    const appJson = await fs.readJson(appJsonPath);
    // 生成子包
    await Promise.all(weapps.map(async (app, index) => {
        if (index === 0) {
            return;
        }
        else {
            const subpackageRootPath = path_1.default.join(localWedaRoot, 'packages', app.rootPath || '/');
            let subpackageBuildCtx = {
                ...buildContext,
                rootPath: app.rootPath,
            };
            if (appJson === null || appJson === void 0 ? void 0 : appJson.window) {
                subpackageBuildCtx.defaultAppWindowConfig = appJson.window;
            }
            await generatePkg(subpackageBuildCtx, { cals: calses[index], weapp: app }, subpackageRootPath, pageConfigs[index], cssVarMap);
            await generateFramework(subpackageBuildCtx, { cals: calses[index], weapp: 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,
                        extraDeps: {
                            ...(0, index_1.generatePackageDependencies)({
                                importJSSDK: endpointType === 'tcb-api',
                                mode: 'app',
                                uin: buildContext.uin,
                            }),
                            ...resolveNpmDeps(weapps, materials),
                        },
                        cdnEndpoints,
                    },
                }, templateDir, subpackageRootPath);
            }
        }
    }));
    // 将子包中 app.json / package.json merge 进主包中
    if (weapps.length > 1) {
        console.log(chalk_1.default.green('【混合模式】'), miniprogramRoot);
        await (0, mixMode_1.handleSubApps)({
            buildContext,
            apps: weapps,
            miniprogramRoot,
            wedaRoot: localWedaRoot,
        });
    }
    const roots = (path_1.default.posix.join('/', projectConfigJson.wedaRoot || '') === '/'
        ? []
        : [{ type: 'miniprogramRoot', path: miniprogramRoot }]).concat([
        { type: 'wedaRoot', path: localWedaRoot },
        { type: '$weda_system', path: path_1.default.join(localWedaRoot, 'packages', '$wd_system') },
    ]);
    for (let meta of roots) {
        if (fs.existsSync(path_1.default.join(meta.path, 'package.json'))) {
            if (isBrowserMpBuilder) {
                await (0, net_1.installBrowserDependencies)({
                    type: meta.type,
                    path: meta.path,
                    runtimeEndpointType: endpointType || undefined,
                });
            }
            else {
                await (0, webpack_1.installDependencies)(meta.path, {
                    ignoreInstall,
                    fixNodeModulesMap: { '@cloudbase/js-sdk': endpointType !== 'tcb-api', mobx: true },
                });
            }
        }
    }
    console.timeEnd(operationLabel);
    // web端的builder不需要清除
    if (!isBrowserMpBuilder) {
        cleanProj(weapps, localWedaRoot);
        cleanMaterils(path_1.default.join(localWedaRoot, config_1.materialsDirName), used);
    }
    return { miniprogramRoot };
}
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, cssVarMap) {
    var _a;
    const wxmlDataPrefix = (0, mp_1.getWxmlDataPrefix)(!ctx.isProduction);
    console.log(`Generating ${em(weapp.rootPath ? 'subApp' : 'app')} to ${appRoot}`);
    const { processCssUnit = 'rpx', defaultAppWindowConfig = {} } = ctx;
    if (weapp.mpPkgUrl) {
        // 清空历史文件，使用zip覆盖
        console.log(`Removing ${appRoot}`);
        await (0, generateFiles_1.cleanDir)(appRoot, [config_1.materialsDirName]);
        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, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
            // # 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 (/^(appShareMessage|shareTimeline)/.test(prop)) {
                    (0, util_2.setDataBind)(pageDataBinds, prop, val);
                }
            });
            if (page.styleBindPath) {
                (0, util_2.setDataBind)(pageDataBinds, 'style', {
                    type: cals_1.PropBindType.expression,
                    value: page.styleBindPath,
                });
            }
            /**
             * 使用最终的 usingComponents 生成一份 componentPlaceholder
             */
            let componentPlaceholder = ctx.enableAsyncMaterials ? (0, wxml_1.generateComponentPlaceholder)(usingComponents) : undefined;
            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),
                    /**
                     * @deprecated
                     */
                    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: {
                        appShareMessage: (_f = (_e = page.data) === null || _e === void 0 ? void 0 : _e.appShareMessage) === null || _f === void 0 ? void 0 : _f.value,
                        shareTimeline: (_h = (_g = page.data) === null || _g === void 0 ? void 0 : _g.shareTimeline) === null || _h === void 0 ? void 0 : _h.value,
                    },
                    pageDataBinds,
                    debug: ctx.debugMode,
                    /**
                     * @deprecated
                     */
                    stringifyObj: util_1.inspect,
                    subLevelPath,
                    importor,
                    query: (0, util_2.createTemplateQuery)(ctx, (_j = page.dataset) === null || _j === void 0 ? void 0 : _j.query),
                    datasetProfile: (0, util_3.JsonToStringWithVariableName)((0, lowcode_generator_1.generateDynamicDataset)(page.dataset || {}), { EOL: true }),
                    eventFlows: (0, util_2.createTemplateEventFlows)(ctx, page.eventFlows),
                    resetShare: ((_m = (_l = (_k = page === null || page === void 0 ? void 0 : page.data) === null || _k === void 0 ? void 0 : _k.appShareMessage) === null || _l === void 0 ? void 0 : _l.value) === null || _m === void 0 ? void 0 : _m.enable) ||
                        ((_o = allAppUsedComps === null || allAppUsedComps === void 0 ? void 0 : allAppUsedComps[cals_1.OFFICIAL_LIB_KEY]) === null || _o === void 0 ? void 0 : _o.has('Share')) ||
                        /* 从 enablePageRoot 的版本开始支持按需reset share
                         * 否则默认都开启
                         */ !ctx.enablePageRoot,
                },
                [`index.json|${pageFileName}.json`]: {
                    usingComponents,
                    componentGenerics,
                    componentPlaceholder,
                    extra: getAppendableJson(ctx.isBrowserMpBuilder
                        ? pageConfigs[page.id]
                        : (0, util_2.cleanWindowDefultConfig)(pageConfigs[page.id], defaultAppWindowConfig)),
                },
                [`index.wxml|${pageFileName}.wxml`]: {
                    content: wxml,
                },
                [`index.wxss|${pageFileName}.wxss`]: {
                    subWxss: rootPath && !((_p = ctx.mainAppData) === null || _p === void 0 ? void 0 : _p.mpPkgUrl)
                        ? `@import "${path_1.default.posix.relative(`/packages/${rootPath}/pages/${page.id}`, '/lowcode')}/style.wxss";`
                        : '',
                    content: [
                        (0, weapps_core_1.toCssText)(((_r = (_q = CALS_PAGE_MAP[page.id]) === null || _q === void 0 ? void 0 : _q.attributes) === null || _r === void 0 ? void 0 : _r.style) &&
                            ((_u = Object.keys(((_t = (_s = CALS_PAGE_MAP[page.id]) === null || _s === void 0 ? void 0 : _s.attributes) === null || _t === void 0 ? void 0 : _t.style) || {})) === null || _u === void 0 ? void 0 : _u.length)
                            ? (0, cals_1.processCSSPropertiesUnit)(((_w = (_v = CALS_PAGE_MAP[page.id]) === null || _v === void 0 ? void 0 : _v.attributes) === null || _w === void 0 ? void 0 : _w.style) || {}, processCssUnit)
                            : (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, cssVarMap);
    }
}
async function generateFramework(ctx, { cals, weapp: appData }, outDir, options) {
    var _a, _b, _c;
    let fileData = {};
    if (appData.mpPkgUrl) {
        /**
         * 当前包为代码包 + 主包
         * framework 基础兜底
         */
        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: {},
                    /**
                     * @deprecated
                     */
                    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,
                        loginConfigVersion: (_b = cals.extra) === null || _b === void 0 ? void 0 : _b.loginConfigVersion,
                        basename: ctx.wedaRoot,
                        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, (_c = appData.dataset) === null || _c === void 0 ? void 0 : _c.query),
                    /**
                     * @deprecated
                     */
                    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, cssVarMap) {
    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)) {
        const globalTheme = `${ctx.enablePageRoot && cssVarMap ? (0, weapps_core_1.toCssText)(cssVarMap || {}, 'page, page .wd-mp-root') : ''}${(themeStyle === null || themeStyle === void 0 ? void 0 : themeStyle.code) || ''}`;
        await Promise.all(lowCodes
            .filter((mod) => mod.type !== cals_1.ECodeType.RENDERER)
            .map((m) => {
            (0, lowcode_1.writeCode2file)(ctx, m, lowcodeRootDir, { appDir: outDir }, globalTheme);
        }));
    }
    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, shareTimeline, ...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, wedaRoot) {
    weapps.map((pkg) => cleanPkg(pkg, wedaRoot));
}
async function cleanPkg(pkg, wedaRoot) {
    // zip 模式跳过clean
    if (pkg.mpPkgUrl) {
        return;
    }
    const pkgDir = [wedaRoot, 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']);
        });
    }
}
