@regle/core 1.10.0 → 1.11.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/regle-core.d.ts +3907 -1209
- package/dist/regle-core.js +612 -5
- package/dist/regle-core.min.js +1 -1
- package/package.json +4 -2
package/dist/regle-core.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { computed, effectScope, getCurrentInstance, getCurrentScope, isRef, markRaw, nextTick, onMounted, onScopeDispose, reactive, ref, shallowRef, toRef, toValue, triggerRef, unref, version, watch, watchEffect } from "vue";
|
|
2
|
+
import { setupDevtoolsPlugin } from "@vue/devtools-api";
|
|
2
3
|
|
|
3
4
|
//#region ../shared/utils/isFile.ts
|
|
4
5
|
/**
|
|
@@ -522,9 +523,10 @@ function useStorage() {
|
|
|
522
523
|
if (!storedRuleElement || !newRuleElement || typeof newRuleElement === "function" || typeof storedRuleElement === "function") return false;
|
|
523
524
|
if (typeof newRuleElement === "number") return false;
|
|
524
525
|
else if (typeof newRuleElement === "boolean") return false;
|
|
526
|
+
else if (typeof newRuleElement === "string") return false;
|
|
525
527
|
else if (!newRuleElement._params) return true;
|
|
526
528
|
else return newRuleElement._params?.every((paramKey, index) => {
|
|
527
|
-
if (typeof storedRuleElement === "number" || typeof storedRuleElement === "boolean") return true;
|
|
529
|
+
if (typeof storedRuleElement === "number" || typeof storedRuleElement === "boolean" || typeof storedRuleElement === "string") return true;
|
|
528
530
|
else {
|
|
529
531
|
const storedParams = unwrapRuleParameters(storedRuleElement._params);
|
|
530
532
|
const newParams = unwrapRuleParameters(newRuleElement._params);
|
|
@@ -705,6 +707,9 @@ function isFormRuleDefinition(rule) {
|
|
|
705
707
|
function isNestedRulesStatus(rule) {
|
|
706
708
|
return isObject(rule) && "$fields" in rule;
|
|
707
709
|
}
|
|
710
|
+
function isCollectionRulesStatus(rule) {
|
|
711
|
+
return !!rule && "$each" in rule;
|
|
712
|
+
}
|
|
708
713
|
function isFieldStatus(rule) {
|
|
709
714
|
return !!rule && "$rules" in rule;
|
|
710
715
|
}
|
|
@@ -2421,7 +2426,7 @@ function createRootRegleLogic({ state, rulesFactory, options, globalOptions, cus
|
|
|
2421
2426
|
tryOnScopeDispose(() => {
|
|
2422
2427
|
unwatchRules?.();
|
|
2423
2428
|
});
|
|
2424
|
-
|
|
2429
|
+
const regle = useRootStorage({
|
|
2425
2430
|
scopeRules: watchableRulesGetters,
|
|
2426
2431
|
state,
|
|
2427
2432
|
options: resolvedOptions,
|
|
@@ -2430,6 +2435,83 @@ function createRootRegleLogic({ state, rulesFactory, options, globalOptions, cus
|
|
|
2430
2435
|
customRules,
|
|
2431
2436
|
shortcuts
|
|
2432
2437
|
});
|
|
2438
|
+
if (process.env.NODE_ENV === "development" && regle.regle) registerRegleInstance(regle.regle, { name: toValue(resolvedOptions.id) });
|
|
2439
|
+
return regle;
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2442
|
+
//#endregion
|
|
2443
|
+
//#region src/devtools/registry.ts
|
|
2444
|
+
var RegleDevtoolsRegistry = class {
|
|
2445
|
+
instances = reactive(/* @__PURE__ */ new Map());
|
|
2446
|
+
watchers = /* @__PURE__ */ new Map();
|
|
2447
|
+
idCounter = 0;
|
|
2448
|
+
notifyCallbacks = /* @__PURE__ */ new Set();
|
|
2449
|
+
register(r$, options) {
|
|
2450
|
+
const id = `regle-${++this.idCounter}`;
|
|
2451
|
+
const name = options?.name || `Regle #${this.idCounter}`;
|
|
2452
|
+
this.instances.set(id, {
|
|
2453
|
+
id,
|
|
2454
|
+
name,
|
|
2455
|
+
r$,
|
|
2456
|
+
componentName: options?.componentName ? `<${options.componentName}>` : void 0
|
|
2457
|
+
});
|
|
2458
|
+
this.notifyDevtools();
|
|
2459
|
+
return id;
|
|
2460
|
+
}
|
|
2461
|
+
unregister(id) {
|
|
2462
|
+
this.instances.delete(id);
|
|
2463
|
+
const watcher = this.watchers.get(id);
|
|
2464
|
+
if (watcher) {
|
|
2465
|
+
watcher();
|
|
2466
|
+
this.watchers.delete(id);
|
|
2467
|
+
}
|
|
2468
|
+
this.notifyDevtools();
|
|
2469
|
+
}
|
|
2470
|
+
getAll() {
|
|
2471
|
+
return Array.from(this.instances.values());
|
|
2472
|
+
}
|
|
2473
|
+
get(id) {
|
|
2474
|
+
return this.instances.get(id);
|
|
2475
|
+
}
|
|
2476
|
+
clear() {
|
|
2477
|
+
this.watchers.forEach((stop) => stop());
|
|
2478
|
+
this.watchers.clear();
|
|
2479
|
+
this.instances.clear();
|
|
2480
|
+
this.notifyDevtools();
|
|
2481
|
+
}
|
|
2482
|
+
onInstancesChange(callback) {
|
|
2483
|
+
this.notifyCallbacks.add(callback);
|
|
2484
|
+
return () => {
|
|
2485
|
+
this.notifyCallbacks.delete(callback);
|
|
2486
|
+
};
|
|
2487
|
+
}
|
|
2488
|
+
addWatcher(id, stopHandle) {
|
|
2489
|
+
this.watchers.set(id, stopHandle);
|
|
2490
|
+
}
|
|
2491
|
+
notifyDevtools() {
|
|
2492
|
+
this.notifyCallbacks.forEach((callback) => callback());
|
|
2493
|
+
}
|
|
2494
|
+
};
|
|
2495
|
+
const regleDevtoolsRegistry = new RegleDevtoolsRegistry();
|
|
2496
|
+
function registerRegleInstance(r$, options) {
|
|
2497
|
+
if (typeof window === "undefined") return;
|
|
2498
|
+
const instance = getCurrentInstance();
|
|
2499
|
+
const componentName = instance?.type?.name || instance?.type?.__name;
|
|
2500
|
+
const id = regleDevtoolsRegistry.register(r$, {
|
|
2501
|
+
name: options?.name,
|
|
2502
|
+
componentName
|
|
2503
|
+
});
|
|
2504
|
+
tryOnScopeDispose(() => {
|
|
2505
|
+
regleDevtoolsRegistry.unregister(id);
|
|
2506
|
+
});
|
|
2507
|
+
}
|
|
2508
|
+
function watchRegleInstance(id, r$, onChange) {
|
|
2509
|
+
const stopHandle = watch(() => r$, onChange, {
|
|
2510
|
+
deep: true,
|
|
2511
|
+
flush: "post"
|
|
2512
|
+
});
|
|
2513
|
+
regleDevtoolsRegistry.addWatcher(id, stopHandle);
|
|
2514
|
+
return stopHandle;
|
|
2433
2515
|
}
|
|
2434
2516
|
|
|
2435
2517
|
//#endregion
|
|
@@ -2494,6 +2576,11 @@ const inferRules = createInferRuleHelper();
|
|
|
2494
2576
|
|
|
2495
2577
|
//#endregion
|
|
2496
2578
|
//#region src/core/useRegle/useRules.ts
|
|
2579
|
+
function registerRegleWithDevtools(regle, options) {
|
|
2580
|
+
try {
|
|
2581
|
+
registerRegleInstance(regle, { name: options?.devtoolsName });
|
|
2582
|
+
} catch (e) {}
|
|
2583
|
+
}
|
|
2497
2584
|
function createEmptyRuleState(rules) {
|
|
2498
2585
|
const result = {};
|
|
2499
2586
|
if (Object.entries(rules).some(([_, rule]) => isRuleDef(rule) || typeof rule === "function")) return null;
|
|
@@ -2515,14 +2602,16 @@ function createUseRulesComposable(customRules, options, shortcuts) {
|
|
|
2515
2602
|
};
|
|
2516
2603
|
function useRules$1(rulesFactory, options$1) {
|
|
2517
2604
|
const definedRules = isRef(rulesFactory) ? rulesFactory : typeof rulesFactory === "function" ? void 0 : computed(() => rulesFactory);
|
|
2518
|
-
|
|
2605
|
+
const regle = createRootRegleLogic({
|
|
2519
2606
|
state: ref(createEmptyRuleState(definedRules?.value)),
|
|
2520
2607
|
rulesFactory: definedRules,
|
|
2521
2608
|
options: options$1,
|
|
2522
2609
|
globalOptions,
|
|
2523
2610
|
customRules,
|
|
2524
2611
|
shortcuts
|
|
2525
|
-
})
|
|
2612
|
+
});
|
|
2613
|
+
registerRegleWithDevtools(regle.regle, options$1);
|
|
2614
|
+
return regle.regle;
|
|
2526
2615
|
}
|
|
2527
2616
|
return useRules$1;
|
|
2528
2617
|
}
|
|
@@ -2972,4 +3061,522 @@ function refineRules(rules, refinement) {
|
|
|
2972
3061
|
}
|
|
2973
3062
|
|
|
2974
3063
|
//#endregion
|
|
2975
|
-
|
|
3064
|
+
//#region src/devtools/constants.ts
|
|
3065
|
+
const COLORS = {
|
|
3066
|
+
ERROR: {
|
|
3067
|
+
text: 16777215,
|
|
3068
|
+
bg: 15680580
|
|
3069
|
+
},
|
|
3070
|
+
INVALID: {
|
|
3071
|
+
text: 16777215,
|
|
3072
|
+
bg: 16281969
|
|
3073
|
+
},
|
|
3074
|
+
VALID: {
|
|
3075
|
+
text: 16777215,
|
|
3076
|
+
bg: 1096065
|
|
3077
|
+
},
|
|
3078
|
+
PENDING: {
|
|
3079
|
+
text: 16777215,
|
|
3080
|
+
bg: 16096779
|
|
3081
|
+
},
|
|
3082
|
+
DIRTY: {
|
|
3083
|
+
text: 2042167,
|
|
3084
|
+
bg: 16708551
|
|
3085
|
+
},
|
|
3086
|
+
COMPONENT: {
|
|
3087
|
+
text: 16777215,
|
|
3088
|
+
bg: 6514417
|
|
3089
|
+
}
|
|
3090
|
+
};
|
|
3091
|
+
const PRIORITY_KEYS = {
|
|
3092
|
+
ROOT: [
|
|
3093
|
+
"$invalid",
|
|
3094
|
+
"$dirty",
|
|
3095
|
+
"$error",
|
|
3096
|
+
"$pending",
|
|
3097
|
+
"$valid",
|
|
3098
|
+
"$ready"
|
|
3099
|
+
],
|
|
3100
|
+
FIELD: [
|
|
3101
|
+
"$value",
|
|
3102
|
+
"$invalid",
|
|
3103
|
+
"$dirty",
|
|
3104
|
+
"$error",
|
|
3105
|
+
"$pending",
|
|
3106
|
+
"$errors"
|
|
3107
|
+
]
|
|
3108
|
+
};
|
|
3109
|
+
const INSPECTOR_IDS = {
|
|
3110
|
+
INSPECTOR: "regle-inspector",
|
|
3111
|
+
TIMELINE: "regle-timeline"
|
|
3112
|
+
};
|
|
3113
|
+
|
|
3114
|
+
//#endregion
|
|
3115
|
+
//#region src/devtools/utils.ts
|
|
3116
|
+
function isMethod(value) {
|
|
3117
|
+
return typeof value === "function";
|
|
3118
|
+
}
|
|
3119
|
+
function getPriorityProperties(obj, keys) {
|
|
3120
|
+
return keys.filter((key) => key in obj && !isMethod(obj[key])).map((key) => {
|
|
3121
|
+
let editable = false;
|
|
3122
|
+
if (key === "$value") editable = true;
|
|
3123
|
+
return {
|
|
3124
|
+
key,
|
|
3125
|
+
value: obj[key],
|
|
3126
|
+
editable
|
|
3127
|
+
};
|
|
3128
|
+
});
|
|
3129
|
+
}
|
|
3130
|
+
function getRemainingProperties(obj, excludeKeys) {
|
|
3131
|
+
return Object.entries(obj).filter(([key]) => !excludeKeys.includes(key) && key.startsWith("$") && !isMethod(obj[key])).map(([key, value]) => ({
|
|
3132
|
+
key,
|
|
3133
|
+
value,
|
|
3134
|
+
editable: false
|
|
3135
|
+
}));
|
|
3136
|
+
}
|
|
3137
|
+
function parseFieldNodeId(nodeId) {
|
|
3138
|
+
if (!nodeId.includes(":field:")) return null;
|
|
3139
|
+
const [instanceId, , fieldName] = nodeId.split(":");
|
|
3140
|
+
return {
|
|
3141
|
+
instanceId,
|
|
3142
|
+
fieldName
|
|
3143
|
+
};
|
|
3144
|
+
}
|
|
3145
|
+
function createFieldNodeId(instanceId, fieldName) {
|
|
3146
|
+
return `${instanceId}:field:${fieldName}`;
|
|
3147
|
+
}
|
|
3148
|
+
function parseRuleNodeId(nodeId) {
|
|
3149
|
+
if (!nodeId.includes(":rule:")) return null;
|
|
3150
|
+
const parts = nodeId.split(":rule:");
|
|
3151
|
+
if (parts.length !== 2) return null;
|
|
3152
|
+
const fieldPart = parts[0];
|
|
3153
|
+
const ruleName = parts[1];
|
|
3154
|
+
const fieldInfo = parseFieldNodeId(fieldPart);
|
|
3155
|
+
if (!fieldInfo) return null;
|
|
3156
|
+
return {
|
|
3157
|
+
...fieldInfo,
|
|
3158
|
+
ruleName
|
|
3159
|
+
};
|
|
3160
|
+
}
|
|
3161
|
+
function createRuleNodeId(instanceId, fieldName, ruleName) {
|
|
3162
|
+
return `${createFieldNodeId(instanceId, fieldName)}:rule:${ruleName}`;
|
|
3163
|
+
}
|
|
3164
|
+
|
|
3165
|
+
//#endregion
|
|
3166
|
+
//#region src/devtools/state-builder.ts
|
|
3167
|
+
/**
|
|
3168
|
+
* Build state for a field node
|
|
3169
|
+
*/
|
|
3170
|
+
function buildFieldState(fieldStatus) {
|
|
3171
|
+
const state = {};
|
|
3172
|
+
const priorityProperties = getPriorityProperties(fieldStatus, PRIORITY_KEYS.FIELD);
|
|
3173
|
+
if (priorityProperties.length > 0) state["State"] = priorityProperties;
|
|
3174
|
+
const remainingProperties = getRemainingProperties(fieldStatus, [
|
|
3175
|
+
...PRIORITY_KEYS.FIELD,
|
|
3176
|
+
"$rules",
|
|
3177
|
+
"$fields"
|
|
3178
|
+
]);
|
|
3179
|
+
if (remainingProperties.length > 0) state["Other Properties"] = remainingProperties;
|
|
3180
|
+
return state;
|
|
3181
|
+
}
|
|
3182
|
+
/**
|
|
3183
|
+
* Build state for a rule node
|
|
3184
|
+
*/
|
|
3185
|
+
function buildRuleState(ruleStatus) {
|
|
3186
|
+
const state = {};
|
|
3187
|
+
const ruleKeys = [
|
|
3188
|
+
"$type",
|
|
3189
|
+
"$valid",
|
|
3190
|
+
"$active",
|
|
3191
|
+
"$pending",
|
|
3192
|
+
"$message",
|
|
3193
|
+
"$tooltip"
|
|
3194
|
+
];
|
|
3195
|
+
const priorityProperties = getPriorityProperties(ruleStatus, ruleKeys);
|
|
3196
|
+
if (priorityProperties.length > 0) state["Rule State"] = priorityProperties;
|
|
3197
|
+
if (ruleStatus.$params && Array.isArray(ruleStatus.$params) && ruleStatus.$params.length > 0) state["Parameters"] = [{
|
|
3198
|
+
key: "$params",
|
|
3199
|
+
value: ruleStatus.$params,
|
|
3200
|
+
editable: false
|
|
3201
|
+
}];
|
|
3202
|
+
if (ruleStatus.$metadata !== void 0 && ruleStatus.$metadata !== true && ruleStatus.$metadata !== false) state["Metadata"] = [{
|
|
3203
|
+
key: "$metadata",
|
|
3204
|
+
value: ruleStatus.$metadata,
|
|
3205
|
+
editable: false
|
|
3206
|
+
}];
|
|
3207
|
+
const remainingProperties = getRemainingProperties(ruleStatus, [
|
|
3208
|
+
...ruleKeys,
|
|
3209
|
+
"$params",
|
|
3210
|
+
"$metadata",
|
|
3211
|
+
"$validator",
|
|
3212
|
+
"$parse",
|
|
3213
|
+
"$reset",
|
|
3214
|
+
"$unwatch",
|
|
3215
|
+
"$watch",
|
|
3216
|
+
"$haveAsync",
|
|
3217
|
+
"$validating",
|
|
3218
|
+
"$fieldDirty",
|
|
3219
|
+
"$fieldInvalid",
|
|
3220
|
+
"$fieldPending",
|
|
3221
|
+
"$fieldCorrect",
|
|
3222
|
+
"$fieldError",
|
|
3223
|
+
"$maybePending",
|
|
3224
|
+
"$externalErrors"
|
|
3225
|
+
]);
|
|
3226
|
+
if (remainingProperties.length > 0) state["Other Properties"] = remainingProperties;
|
|
3227
|
+
return state;
|
|
3228
|
+
}
|
|
3229
|
+
function buildRootState(r$) {
|
|
3230
|
+
const state = {};
|
|
3231
|
+
const priorityProperties = getPriorityProperties(r$, PRIORITY_KEYS.ROOT);
|
|
3232
|
+
if (priorityProperties.length > 0) state["State"] = priorityProperties;
|
|
3233
|
+
const remainingProperties = getRemainingProperties(r$, [...PRIORITY_KEYS.ROOT, "$fields"]);
|
|
3234
|
+
if (remainingProperties.length > 0) state["Other Properties"] = remainingProperties;
|
|
3235
|
+
return state;
|
|
3236
|
+
}
|
|
3237
|
+
function resolveFieldByPath(fields, path) {
|
|
3238
|
+
if (!fields || !path) return null;
|
|
3239
|
+
const segments = path.match(/[^.\[\]]+/g);
|
|
3240
|
+
if (!segments) return null;
|
|
3241
|
+
let current = fields;
|
|
3242
|
+
for (const segment of segments) {
|
|
3243
|
+
if (!current) return null;
|
|
3244
|
+
const index = parseInt(segment);
|
|
3245
|
+
if (!isNaN(index)) if (isCollectionRulesStatus(current) && Array.isArray(current.$each)) current = current.$each[index];
|
|
3246
|
+
else return null;
|
|
3247
|
+
else if (isNestedRulesStatus(current) && current.$fields && current.$fields[segment]) current = current.$fields[segment];
|
|
3248
|
+
else if (current[segment]) current = current[segment];
|
|
3249
|
+
else return null;
|
|
3250
|
+
}
|
|
3251
|
+
return current;
|
|
3252
|
+
}
|
|
3253
|
+
function buildInspectorState(nodeId, getInstance) {
|
|
3254
|
+
const ruleInfo = parseRuleNodeId(nodeId);
|
|
3255
|
+
if (ruleInfo) {
|
|
3256
|
+
const { instanceId, fieldName, ruleName } = ruleInfo;
|
|
3257
|
+
const instance$1 = getInstance(instanceId);
|
|
3258
|
+
if (!instance$1 || !instance$1.r$.$fields) return null;
|
|
3259
|
+
const fieldStatus = resolveFieldByPath(instance$1.r$.$fields, fieldName);
|
|
3260
|
+
if (!fieldStatus || !("$rules" in fieldStatus)) return null;
|
|
3261
|
+
const ruleStatus = fieldStatus.$rules[ruleName];
|
|
3262
|
+
if (!ruleStatus) return null;
|
|
3263
|
+
return buildRuleState(ruleStatus);
|
|
3264
|
+
}
|
|
3265
|
+
const fieldInfo = parseFieldNodeId(nodeId);
|
|
3266
|
+
if (fieldInfo) {
|
|
3267
|
+
const { instanceId, fieldName } = fieldInfo;
|
|
3268
|
+
const instance$1 = getInstance(instanceId);
|
|
3269
|
+
if (!instance$1 || !instance$1.r$.$fields) return null;
|
|
3270
|
+
const fieldStatus = resolveFieldByPath(instance$1.r$.$fields, fieldName);
|
|
3271
|
+
if (!fieldStatus) return null;
|
|
3272
|
+
return buildFieldState(fieldStatus);
|
|
3273
|
+
}
|
|
3274
|
+
const instance = getInstance(nodeId);
|
|
3275
|
+
if (!instance) return null;
|
|
3276
|
+
return buildRootState(instance.r$);
|
|
3277
|
+
}
|
|
3278
|
+
|
|
3279
|
+
//#endregion
|
|
3280
|
+
//#region src/devtools/actions.ts
|
|
3281
|
+
function handleValidateAction(nodeId, api) {
|
|
3282
|
+
if (nodeId.includes(":rule:")) return;
|
|
3283
|
+
const fieldInfo = parseFieldNodeId(nodeId);
|
|
3284
|
+
if (fieldInfo) {
|
|
3285
|
+
const { instanceId, fieldName } = fieldInfo;
|
|
3286
|
+
const instance = regleDevtoolsRegistry.get(instanceId);
|
|
3287
|
+
if (instance && instance.r$.$fields) {
|
|
3288
|
+
const fieldStatus = resolveFieldByPath(instance.r$.$fields, fieldName);
|
|
3289
|
+
if (fieldStatus && typeof fieldStatus.$validate === "function") fieldStatus.$validate();
|
|
3290
|
+
}
|
|
3291
|
+
} else {
|
|
3292
|
+
const instance = regleDevtoolsRegistry.get(nodeId);
|
|
3293
|
+
if (instance && typeof instance.r$.$validate === "function") instance.r$.$validate();
|
|
3294
|
+
}
|
|
3295
|
+
emitInspectorState(api);
|
|
3296
|
+
}
|
|
3297
|
+
function handleResetAction(nodeId, api, resetState = false) {
|
|
3298
|
+
const fieldInfo = parseFieldNodeId(nodeId);
|
|
3299
|
+
if (fieldInfo) {
|
|
3300
|
+
const { instanceId, fieldName } = fieldInfo;
|
|
3301
|
+
const instance = regleDevtoolsRegistry.get(instanceId);
|
|
3302
|
+
if (instance && instance.r$.$fields) {
|
|
3303
|
+
const fieldStatus = resolveFieldByPath(instance.r$.$fields, fieldName);
|
|
3304
|
+
if (fieldStatus && typeof fieldStatus.$reset === "function") fieldStatus.$reset({ toInitialState: resetState });
|
|
3305
|
+
}
|
|
3306
|
+
} else {
|
|
3307
|
+
const instance = regleDevtoolsRegistry.get(nodeId);
|
|
3308
|
+
if (instance && typeof instance.r$.$reset === "function") instance.r$.$reset({ toInitialState: resetState });
|
|
3309
|
+
}
|
|
3310
|
+
emitInspectorState(api);
|
|
3311
|
+
}
|
|
3312
|
+
function handleEditInspectorState(payload, api) {
|
|
3313
|
+
const { nodeId, path, state } = payload;
|
|
3314
|
+
if (!path.includes("$value")) return;
|
|
3315
|
+
if (!parseFieldNodeId(nodeId)) return;
|
|
3316
|
+
const [instanceId, _, fieldPath] = nodeId.split(":");
|
|
3317
|
+
const instance = regleDevtoolsRegistry.get(instanceId);
|
|
3318
|
+
if (instance && instance.r$.$fields) {
|
|
3319
|
+
const fieldStatus = resolveFieldByPath(instance.r$.$fields, fieldPath);
|
|
3320
|
+
if (fieldStatus && "$value" in fieldStatus) fieldStatus.$value = state.value;
|
|
3321
|
+
}
|
|
3322
|
+
emitInspectorState(api);
|
|
3323
|
+
}
|
|
3324
|
+
function emitInspectorState(api) {
|
|
3325
|
+
setTimeout(() => {
|
|
3326
|
+
api.sendInspectorState(INSPECTOR_IDS.INSPECTOR);
|
|
3327
|
+
api.sendInspectorTree(INSPECTOR_IDS.INSPECTOR);
|
|
3328
|
+
}, 100);
|
|
3329
|
+
}
|
|
3330
|
+
|
|
3331
|
+
//#endregion
|
|
3332
|
+
//#region src/devtools/tree-builder.ts
|
|
3333
|
+
function buildNodeTags(fieldOrR$, componentName) {
|
|
3334
|
+
const tags = [];
|
|
3335
|
+
if (fieldOrR$.$error) tags.push({
|
|
3336
|
+
label: "error",
|
|
3337
|
+
textColor: COLORS.ERROR.text,
|
|
3338
|
+
backgroundColor: COLORS.ERROR.bg
|
|
3339
|
+
});
|
|
3340
|
+
else if (fieldOrR$.$correct) tags.push({
|
|
3341
|
+
label: "correct",
|
|
3342
|
+
textColor: COLORS.VALID.text,
|
|
3343
|
+
backgroundColor: COLORS.VALID.bg
|
|
3344
|
+
});
|
|
3345
|
+
if (fieldOrR$.$pending) tags.push({
|
|
3346
|
+
label: "pending",
|
|
3347
|
+
textColor: COLORS.PENDING.text,
|
|
3348
|
+
backgroundColor: COLORS.PENDING.bg
|
|
3349
|
+
});
|
|
3350
|
+
if (fieldOrR$.$dirty) tags.push({
|
|
3351
|
+
label: "dirty",
|
|
3352
|
+
textColor: COLORS.DIRTY.text,
|
|
3353
|
+
backgroundColor: COLORS.DIRTY.bg
|
|
3354
|
+
});
|
|
3355
|
+
if (componentName) tags.push({
|
|
3356
|
+
label: componentName,
|
|
3357
|
+
textColor: COLORS.COMPONENT.text,
|
|
3358
|
+
backgroundColor: COLORS.COMPONENT.bg
|
|
3359
|
+
});
|
|
3360
|
+
return tags;
|
|
3361
|
+
}
|
|
3362
|
+
function buildRuleTags(rule) {
|
|
3363
|
+
const tags = [];
|
|
3364
|
+
if (!rule.$active) tags.push({
|
|
3365
|
+
label: "inactive",
|
|
3366
|
+
textColor: 10265519,
|
|
3367
|
+
backgroundColor: 15987958
|
|
3368
|
+
});
|
|
3369
|
+
else if (!rule.$valid) tags.push({
|
|
3370
|
+
label: "invalid",
|
|
3371
|
+
textColor: COLORS.INVALID.text,
|
|
3372
|
+
backgroundColor: COLORS.INVALID.bg
|
|
3373
|
+
});
|
|
3374
|
+
else if (rule.$valid) tags.push({
|
|
3375
|
+
label: "valid",
|
|
3376
|
+
textColor: COLORS.VALID.text,
|
|
3377
|
+
backgroundColor: COLORS.VALID.bg
|
|
3378
|
+
});
|
|
3379
|
+
if (rule.$pending) tags.push({
|
|
3380
|
+
label: "pending",
|
|
3381
|
+
textColor: COLORS.PENDING.text,
|
|
3382
|
+
backgroundColor: COLORS.PENDING.bg
|
|
3383
|
+
});
|
|
3384
|
+
return tags;
|
|
3385
|
+
}
|
|
3386
|
+
function buildRuleNodes(fieldStatus, instanceId, fieldPath) {
|
|
3387
|
+
const children = [];
|
|
3388
|
+
if (!fieldStatus.$rules || typeof fieldStatus.$rules !== "object") return children;
|
|
3389
|
+
Object.entries(fieldStatus.$rules).forEach(([ruleName, ruleStatus]) => {
|
|
3390
|
+
if (ruleStatus && typeof ruleStatus === "object") {
|
|
3391
|
+
const ruleTags = buildRuleTags(ruleStatus);
|
|
3392
|
+
children.push({
|
|
3393
|
+
id: createRuleNodeId(instanceId, fieldPath, ruleName),
|
|
3394
|
+
label: ruleName,
|
|
3395
|
+
tags: ruleTags,
|
|
3396
|
+
children: []
|
|
3397
|
+
});
|
|
3398
|
+
}
|
|
3399
|
+
});
|
|
3400
|
+
return children;
|
|
3401
|
+
}
|
|
3402
|
+
function buildCollectionItemNodes(fieldStatus, instanceId, fieldPath) {
|
|
3403
|
+
const children = [];
|
|
3404
|
+
if (!fieldStatus.$each || !Array.isArray(fieldStatus.$each)) return children;
|
|
3405
|
+
fieldStatus.$each.forEach((item, index) => {
|
|
3406
|
+
if (item && typeof item === "object") {
|
|
3407
|
+
const itemTags = buildNodeTags(item);
|
|
3408
|
+
const itemPath = `${fieldPath}[${index}]`;
|
|
3409
|
+
let itemChildren = [];
|
|
3410
|
+
if (isNestedRulesStatus(item)) itemChildren = buildNestedFieldNodes(item.$fields, instanceId, itemPath);
|
|
3411
|
+
else if (isFieldStatus(item)) itemChildren = buildRuleNodes(item, instanceId, itemPath);
|
|
3412
|
+
children.push({
|
|
3413
|
+
id: createFieldNodeId(instanceId, itemPath),
|
|
3414
|
+
label: `[${index}]`,
|
|
3415
|
+
tags: itemTags,
|
|
3416
|
+
children: itemChildren
|
|
3417
|
+
});
|
|
3418
|
+
}
|
|
3419
|
+
});
|
|
3420
|
+
return children;
|
|
3421
|
+
}
|
|
3422
|
+
function buildNestedFieldNodes(fields, instanceId, parentPath) {
|
|
3423
|
+
const children = [];
|
|
3424
|
+
Object.entries(fields).forEach(([fieldName, fieldStatus]) => {
|
|
3425
|
+
if (fieldStatus && typeof fieldStatus === "object") {
|
|
3426
|
+
const fieldPath = parentPath ? `${parentPath}.${fieldName}` : fieldName;
|
|
3427
|
+
const fieldTags = buildNodeTags(fieldStatus);
|
|
3428
|
+
let fieldChildren = [];
|
|
3429
|
+
if (isCollectionRulesStatus(fieldStatus)) fieldChildren = buildCollectionItemNodes(fieldStatus, instanceId, fieldPath);
|
|
3430
|
+
else if (isNestedRulesStatus(fieldStatus)) fieldChildren = buildNestedFieldNodes(fieldStatus.$fields, instanceId, fieldPath);
|
|
3431
|
+
else if (isFieldStatus(fieldStatus)) fieldChildren = buildRuleNodes(fieldStatus, instanceId, fieldPath);
|
|
3432
|
+
children.push({
|
|
3433
|
+
id: createFieldNodeId(instanceId, fieldPath),
|
|
3434
|
+
label: fieldName,
|
|
3435
|
+
tags: fieldTags,
|
|
3436
|
+
children: fieldChildren
|
|
3437
|
+
});
|
|
3438
|
+
}
|
|
3439
|
+
});
|
|
3440
|
+
return children;
|
|
3441
|
+
}
|
|
3442
|
+
function buildRootChildrenNodes(r$, instanceId) {
|
|
3443
|
+
const children = [];
|
|
3444
|
+
if (isFieldStatus(r$)) return buildRuleNodes(r$, instanceId, "root");
|
|
3445
|
+
if (!r$.$fields || typeof r$.$fields !== "object") return children;
|
|
3446
|
+
Object.entries(r$.$fields).forEach(([fieldName, fieldStatus]) => {
|
|
3447
|
+
if (fieldStatus && typeof fieldStatus === "object") {
|
|
3448
|
+
const fieldTags = buildNodeTags(fieldStatus);
|
|
3449
|
+
let fieldChildren = [];
|
|
3450
|
+
if (isCollectionRulesStatus(fieldStatus)) fieldChildren = buildCollectionItemNodes(fieldStatus, instanceId, fieldName);
|
|
3451
|
+
else if (isNestedRulesStatus(fieldStatus)) fieldChildren = buildNestedFieldNodes(fieldStatus.$fields, instanceId, fieldName);
|
|
3452
|
+
else if (isFieldStatus(fieldStatus)) fieldChildren = buildRuleNodes(fieldStatus, instanceId, fieldName);
|
|
3453
|
+
children.push({
|
|
3454
|
+
id: createFieldNodeId(instanceId, fieldName),
|
|
3455
|
+
label: fieldName,
|
|
3456
|
+
tags: fieldTags,
|
|
3457
|
+
children: fieldChildren
|
|
3458
|
+
});
|
|
3459
|
+
}
|
|
3460
|
+
});
|
|
3461
|
+
return children;
|
|
3462
|
+
}
|
|
3463
|
+
function buildInspectorTree(instances, filter) {
|
|
3464
|
+
const nodes = instances.map((instance) => {
|
|
3465
|
+
const { r$, id, name, componentName } = instance;
|
|
3466
|
+
return {
|
|
3467
|
+
id,
|
|
3468
|
+
label: name,
|
|
3469
|
+
tags: buildNodeTags(r$, componentName),
|
|
3470
|
+
children: buildRootChildrenNodes(r$, id)
|
|
3471
|
+
};
|
|
3472
|
+
});
|
|
3473
|
+
if (!filter || filter.trim() === "") return nodes;
|
|
3474
|
+
return filterInspectorTree(nodes, filter);
|
|
3475
|
+
}
|
|
3476
|
+
function filterInspectorTree(nodes, filter) {
|
|
3477
|
+
const lowerFilter = filter.toLowerCase();
|
|
3478
|
+
const filtered = [];
|
|
3479
|
+
for (const node of nodes) {
|
|
3480
|
+
const labelMatches = node.label.toLowerCase().includes(lowerFilter);
|
|
3481
|
+
const tagMatches = node.tags?.some((tag) => tag.label.toLowerCase().includes(lowerFilter)) ?? false;
|
|
3482
|
+
const filteredChildren = node.children ? filterInspectorTree(node.children, filter) : [];
|
|
3483
|
+
if (labelMatches || tagMatches || filteredChildren.length > 0) filtered.push({
|
|
3484
|
+
...node,
|
|
3485
|
+
children: filteredChildren.length > 0 ? filteredChildren : node.children
|
|
3486
|
+
});
|
|
3487
|
+
}
|
|
3488
|
+
return filtered;
|
|
3489
|
+
}
|
|
3490
|
+
|
|
3491
|
+
//#endregion
|
|
3492
|
+
//#region src/devtools/devtools.ts
|
|
3493
|
+
function createDevtools(app) {
|
|
3494
|
+
setupDevtoolsPlugin({
|
|
3495
|
+
id: "regle-devtools",
|
|
3496
|
+
label: "Regle",
|
|
3497
|
+
logo: "https://reglejs.dev/logo_main.png",
|
|
3498
|
+
packageName: "@regle/core",
|
|
3499
|
+
homepage: "https://reglejs.dev",
|
|
3500
|
+
componentStateTypes: [],
|
|
3501
|
+
app
|
|
3502
|
+
}, (api) => {
|
|
3503
|
+
api.addInspector({
|
|
3504
|
+
id: INSPECTOR_IDS.INSPECTOR,
|
|
3505
|
+
label: "Regle",
|
|
3506
|
+
noSelectionText: "No instance selected",
|
|
3507
|
+
icon: "rule",
|
|
3508
|
+
treeFilterPlaceholder: "Filter",
|
|
3509
|
+
stateFilterPlaceholder: "Filter validation status",
|
|
3510
|
+
nodeActions: [
|
|
3511
|
+
{
|
|
3512
|
+
icon: "check_circle",
|
|
3513
|
+
tooltip: "Validate (with `$validate`)",
|
|
3514
|
+
action: (nodeId) => {
|
|
3515
|
+
handleValidateAction(nodeId, api);
|
|
3516
|
+
}
|
|
3517
|
+
},
|
|
3518
|
+
{
|
|
3519
|
+
icon: "refresh",
|
|
3520
|
+
tooltip: "Reset validation state (with `$reset`)",
|
|
3521
|
+
action: (nodeId) => {
|
|
3522
|
+
handleResetAction(nodeId, api);
|
|
3523
|
+
}
|
|
3524
|
+
},
|
|
3525
|
+
{
|
|
3526
|
+
icon: "restore",
|
|
3527
|
+
tooltip: "Restore to initial state (with `$reset`)",
|
|
3528
|
+
action: (nodeId) => {
|
|
3529
|
+
handleResetAction(nodeId, api, true);
|
|
3530
|
+
}
|
|
3531
|
+
}
|
|
3532
|
+
]
|
|
3533
|
+
});
|
|
3534
|
+
setupInstanceWatchers(api);
|
|
3535
|
+
api.on.getInspectorTree((payload) => {
|
|
3536
|
+
if (payload.inspectorId === INSPECTOR_IDS.INSPECTOR) payload.rootNodes = buildInspectorTree(regleDevtoolsRegistry.getAll(), payload.filter);
|
|
3537
|
+
});
|
|
3538
|
+
api.on.getInspectorState((payload) => {
|
|
3539
|
+
if (payload.inspectorId === INSPECTOR_IDS.INSPECTOR) {
|
|
3540
|
+
const state = buildInspectorState(payload.nodeId, (id) => regleDevtoolsRegistry.get(id));
|
|
3541
|
+
if (state) payload.state = state;
|
|
3542
|
+
}
|
|
3543
|
+
});
|
|
3544
|
+
api.on.editInspectorState((payload) => {
|
|
3545
|
+
if (payload.inspectorId === INSPECTOR_IDS.INSPECTOR) handleEditInspectorState(payload, api);
|
|
3546
|
+
});
|
|
3547
|
+
});
|
|
3548
|
+
}
|
|
3549
|
+
function setupInstanceWatchers(api) {
|
|
3550
|
+
const watchedInstances = /* @__PURE__ */ new Set();
|
|
3551
|
+
const setupWatchers = () => {
|
|
3552
|
+
regleDevtoolsRegistry.getAll().forEach((instance) => {
|
|
3553
|
+
const { r$, id } = instance;
|
|
3554
|
+
if (watchedInstances.has(id)) return;
|
|
3555
|
+
const stopHandle = watchRegleInstance(id, r$, () => {
|
|
3556
|
+
api.sendInspectorState(INSPECTOR_IDS.INSPECTOR);
|
|
3557
|
+
api.sendInspectorTree(INSPECTOR_IDS.INSPECTOR);
|
|
3558
|
+
});
|
|
3559
|
+
regleDevtoolsRegistry.addWatcher(id, stopHandle);
|
|
3560
|
+
watchedInstances.add(id);
|
|
3561
|
+
});
|
|
3562
|
+
};
|
|
3563
|
+
setupWatchers();
|
|
3564
|
+
regleDevtoolsRegistry.onInstancesChange(() => {
|
|
3565
|
+
const currentIds = new Set(regleDevtoolsRegistry.getAll().map((i) => i.id));
|
|
3566
|
+
for (const id of watchedInstances) if (!currentIds.has(id)) watchedInstances.delete(id);
|
|
3567
|
+
api.sendInspectorTree(INSPECTOR_IDS.INSPECTOR);
|
|
3568
|
+
setupWatchers();
|
|
3569
|
+
});
|
|
3570
|
+
}
|
|
3571
|
+
|
|
3572
|
+
//#endregion
|
|
3573
|
+
//#region src/devtools/plugin.ts
|
|
3574
|
+
const __USE_DEVTOOLS__ = process.env.NODE_ENV === "development";
|
|
3575
|
+
const regleSymbol = Symbol("regle");
|
|
3576
|
+
const RegleVuePlugin = { install(app) {
|
|
3577
|
+
app.provide(regleSymbol, true);
|
|
3578
|
+
if (typeof window !== "undefined" && __USE_DEVTOOLS__) createDevtools(app);
|
|
3579
|
+
} };
|
|
3580
|
+
|
|
3581
|
+
//#endregion
|
|
3582
|
+
export { InternalRuleType, RegleVuePlugin, createRule, createScopedUseRegle, createVariant, defineRegleConfig, defineRules, extendRegleConfig, flatErrors, inferRules, mergeRegles, narrowVariant, refineRules, registerRegleInstance, unwrapRuleParameters, useCollectScope, useRegle, useRootStorage, useRules, useScopedRegle, variantToRef };
|