@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.
@@ -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
- return useRootStorage({
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
- return createRootRegleLogic({
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
- }).regle;
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
- export { InternalRuleType, createRule, createScopedUseRegle, createVariant, defineRegleConfig, defineRules, extendRegleConfig, flatErrors, inferRules, mergeRegles, narrowVariant, refineRules, unwrapRuleParameters, useCollectScope, useRegle, useRootStorage, useRules, useScopedRegle, variantToRef };
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 };