UNPKG

@pisell/pisellos

Version:

一个可扩展的前端模块化SDK框架,支持插件系统

451 lines (449 loc) 14 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/model/strategy/engine.ts var engine_exports = {}; __export(engine_exports, { StrategyEngine: () => StrategyEngine, createStrategyEngine: () => createStrategyEngine, evaluate: () => evaluate }); module.exports = __toCommonJS(engine_exports); var import_type = require("./type"); var StrategyEngine = class { constructor(options = {}) { this.options = { debug: options.debug ?? false, enableTrace: options.enableTrace ?? false, operatorHandlers: options.operatorHandlers ?? {}, errorHandler: options.errorHandler ?? ((error) => console.error(error)) }; this.operatorHandlers = new Map( Object.entries(this.options.operatorHandlers) ); this.initializeBuiltInOperators(); } /** * 评估策略 */ evaluate(config, context) { var _a; const startTime = Date.now(); const trace = { steps: [], duration: 0, errors: [] }; try { this.validateConfig(config); if (this.options.enableTrace) { trace.steps.push({ step: "validate_config", status: "success", duration: Date.now() - startTime }); } const evaluateStart = Date.now(); const evaluationResult = this.evaluateConditionGroup( config.conditions, context ); if (this.options.enableTrace) { trace.steps.push({ step: "evaluate_conditions", status: "success", duration: Date.now() - evaluateStart, details: { satisfied: evaluationResult.satisfied, collectedActionIds: evaluationResult.actionIds } }); } const actionStart = Date.now(); const matchedActions = this.getActionsByIds( evaluationResult.actionIds, config.actions ); if (this.options.enableTrace) { trace.steps.push({ step: "get_actions", status: "success", duration: Date.now() - actionStart, details: { matchedCount: matchedActions.length } }); } const sortStart = Date.now(); const sortedActions = this.sortActionsByPriority(matchedActions); if (this.options.enableTrace) { trace.steps.push({ step: "sort_actions", status: "success", duration: Date.now() - sortStart }); } const applicable = evaluationResult.satisfied; const result = { success: true, applicable, code: applicable ? import_type.SUCCESS_CODES.SUCCESS : import_type.NOT_APPLICABLE_CODES.CONDITION_NOT_MET, message: applicable ? "Strategy is applicable" : "Conditions not met", matched: { conditions: applicable, actionIds: evaluationResult.actionIds, details: {} }, matchedActions: sortedActions, outputs: {}, config }; trace.duration = Date.now() - startTime; if (this.options.enableTrace) { result.trace = trace; } return result; } catch (error) { const errorMessage = error instanceof Error ? error.message : "Unknown error"; if (this.options.enableTrace) { (_a = trace.errors) == null ? void 0 : _a.push({ step: "evaluation", error: errorMessage, timestamp: Date.now() }); trace.duration = Date.now() - startTime; } this.options.errorHandler(error, context); return { success: false, applicable: false, code: import_type.ERROR_CODES.EVALUATION_ERROR, message: errorMessage, matched: { conditions: false, actionIds: [], details: {} }, matchedActions: [], outputs: {}, trace: this.options.enableTrace ? trace : void 0, config }; } } /** * 递归评估条件组 * * @param group 条件组 * @param context 运行时上下文 * @returns 评估结果对象,包含条件是否满足和收集到的 actionIds */ evaluateConditionGroup(group, context) { const collectedActionIds = []; const isCurrentLayerSatisfied = this.evaluateGroupLogic(group, context); if (isCurrentLayerSatisfied) { collectedActionIds.push(...group.actionIds); for (const rule of group.rules) { if (this.isConditionGroup(rule)) { const nestedResult = this.evaluateConditionGroup(rule, context); collectedActionIds.push(...nestedResult.actionIds); } } } return { satisfied: isCurrentLayerSatisfied, actionIds: collectedActionIds }; } /** * 评估条件组的逻辑运算 */ evaluateGroupLogic(group, context) { const { operator, rules } = group; switch (operator) { case "and": return rules.every((rule) => this.evaluateRule(rule, context)); case "or": return rules.some((rule) => this.evaluateRule(rule, context)); case "not": if (rules.length === 0) return false; return !this.evaluateRule(rules[0], context); default: throw new Error(`Unknown operator: ${operator}`); } } /** * 评估单个规则 */ evaluateRule(rule, context) { if (this.isConditionGroup(rule)) { return this.evaluateGroupLogic(rule, context); } const conditionRule = rule; if (conditionRule.type === "code" && conditionRule.code) { return this.evaluateCodeCondition(conditionRule.code, context); } return this.evaluateOperatorCondition(conditionRule, context); } /** * 评估代码模式条件 */ evaluateCodeCondition(code, context) { try { const { entities, attributes, metadata } = context; const evalFunc = new Function( "entities", "attributes", "metadata", `return (${code})` ); const result = evalFunc(entities, attributes, metadata); return Boolean(result); } catch (error) { if (this.options.debug) { console.error("Code evaluation error:", error); } return false; } } /** * 评估运算符模式条件 */ evaluateOperatorCondition(rule, context) { const { field, operator, value } = rule; if (!field || !operator) { return false; } const fieldValue = this.getFieldValue(field, context); const handler = this.operatorHandlers.get(operator); if (handler) { return handler(fieldValue, value, rule); } return this.evaluateBuiltInOperator(fieldValue, operator, value); } /** * 获取字段值 */ getFieldValue(field, context) { const path = field.split("."); let value = context.attributes; for (const key of path) { if (value && typeof value === "object" && key in value) { value = value[key]; } else { return void 0; } } return value; } /** * 评估内置运算符 */ evaluateBuiltInOperator(fieldValue, operator, compareValue) { switch (operator) { case "=": case "==": return fieldValue == compareValue; case "!=": return fieldValue != compareValue; case ">": return fieldValue > compareValue; case ">=": return fieldValue >= compareValue; case "<": return fieldValue < compareValue; case "<=": return fieldValue <= compareValue; case "in": return Array.isArray(compareValue) && compareValue.includes(fieldValue); case "not_in": return Array.isArray(compareValue) && !compareValue.includes(fieldValue); case "contains": if (Array.isArray(fieldValue)) { return fieldValue.includes(compareValue); } if (typeof fieldValue === "string") { return fieldValue.includes(compareValue); } return false; case "not_contains": if (Array.isArray(fieldValue)) { return !fieldValue.includes(compareValue); } if (typeof fieldValue === "string") { return !fieldValue.includes(compareValue); } return true; case "starts_with": return typeof fieldValue === "string" && fieldValue.startsWith(compareValue); case "ends_with": return typeof fieldValue === "string" && fieldValue.endsWith(compareValue); case "regex": return typeof fieldValue === "string" && new RegExp(compareValue).test(fieldValue); case "between": if (!Array.isArray(compareValue) || compareValue.length !== 2) return false; return fieldValue >= compareValue[0] && fieldValue <= compareValue[1]; case "is_null": return fieldValue === null || fieldValue === void 0; case "is_not_null": return fieldValue !== null && fieldValue !== void 0; case "is_empty": if (Array.isArray(fieldValue)) return fieldValue.length === 0; if (typeof fieldValue === "string") return fieldValue.length === 0; if (typeof fieldValue === "object") return Object.keys(fieldValue).length === 0; return !fieldValue; case "is_not_empty": if (Array.isArray(fieldValue)) return fieldValue.length > 0; if (typeof fieldValue === "string") return fieldValue.length > 0; if (typeof fieldValue === "object") return Object.keys(fieldValue).length > 0; return Boolean(fieldValue); case "product_match": return this.evaluateProductMatch(fieldValue, compareValue); case "object_in": return this.evaluateProductMatch(fieldValue, compareValue); default: throw new Error(`Unsupported operator: ${operator}`); } } /** * 根据 actionIds 获取 ActionEffect 对象 */ getActionsByIds(actionIds, actions) { const matchedActions = []; const actionMap = new Map(actions.map((action) => [action.id, action])); for (const id of actionIds) { const action = actionMap.get(id); if (action) { matchedActions.push(action); } else { if (this.options.debug) { console.warn(`Action with id "${id}" not found in actions array`); } } } return matchedActions; } /** * 按 priority 排序(降序) */ sortActionsByPriority(actions) { return [...actions].sort((a, b) => { const priorityA = a.priority ?? 0; const priorityB = b.priority ?? 0; return priorityB - priorityA; }); } /** * 判断是否为条件组 */ isConditionGroup(rule) { return "operator" in rule && "rules" in rule && Array.isArray(rule.rules); } /** * 验证配置 */ validateConfig(config) { if (!config) { throw new Error("Strategy config is required"); } if (!config.metadata || !config.metadata.id) { throw new Error("Strategy metadata.id is required"); } if (!config.conditions) { throw new Error("Strategy conditions is required"); } if (!Array.isArray(config.actions)) { throw new Error("Strategy actions must be an array"); } } /** * 初始化内置运算符处理器 */ initializeBuiltInOperators() { } /** * 评估商品匹配运算符 * * 匹配规则: * - 首先匹配 product_id * - 如果配置的 product_variant_id = 0,只需要 product_id 匹配(表示任意变体) * - 如果配置的 product_variant_id != 0,还需要 product_variant_id 精确匹配 * * @param fieldValue 实际商品 { product_id: number, product_variant_id: number } * @param configValue 配置的商品列表 Array<{ product_id: number, product_variant_id: number }> * @returns 是否匹配 */ evaluateProductMatch(fieldValue, configValue) { if (!Array.isArray(configValue)) { return false; } if (!fieldValue || typeof fieldValue !== "object" || typeof fieldValue.product_id !== "number") { return false; } const actualProductId = fieldValue.product_id; const actualVariantId = fieldValue.product_variant_id ?? 0; return configValue.some((item) => { if (!item || typeof item.product_id !== "number") { return false; } const configProductId = item.product_id; const configVariantId = item.product_variant_id ?? 0; if (configProductId !== actualProductId) { return false; } if (configVariantId === 0) { return true; } return configVariantId === actualVariantId; }); } /** * 注册自定义运算符 */ registerOperator(operator, handler) { this.operatorHandlers.set(operator, handler); } /** * 获取调试信息 */ getDebugInfo() { return { debug: this.options.debug, enableTrace: this.options.enableTrace, registeredOperators: Array.from(this.operatorHandlers.keys()) }; } }; function createStrategyEngine(options) { return new StrategyEngine(options); } function evaluate(config, context) { const engine = new StrategyEngine(); return engine.evaluate(config, context); } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { StrategyEngine, createStrategyEngine, evaluate });