"use strict";
/* eslint-disable no-new-func */
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateEventFlows = exports.generateDatasetQuery = exports.generateListnerInstances = exports.generateDataBindForDataset = exports.generateDataBinds = exports.getComponentSchema = exports.splitDynamicMap = exports.getComponentsInfo = void 0;
const common_1 = require("../common");
const cals_1 = require("@cloudbase/cals");
const lodash_es_1 = require("lodash-es");
const index_1 = require("./index");
const constants_1 = require("../constants");
const index_2 = require("../index");
const query_1 = require("../query");
const flow_1 = require("../flow");
const dependencies_1 = require("./dependencies");
function getComponentsInfo(dependencies) {
    const outputObj = {};
    dependencies.forEach(({ name: materialName, components, isComposite }) => {
        components.forEach(({ name, meta, emitEvents, events = undefined, isContainer, compConfig, dataForm, properties, }) => {
            outputObj[`${materialName}:${name}`] = Object.assign(Object.assign({ isComposite }, (0, dependencies_1.componentMetaFilter)(meta)), { events,
                emitEvents,
                isContainer,
                compConfig,
                dataForm,
                properties });
        });
    });
    return outputObj;
}
exports.getComponentsInfo = getComponentsInfo;
function getInputProps(componentsMetaMap) {
    const outputObj = {};
    // eslint-disable-next-line no-restricted-syntax
    for (let key in componentsMetaMap) {
        let component = componentsMetaMap[key];
        const sourceKey = key;
        const inputProps = (component === null || component === void 0 ? void 0 : component.inputProps) || (component === null || component === void 0 ? void 0 : component.syncProps);
        if (inputProps) {
            outputObj[sourceKey] = inputProps;
        }
        let compItem = component;
        Object.keys(compItem.dataForm || {}).forEach((key) => {
            var _a, _b;
            const inputProps = ((_a = compItem.dataForm[key]) === null || _a === void 0 ? void 0 : _a.inputProp) || ((_b = compItem.dataForm[key]) === null || _b === void 0 ? void 0 : _b.syncProp);
            if (inputProps) {
                outputObj[sourceKey] = Object.assign({ [key]: inputProps }, (outputObj[sourceKey] || {}));
            }
        });
    }
    return outputObj;
}
/**
 * utils end
 */
function splitDynamicMap(data) {
    const staticData = {};
    const dataBinds = [];
    for (let key in data) {
        let meta = data[key];
        if (!meta.type || meta.type === cals_1.PropBindType.static) {
            staticData[key] = meta.value;
        }
        else if (meta.type === cals_1.PropBindType.slot) {
            continue;
        }
        else {
            dataBinds.push({
                type: meta.type,
                bindDataPath: meta.value,
                propertyPath: key,
            });
        }
    }
    return { staticData, dataBinds };
}
exports.splitDynamicMap = splitDynamicMap;
function walkThroughCals(cals, process, options = {}) {
    var _a, _b;
    let { items = [] } = cals;
    cals.extra = cals.extra || {};
    if (((_a = cals === null || cals === void 0 ? void 0 : cals.directives) === null || _a === void 0 ? void 0 : _a[':if']) === false) {
        cals.items = [];
    }
    const filteredItems = [];
    for (let item of items) {
        if (((_b = item === null || item === void 0 ? void 0 : item.directives) === null || _b === void 0 ? void 0 : _b[':if']) === false) {
            continue;
        }
        filteredItems.push(item);
        item.extra = item.extra || {};
        item.extra.__parent = cals;
    }
    cals.items = filteredItems;
    // 先根遍历 因为父上的状态可能需要带下去
    process(cals, options);
    for (let item of cals.items) {
        walkThroughCals(item, process, options);
    }
    return cals;
}
function parseDirectiveIfAndDispaly(directiveValue) {
    let value;
    switch (directiveValue) {
        case true:
        case false: {
            value = directiveValue;
            break;
        }
        case undefined: {
            value = true;
            break;
        }
    }
    return value;
}
/**
 * widgets 不包括page 的 widges
 */
function getComponentSchema(ctx, page, componentsInfoMap = {}, wrapperClass, options) {
    const { processCssUnit = 'rem', looseError = false, isComposite = false } = options || {};
    const componentInputProps = getInputProps(componentsInfoMap) || {};
    const copyJson = JSON.parse(JSON.stringify(page, (key, value) => {
        var _a;
        /**
         * 处理默认的 module 补全
         */
        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;
            if ((value === null || value === void 0 ? void 0 : value.component) &&
                (`${component.module}:${component.component}` === `${constants_1.REPEATER.MODULE_NAME}:${constants_1.REPEATER.REPEATER_NAME}` ||
                    `${component.module}:${component.component}` === `${constants_1.REPEATER.DEBUG_MODULE_NAME}:${constants_1.REPEATER.REPEATER_NAME}`)) {
                // 给 Repeater 组件加一层虚拟项组件，在虚拟项组件上挂 for 循环
                const { items = [] } = component;
                const firstChildComponent = items[0];
                if (`${firstChildComponent === null || firstChildComponent === void 0 ? void 0 : firstChildComponent.module}:${firstChildComponent === null || firstChildComponent === void 0 ? void 0 : firstChildComponent.component}` ===
                    `${constants_1.REPEATER.MODULE_NAME}:${constants_1.REPEATER.REPEATER_ITEM_NAME}` ||
                    `${firstChildComponent === null || firstChildComponent === void 0 ? void 0 : firstChildComponent.module}:${firstChildComponent === null || firstChildComponent === void 0 ? void 0 : firstChildComponent.component}` ===
                        `${constants_1.REPEATER.DEBUG_MODULE_NAME}:${constants_1.REPEATER.REPEATER_ITEM_NAME}`) {
                    return value;
                }
                component.items = [
                    {
                        component: constants_1.REPEATER.REPEATER_ITEM_NAME,
                        module: component.module,
                        directives: {
                            ':if': true,
                            ':for': component.attributes[':data'],
                            key: component.attributes.key || '',
                            ':display': (_a = component.directives) === null || _a === void 0 ? void 0 : _a[':display'],
                        },
                        items: items.map((item) => {
                            var _a;
                            let currentDisplay = (_a = 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;
                        }),
                        id: `$weda_internal_${component.id}`, // uniqueId() 解决在编辑器中切换组件导致 children 不断增加的问题
                    },
                ];
            }
        }
        return value;
    }));
    const compWidgets = {};
    const compDataBinds = {};
    const componentSchemaJson = walkThroughCals(copyJson, (component, options = {}) => {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
        const parentComponent = component.extra.__parent;
        if ((0, common_1.isSlot)(component)) {
            if (parentComponent) {
                const slotId = `${parentComponent.id}.${component.id}`;
                const parentComponentSourceKey = `${parentComponent.module}:${parentComponent.component}`;
                const sourceKey = `${parentComponentSourceKey}.${component.id}`;
                const { isScopeSlot, config: scopeSlotConfig, useScopeWidgetData = false, } = (0, common_1.getScopeSlotMeta)(parentComponent, component.id, {
                    componentsInfoMap,
                });
                if (isScopeSlot) {
                    compWidgets[slotId] = {
                        _visible: true,
                        _display: true,
                        style: {},
                        classList: [],
                        widgetType: sourceKey,
                        _parentId: parentComponent.id,
                        getConfig: () => ({}),
                        _waForKey: undefined,
                    };
                    if (!useScopeWidgetData) {
                        options.useScopeWidgetData = false;
                    }
                    if ((_a = scopeSlotConfig === null || scopeSlotConfig === void 0 ? void 0 : scopeSlotConfig['x-slot-directives']) === null || _a === void 0 ? void 0 : _a.for) {
                        compDataBinds[slotId] = generateDataBinds(ctx, [
                            {
                                type: cals_1.PropBindType.expression,
                                bindDataPath: `$w.${parentComponent.id}.${(_b = scopeSlotConfig === null || scopeSlotConfig === void 0 ? void 0 : scopeSlotConfig['x-slot-directives']) === null || _b === void 0 ? void 0 : _b.for}`,
                                // bindDataPath: '$page.dataset.state.list',
                                propertyPath: '_waFor',
                            },
                        ], {
                            isComposite,
                            looseError,
                            key: `组件 ${slotId}`,
                            useScopeWidgetData: true,
                        });
                    }
                }
            }
            return;
        }
        const { component: componentName, module, attributes = {} } = component;
        const { commonStyle = {} } = component.extra || {};
        const rpxCalcRoot = `var(${index_2.CALC_RPX_ROOT_VAL_NAME})`;
        const processedCommonStyle = attributes.style
            ? (0, cals_1.processCSSPropertiesUnit)(attributes.style || {}, processCssUnit, { rpxCalcRoot })
            : (0, cals_1.processCommonStyle2CSSProperties)(commonStyle, {
                defaultUnit: processCssUnit,
                rpxCalcRoot,
            });
        if (processedCommonStyle) {
            component.extra.commonStyle = processedCommonStyle;
        }
        const sourceKey = `${module}:${componentName}`;
        // 如果是复合组件的根节点，则补充 wrapperClass
        if (isComposite) {
            if (((_c = component === null || component === void 0 ? void 0 : component.extra) === null || _c === void 0 ? void 0 : _c.__parent) && !((_f = (_e = (_d = component === null || component === void 0 ? void 0 : component.extra) === null || _d === void 0 ? void 0 : _d.__parent) === null || _e === void 0 ? void 0 : _e.extra) === null || _f === void 0 ? void 0 : _f.__parent)) {
                if (!component.attributes) {
                    component.attributes = {};
                }
                component.attributes.class = Array.from(new Set([component.attributes.class, wrapperClass === null || wrapperClass === void 0 ? void 0 : wrapperClass.split(/\s/)]))
                    .filter((item) => !!item)
                    .join(' ');
            }
        }
        const { class: className = '' } = attributes;
        /**
         * TODO:
         * 此处有变更，之前强行声明 page 为传进来的 schema
         */
        const deserializeCtx = isComposite ? { page: page } : {};
        let dynamicStyle = component[':style']
            ? (0, cals_1.deserializeValue)(deserializeCtx, ':style', component[':style']).value
            : undefined;
        let dynamicClassList = component[':class']
            ? (0, cals_1.deserializeValue)(deserializeCtx, ':class', component[':class']).value
            : undefined;
        let dynamicIf = ((_g = component.directives) === null || _g === void 0 ? void 0 : _g[':if'])
            ? (0, cals_1.deserializeValue)(deserializeCtx, ':if', (_h = component.directives) === null || _h === void 0 ? void 0 : _h[':if']).value
            : undefined;
        let dynamicDisplay = ((_j = component.directives) === null || _j === void 0 ? void 0 : _j[':display'])
            ? (0, cals_1.deserializeValue)(deserializeCtx, ':display', (_k = component.directives) === null || _k === void 0 ? void 0 : _k[':display']).value
            : undefined;
        let dynamicFor = ((_l = component.directives) === null || _l === void 0 ? void 0 : _l[':for'])
            ? (0, cals_1.deserializeValue)(deserializeCtx, ':for', (_m = component.directives) === null || _m === void 0 ? void 0 : _m[':for']).value
            : undefined;
        if (dynamicIf != undefined &&
            (dynamicIf.value == undefined || dynamicIf.value === true || dynamicIf.value === false)) {
            dynamicIf = undefined;
        }
        if (dynamicDisplay != undefined &&
            (dynamicDisplay.value == undefined || dynamicDisplay.value === true || dynamicDisplay.value === false)) {
            dynamicDisplay = undefined;
        }
        if (dynamicFor) {
            let { type, value } = dynamicFor;
            if (type === cals_1.PropBindType.expression) {
                dynamicFor.value = value.replace(/^(.*?in\s)/, '');
            }
        }
        const data = (0, cals_1.deserializeAttributes)(deserializeCtx, attributes);
        const { dataBinds, staticData } = splitDynamicMap(data);
        const componentInfo = componentsInfoMap[sourceKey];
        if (componentInfo === null || componentInfo === void 0 ? void 0 : componentInfo.compConfig) {
            component.extra.compConfig = componentInfo === null || componentInfo === void 0 ? void 0 : componentInfo.compConfig;
        }
        if (componentInfo === null || componentInfo === void 0 ? void 0 : componentInfo.events) {
            component.extra.emitEvents = componentInfo === null || componentInfo === void 0 ? void 0 : componentInfo.events.map((item) => item.name);
        }
        else if (componentInfo === null || componentInfo === void 0 ? void 0 : componentInfo.emitEvents) {
            component.extra.emitEvents = componentInfo.emitEvents.map((item) => item.eventName);
        }
        // 生成 widgets/dataBinds
        if (!(0, common_1.isSlot)(component) && component.id) {
            let _visible = parseDirectiveIfAndDispaly((_o = component.directives) === null || _o === void 0 ? void 0 : _o[':if']);
            let _display = parseDirectiveIfAndDispaly((_p = component === null || component === void 0 ? void 0 : component.directives) === null || _p === void 0 ? void 0 : _p[':display']);
            if (component.type !== 'PAGE') {
                /**
                 * TODO:
                 * 原版中 _parentId 赋值
                 *  _parentId: parentComponent
                 *  ? isSlot(parentComponent)
                 *    ? parentComponent.extra?.__parent?.id
                 *   : parentComponent.id
                 * : null,
                 */
                let _parentId = null;
                if (parentComponent) {
                    _parentId = parentComponent.id;
                    if (parentComponent.type === cals_1.EComponentType.PAGE || parentComponent.type === cals_1.EComponentType.COMPLEX) {
                        _parentId = (_r = (_q = parentComponent.extra) === null || _q === void 0 ? void 0 : _q.__parent) === null || _r === void 0 ? void 0 : _r.id;
                    }
                    else if ((0, common_1.isSlot)(parentComponent)) {
                        _parentId = (_t = (_s = parentComponent.extra) === null || _s === void 0 ? void 0 : _s.__parent) === null || _t === void 0 ? void 0 : _t.id;
                        const { isScopeSlot } = (0, common_1.getScopeSlotMeta)(parentComponent.extra.__parent, parentComponent.id, {
                            componentsInfoMap,
                        });
                        if (isScopeSlot) {
                            _parentId = `${(_u = parentComponent.extra.__parent) === null || _u === void 0 ? void 0 : _u.id}.${parentComponent.id}`;
                        }
                    }
                }
                compWidgets[component.id] = Object.assign(Object.assign({}, Object.entries(staticData).reduce((data, [propsKey, propsValue]) => {
                    let value = propsValue;
                    if (value && Array.isArray(value)) {
                        value = value.map((_, index) => {
                            var _a, _b;
                            const block = (_a = attributes[propsKey]) === null || _a === void 0 ? void 0 : _a[index]; // 因为 value 里的是序列化过的，尤其是选区的是时候
                            const blockInstances = (_b = block === null || block === void 0 ? void 0 : block.selectableBlock) === null || _b === void 0 ? void 0 : _b.listeners;
                            if (blockInstances) {
                                block.selectableBlock.listenerInstances = generateListnerInstances(ctx, blockInstances || [], {
                                    isComposite,
                                    looseError,
                                    useScopeWidgetData: options.useScopeWidgetData === undefined ? true : options.useScopeWidgetData,
                                });
                                return block;
                            }
                            else {
                                // 普通的非选区的，返回staticData 里的值
                                return _;
                            }
                        });
                    }
                    data[propsKey] = value;
                    return data;
                }, {})), { 
                    /**
                     * 此处新增key，需要同步定义 widgets.ts/widgetKeys 常量
                     */
                    _visible,
                    _display, style: Object.assign({}, processedCommonStyle), classList: className.split(/\s/).filter((item) => !!item), widgetType: sourceKey, _parentId, getConfig: () => {
                        var _a;
                        return (_a = componentInfo === null || componentInfo === void 0 ? void 0 : componentInfo.compConfig) !== null && _a !== void 0 ? _a : {};
                    }, _waForKey: (_v = component.directives) === null || _v === void 0 ? void 0 : _v.key });
            }
            const processedDataBinds = [...dataBinds];
            const dynamicMetaList = [
                { property: '_visible', meta: dynamicIf },
                { property: '_display', meta: dynamicDisplay },
                { property: '_waFor', meta: dynamicFor },
                { property: 'style', meta: dynamicStyle },
                { property: 'classList', meta: dynamicClassList },
            ];
            for (let item of dynamicMetaList) {
                const { property, meta } = item;
                if (meta === null || meta === void 0 ? void 0 : meta.value) {
                    processedDataBinds.push({
                        type: meta.type,
                        bindDataPath: meta.value,
                        propertyPath: property,
                    });
                }
            }
            if (processedDataBinds.length > 0) {
                compDataBinds[component.id] = generateDataBinds(ctx, processedDataBinds, {
                    isComposite,
                    looseError,
                    key: `组件 ${component.id}`,
                    useScopeWidgetData: options.useScopeWidgetData === undefined ? true : options.useScopeWidgetData,
                });
            }
        }
        component.listenerInstances = generateListnerInstances(ctx, component.listeners || [], {
            isComposite,
            looseError,
            key: `组件事件 ${component.id}`,
            useScopeWidgetData: options.useScopeWidgetData === undefined ? true : options.useScopeWidgetData,
        });
        delete component.listeners;
        if (!(0, common_1.isEmptyObj)(attributes)) {
            // 组件双向绑定
            const syncProps = componentInputProps[sourceKey];
            if (syncProps) {
                Object.keys(syncProps).forEach((syncPropKey) => {
                    const syncProp = syncProps[syncPropKey];
                    let syncPropArr = syncProp !== null && syncProp !== void 0 ? syncProp : [];
                    // 统一转成数组处理
                    if (!Array.isArray(syncProp)) {
                        syncPropArr = [syncProp];
                    }
                    else {
                        syncPropArr = syncPropArr;
                    }
                    syncPropArr.forEach(({ changeEvent, valueFromEvent }) => {
                        // 双向绑定需要优先第一个执行，否则会出现输入框的拼音被打断的问题
                        function withContext(context) {
                            let instance = new index_1.runtime.Function('context', `return function({ event, forItems }) {
                  const $for = forItems;
                  const $index = $for.forIndexes ? $for.forIndexes[$for.forIndexes.length - 1] : undefined;
                  const wid = ${isComposite ? 'this.widgets' : 'context.$page.widgets'}.${component.id};
                  const widgetData = $for.forIndexes && $for.forIndexes.length > 0 ? context.get(wid, forItems.forIndexes) : wid;
                  widgetData.${syncPropKey} = ${valueFromEvent}
                }`)(context);
                            return ctx.this ? instance.bind(this) : instance;
                        }
                        component.listenerInstances.unshift({
                            trigger: changeEvent,
                            instanceFunction: withContext(Object.assign(Object.assign({}, ctx), { get: lodash_es_1.get })),
                        });
                    });
                });
            }
        }
    });
    return {
        widgets: compWidgets,
        dataBinds: compDataBinds,
        componentSchema: componentSchemaJson,
    };
}
exports.getComponentSchema = getComponentSchema;
// convert data binds to functions for performance & simplicity
function generateDataBinds(ctx, dataBinds, options) {
    const dataBindFuncs = {};
    const { useScopeWidgetData = true } = options || {};
    dataBinds.forEach((bind) => {
        var _a, _b;
        if (!bind.bindDataPath) {
            return console.warn('bindDataPath error', bind.propertyPath);
        }
        let databindFunction = () => { };
        let funcCode = `function (){}`;
        const alias = `
const $for = forItems;
const $index = $for.forIndexes ? $for.forIndexes[$for.forIndexes.length - 1] : undefined;
`;
        try {
            if (bind.type === cals_1.PropBindType.forItem) {
                funcCode = `function(forItems){ return forItems.${bind.bindDataPath} } `;
            }
            else if (bind.type === 'scope') {
                funcCode = `function(_, __, ___, ____, $scope, _____){ ${useScopeWidgetData
                    ? 'return $scope.${bind.bindDataPath};'
                    : `return ({__type: "scopedValue", getValue: function($scope){ return $scope.${bind.bindDataPath}}});`} }`;
            }
            else if (bind.type === cals_1.PropBindType.expression) {
                if (options === null || options === void 0 ? void 0 : options.isComposite) {
                    funcCode = `function(forItems, $context, $w) {${alias}; return (\n${bind.bindDataPath.replace(/;$/, '') || 'undefined'}\n);}`;
                }
                else {
                    const code = bind.bindDataPath.replace(/;$/, '');
                    const content = `${alias} return (\n${code || 'undefined'}\n)`;
                    if ((!useScopeWidgetData && /\$scope\./.test(code)) || code === '$scope') {
                        funcCode = `(forItems, event, $context, $w, $scope, params) => ({__type: "scopedValue", getValue: ($scope) => { ${content} }})`;
                    }
                    else {
                        funcCode = `(forItems, event, $context, $w, $scope, params) => {${content}}`;
                    }
                }
            }
            else if (bind.type === cals_1.PropBindType.prop) {
                let { bindDataPath } = bind;
                const isNegated = bindDataPath.startsWith('!');
                if (isNegated)
                    bindDataPath = bindDataPath.replace(/^!/, '');
                if (options === null || options === void 0 ? void 0 : options.isComposite) {
                    // 复合组件在预览时其实就是page，所以沿用page的变量即可
                    funcCode = `function() { return ${isNegated ? '!' : ''}$comp.props.data.${bindDataPath} }`;
                }
                else {
                    // 复合组件在预览时其实就是page，所以沿用page的变量即可
                    funcCode = `function() { return ${isNegated ? '!' : ''}$page.props.data.${bindDataPath} }`;
                }
            }
            else {
                const isGlobal = bind.bindDataPath.startsWith('global.');
                let returnValue = '';
                const PREFIX_MAP = {
                    [cals_1.PropBindType.state]: 'state',
                    [cals_1.PropBindType.computed]: 'computed',
                    // [PropBindType.dataVar]: 'dataVar',
                    [cals_1.PropBindType.stateData]: 'dataset.state',
                    [cals_1.PropBindType.paramData]: 'dataset.params',
                };
                switch (bind.type) {
                    case cals_1.PropBindType.state:
                    case cals_1.PropBindType.computed:
                    // case PropBindType.dataVar:
                    case cals_1.PropBindType.stateData:
                    case cals_1.PropBindType.paramData: {
                        if (isGlobal) {
                            returnValue = bind.bindDataPath.replace(/^global([.[])/, (_, $1) => `$app.${PREFIX_MAP[bind.type]}${$1}`);
                        }
                        else {
                            if (options === null || options === void 0 ? void 0 : options.isComposite) {
                                returnValue = bind.bindDataPath
                                    .replace(/^comp-\w+([.[])/, (_, $1) => `$comp.${PREFIX_MAP[bind.type]}${$1}`)
                                    .replace(/^\$\w+_\d+([.[])/, (_, $1) => `$comp.${PREFIX_MAP[bind.type]}${$1}`);
                            }
                            else {
                                returnValue = bind.bindDataPath.replace(/^\w+([.[])/, (_, $1) => `$page.${PREFIX_MAP[bind.type]}${$1}`);
                            }
                        }
                        funcCode = `function(){ return ${returnValue} }`;
                        break;
                    }
                }
            }
            const imports = Object.keys(((_a = ctx === null || ctx === void 0 ? void 0 : ctx.$app) === null || _a === void 0 ? void 0 : _a.utils) || {}).map((key) => {
                return `const ${key} = $app.utils["${key}"]`;
            });
            if (imports.length) {
                imports.push('');
            }
            try {
                databindFunction = new index_1.runtime.Function('context', `const { $page, $app, $comp } = context || {};
          const app = $app;
          ${imports.join(';')}
          return ${funcCode}`)(ctx);
            }
            catch (e) {
                let errorType = e instanceof SyntaxError ? '语法错误' : '错误';
                e.message = `${options.key ? `${options.key}.` : ''}${bind.propertyPath} 绑定${errorType}: ${(_b = e.message) === null || _b === void 0 ? void 0 : _b.replace(/^Unexpected token/, '非法字符')}`;
                throw e;
            }
            if (ctx.this) {
                databindFunction = databindFunction.bind(ctx.this);
            }
        }
        catch (e) {
            if (options === null || options === void 0 ? void 0 : options.looseError) {
                console.error('generate dynamic data error:', e);
                databindFunction = () => {
                    throw e;
                };
            }
            else {
                throw e;
            }
        }
        dataBindFuncs[bind.propertyPath] = databindFunction;
    });
    return dataBindFuncs;
}
exports.generateDataBinds = generateDataBinds;
/**
 * dataset 特殊的绑定格式
 * 要求：入参分别为 app ， page
 * 绑定只有变量，参数，表达式的绑定
 */
function generateDataBindForDataset(bind) {
    let expr = '';
    const { type, bindDataPath } = bind;
    if (type === cals_1.PropBindType.static || !type) {
        expr = typeof bindDataPath === 'string' ? `'${bindDataPath}'` : JSON.stringify(bindDataPath);
    }
    else if (type === cals_1.PropBindType.expression) {
        expr = bindDataPath;
    }
    else {
        const isGlobal = bindDataPath.startsWith('global.');
        const isCopositive = bindDataPath.startsWith('comp-') || bindDataPath.startsWith('$comp_');
        const PREFIX_MAP = {
            [cals_1.PropBindType.state]: 'state',
            [cals_1.PropBindType.computed]: 'computed',
            [cals_1.PropBindType.dataVar]: 'dataVar',
            [cals_1.PropBindType.stateData]: 'dataset.state',
            [cals_1.PropBindType.paramData]: 'dataset.params',
        };
        switch (type) {
            case cals_1.PropBindType.state:
            case cals_1.PropBindType.computed:
            case cals_1.PropBindType.dataVar:
            case cals_1.PropBindType.stateData:
            case cals_1.PropBindType.paramData: {
                if (isCopositive) {
                    expr = bindDataPath
                        .replace(/^comp-\w+/, `$comp.${PREFIX_MAP[type]}`)
                        .replace(/^\$comp_\w+/, `$comp.${PREFIX_MAP[type]}`);
                }
                else {
                    expr = bindDataPath
                        .replace(/^\w+./, `${isGlobal ? 'app' : '$page'}.${PREFIX_MAP[type]}.`)
                        .replace(/^comp-\w+/, `$comp.${PREFIX_MAP[type]}`)
                        .replace(/^\$comp_\w+/, `$comp.${PREFIX_MAP[type]}`);
                }
            }
        }
    }
    return new index_1.runtime.Function('app, $page, $w', `const $app = app;
    const imports = Object.keys(app && app.utils || {}).map(function (key) {
      return \`const \${key} = app.utils["\${key}"]\`;
    });
    if(imports.length) {
      imports.push('')
    }
    const body =  imports.join(';')+\`return (\n${expr || 'undefined'}\n)\`
   return new Function("", body)()`);
}
exports.generateDataBindForDataset = generateDataBindForDataset;
function generateListnerInstances(ctx, listenerInstances, options = {
    isComposite: false,
    key: '',
    useScopeWidgetData: true,
}) {
    const { isComposite = false } = options;
    return listenerInstances.map((listener) => {
        var _a, _b, _c, _d, _e, _f, _g;
        const generatedListener = {
            key: listener.id,
            trigger: listener.eventName,
            isCapturePhase: !!listener.isCapturePhase,
            noPropagation: listener.noPropagation,
            instanceFunction: () => { },
            data: {},
            dataBinds: {},
        };
        if (listener.type === cals_1.ActionType.Material) {
            const { name, module } = listener.handler || {};
            generatedListener.instanceFunction = new index_1.runtime.Function('context', `const { $page, $app, actionsMap = {} } = context || {};
        const app = $app;
        const sourceKey = "${module}:${name}";
        return function(...args){ return actionsMap[sourceKey] &&  actionsMap[sourceKey].apply(null, args)} `)(ctx);
        }
        else if (listener.type === cals_1.ActionType.PropEvent) {
            if (isComposite) {
                generatedListener.instanceFunction = new index_1.runtime.Function('context', `return function ({ data, event, forItems, $w }) {
            event.detail.data = data
            return context.$comp.props.emit('${
                // TODO: CHECK listener.handler.name 具体是什么
                listener.handler.name || listener.jsCode}', event.detail);}`)(ctx);
            }
            else {
                generatedListener.instanceFunction = new index_1.runtime.Function('context', `return function (...args) { return context.$page.props.events.${((_a = listener.handler) === null || _a === void 0 ? void 0 : _a.name) || listener.jsCode}.apply(null, args);}`)(ctx);
            }
        }
        else if (listener.type === cals_1.ActionType.Inline) {
            // 内联 handler
            const instance = new index_1.runtime.Function('{event, data, forItems, $w}', `return ${listener.jsCode}`);
            generatedListener.instanceFunction = instance.bind(isComposite ? ctx.$comp : ctx.$page);
        }
        else if (listener.type === cals_1.ActionType.Platform) {
            let name = ((_b = listener.handler) === null || _b === void 0 ? void 0 : _b.name) || listener.jsCode;
            generatedListener.sourceKey = `${((_c = listener.handler) === null || _c === void 0 ? void 0 : _c.module) || ''}:${((_d = listener.handler) === null || _d === void 0 ? void 0 : _d.name) || ''}`;
            let functionBody = '';
            switch (name) {
                case 'callNanoFlow': {
                    functionBody = `const flow = context.$page.__internal__.$w[data.id]; return flow && flow.trigger(data.data)`;
                    break;
                }
                case 'callQuery': {
                    functionBody = `const query = context.$page.__internal__.$w[data.id]; return query && query[data.method](data.data)`;
                    break;
                }
                case 'invoke': {
                    functionBody = `return context.$app.invoke({...data, component: $w[data.component]})`;
                    break;
                }
                case 'setCurrentPageParams': {
                    functionBody = `return context.$app.utils.getCurrentPage().setParams(data.params);`;
                    break;
                }
                default: {
                    functionBody = ` return context.$app.${name}(data) `;
                }
            }
            generatedListener.instanceFunction = new index_1.runtime.Function('context', `return function({data, $w}){ ${functionBody} } `)(ctx);
        }
        else if (listener.type === cals_1.ActionType.DataSource) {
            generatedListener.instanceFunction = new index_1.runtime.Function('context', `return function({data}) {return context.$app.cloud.callDataSource(data)}`)(ctx);
        }
        else {
            // Lowcode action(handler)
            if (isComposite) {
                generatedListener.instanceFunction = new index_1.runtime.Function('context', `return context.$comp.handler.${((_e = listener.handler) === null || _e === void 0 ? void 0 : _e.name) || listener.jsCode}.bind(context.$comp)`)(ctx);
            }
            else {
                let name = ((_f = listener.handler) === null || _f === void 0 ? void 0 : _f.name) || listener.jsCode;
                generatedListener.instanceFunction = new index_1.runtime.Function('context', `return context.$page.handler.${name}`)(ctx);
            }
        }
        const processedParams = (0, cals_1.deserializeDynamicMap)({
            page: isComposite ? undefined : { id: ctx.$page.id, type: cals_1.EComponentType.PAGE },
        }, (_g = listener.handler) === null || _g === void 0 ? void 0 : _g.params);
        const { staticData, dataBinds } = splitDynamicMap(processedParams);
        generatedListener.data = staticData;
        generatedListener.dataBinds = generateDataBinds(ctx, dataBinds, Object.assign(Object.assign({}, options), { key: `${options.key ? `${options.key}.` : ''}listener.${listener.eventName}` }));
        return generatedListener;
    });
}
exports.generateListnerInstances = generateListnerInstances;
function generateDatasetQuery(schema, context, options) {
    const result = {};
    for (const key in schema) {
        result[key] = new query_1.Query({ schema: schema[key], context, options });
    }
    return result;
}
exports.generateDatasetQuery = generateDatasetQuery;
function generateEventFlows(flows = [], context, options) {
    const result = {};
    for (let flow of flows) {
        result[flow.id] = new flow_1.EventFlow({ schema: flow, context, options });
    }
    return result;
}
exports.generateEventFlows = generateEventFlows;
//# sourceMappingURL=generate.js.map