Files
LittleWhiteBox/modules/variables/state2/guard.js

124 lines
3.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { getContext } from '../../../../../../extensions.js';
const LWB_RULES_V2_KEY = 'LWB_RULES_V2';
let rulesTable = {};
export function loadRulesFromMeta() {
try {
const meta = getContext()?.chatMetadata || {};
rulesTable = meta[LWB_RULES_V2_KEY] || {};
} catch {
rulesTable = {};
}
}
export function saveRulesToMeta() {
try {
const meta = getContext()?.chatMetadata || {};
meta[LWB_RULES_V2_KEY] = { ...rulesTable };
getContext()?.saveMetadataDebounced?.();
} catch {}
}
export function getRuleNode(path) {
return rulesTable[path] || null;
}
export function setRule(path, rule) {
rulesTable[path] = { ...(rulesTable[path] || {}), ...rule };
}
export function clearRule(path) {
delete rulesTable[path];
saveRulesToMeta();
}
export function clearAllRules() {
rulesTable = {};
saveRulesToMeta();
}
export function getParentPath(absPath) {
const parts = String(absPath).split('.').filter(Boolean);
if (parts.length <= 1) return '';
return parts.slice(0, -1).join('.');
}
/**
* 验证操作
* @param {string} op - set/inc/push/pop/del
* @param {string} absPath - 规范化路径
* @param {*} payload - set的值 / inc的delta / push的值 / pop的值
* @param {*} currentValue - 当前值
*/
export function validate(op, absPath, payload, currentValue) {
const node = getRuleNode(absPath);
const parentPath = getParentPath(absPath);
const parentNode = parentPath ? getRuleNode(parentPath) : null;
const isNewKey = currentValue === undefined;
// 父层 $lock不允许新增/删除 key
if (parentNode?.lock) {
if (isNewKey && (op === 'set' || op === 'push')) {
return { allow: false, reason: 'parent-locked' };
}
if (op === 'del') {
return { allow: false, reason: 'parent-locked' };
}
}
// 当前 $ro不允许改值
if (node?.ro && (op === 'set' || op === 'inc')) {
return { allow: false, reason: 'ro' };
}
// 当前 $lock不允许改结构
if (node?.lock && (op === 'push' || op === 'pop' || op === 'del')) {
return { allow: false, reason: 'lock' };
}
// set 数值约束
if (op === 'set') {
const num = Number(payload);
if (Number.isFinite(num) && (node?.min !== undefined || node?.max !== undefined)) {
let v = num;
if (node.min !== undefined) v = Math.max(v, node.min);
if (node.max !== undefined) v = Math.min(v, node.max);
return { allow: true, value: v };
}
// enum
if (node?.enum?.length) {
if (!node.enum.includes(String(payload ?? ''))) {
return { allow: false, reason: 'enum' };
}
}
return { allow: true, value: payload };
}
// inc返回最终值
if (op === 'inc') {
const delta = Number(payload);
if (!Number.isFinite(delta)) return { allow: false, reason: 'delta-nan' };
const cur = Number(currentValue) || 0;
let d = delta;
// step 限制
if (node?.step !== undefined && node.step >= 0) {
if (d > node.step) d = node.step;
if (d < -node.step) d = -node.step;
}
let next = cur + d;
// range 限制
if (node?.min !== undefined) next = Math.max(next, node.min);
if (node?.max !== undefined) next = Math.min(next, node.max);
return { allow: true, value: next };
}
return { allow: true, value: payload };
}