@regle/core 1.13.0 → 1.14.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 +612 -280
- package/dist/regle-core.js +377 -104
- package/dist/regle-core.min.js +1 -1
- package/package.json +1 -1
package/dist/regle-core.js
CHANGED
|
@@ -9,12 +9,34 @@ function isFile(value) {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
12
|
+
* Checks if a value is empty in any way (including arrays and objects).
|
|
13
|
+
* This is the inverse of `isFilled`.
|
|
13
14
|
*
|
|
14
|
-
* isEmpty also acts as a type guard.
|
|
15
|
+
* `isEmpty` also acts as a type guard.
|
|
15
16
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
17
|
+
* By default, it considers an empty array as `true`. You can override this behavior with `considerEmptyArrayInvalid`.
|
|
18
|
+
*
|
|
19
|
+
* @param value - The target value to check
|
|
20
|
+
* @param considerEmptyArrayInvalid - When `false`, empty arrays are not considered empty (default: `true`)
|
|
21
|
+
* @returns `true` if the value is empty, `false` otherwise
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* import { createRule, type Maybe } from '@regle/core';
|
|
26
|
+
* import { isEmpty } from '@regle/rules';
|
|
27
|
+
*
|
|
28
|
+
* const rule = createRule({
|
|
29
|
+
* validator(value: Maybe<string>) {
|
|
30
|
+
* if (isEmpty(value)) {
|
|
31
|
+
* return true;
|
|
32
|
+
* }
|
|
33
|
+
* return check(value);
|
|
34
|
+
* },
|
|
35
|
+
* message: 'Error'
|
|
36
|
+
* })
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @see {@link https://reglejs.dev/core-concepts/rules/validations-helpers#isempty Documentation}
|
|
18
40
|
*/
|
|
19
41
|
function isEmpty(value, considerEmptyArrayInvalid = true) {
|
|
20
42
|
if (value === void 0 || value === null) return true;
|
|
@@ -153,7 +175,21 @@ function isConstructor(value) {
|
|
|
153
175
|
}
|
|
154
176
|
|
|
155
177
|
/**
|
|
156
|
-
*
|
|
178
|
+
* Coerces any string, number, or Date value into a `Date` using the `Date` constructor.
|
|
179
|
+
*
|
|
180
|
+
* @param argument - The value to convert to a Date
|
|
181
|
+
* @returns A new Date object (may be invalid if input cannot be parsed)
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```ts
|
|
185
|
+
* import { toDate } from '@regle/rules';
|
|
186
|
+
*
|
|
187
|
+
* const date1 = toDate('2024-01-15'); // Date object
|
|
188
|
+
* const date2 = toDate(1705276800000); // Date from timestamp
|
|
189
|
+
* const date3 = toDate(new Date()); // Clone of Date
|
|
190
|
+
* ```
|
|
191
|
+
*
|
|
192
|
+
* @see {@link https://reglejs.dev/core-concepts/rules/validations-helpers#todate Documentation}
|
|
157
193
|
*/
|
|
158
194
|
function toDate(argument) {
|
|
159
195
|
const argStr = Object.prototype.toString.call(argument);
|
|
@@ -282,20 +318,6 @@ const InternalRuleType = {
|
|
|
282
318
|
Async: "__async"
|
|
283
319
|
};
|
|
284
320
|
|
|
285
|
-
function mergeBooleanGroupProperties(entries, property) {
|
|
286
|
-
return entries.some((entry) => {
|
|
287
|
-
if (!property) return false;
|
|
288
|
-
return entry?.[property];
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
function mergeArrayGroupProperties(entries, property) {
|
|
292
|
-
if (!property) return [];
|
|
293
|
-
return entries.reduce((all, entry) => {
|
|
294
|
-
const fetchedProperty = entry?.[property] || [];
|
|
295
|
-
return all.concat(fetchedProperty);
|
|
296
|
-
}, []);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
321
|
/**
|
|
300
322
|
* Returns a clean list of parameters
|
|
301
323
|
* Removing Ref and executing function to return the unwrapped value
|
|
@@ -384,35 +406,57 @@ function defineRuleProcessors(definition, ...params) {
|
|
|
384
406
|
}
|
|
385
407
|
|
|
386
408
|
/**
|
|
387
|
-
* Create a typed custom rule that can be used like
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
* It will automatically detect if the rule is async
|
|
391
|
-
*
|
|
409
|
+
* Create a typed custom rule that can be used like built-in rules.
|
|
410
|
+
* The created rule can be declared in global options or used directly.
|
|
392
411
|
*
|
|
393
|
-
*
|
|
412
|
+
* Features:
|
|
413
|
+
* - Automatically detects if the rule is async
|
|
414
|
+
* - Supports parameters for configurable rules
|
|
415
|
+
* - Full TypeScript type inference
|
|
416
|
+
* - Custom metadata support
|
|
394
417
|
*
|
|
395
|
-
* @
|
|
418
|
+
* @param definition - The rule definition object containing:
|
|
419
|
+
* - `validator`: The validation function
|
|
420
|
+
* - `message`: Error message (string or function)
|
|
421
|
+
* - `type`: Optional rule type identifier
|
|
422
|
+
* - `active`: Optional function to conditionally activate the rule
|
|
423
|
+
* - `tooltip`: Optional tooltip message
|
|
396
424
|
*
|
|
397
|
-
* @
|
|
425
|
+
* @returns A rule definition that is callable if it accepts parameters
|
|
398
426
|
*
|
|
427
|
+
* @example
|
|
399
428
|
* ```ts
|
|
400
|
-
*
|
|
401
|
-
* import {isFilled} from '@regle/rules';
|
|
429
|
+
* import { createRule } from '@regle/core';
|
|
430
|
+
* import { isFilled } from '@regle/rules';
|
|
402
431
|
*
|
|
432
|
+
* // Simple rule without params
|
|
403
433
|
* export const isFoo = createRule({
|
|
404
434
|
* validator(value: Maybe<string>) {
|
|
405
|
-
*
|
|
406
|
-
*
|
|
407
|
-
*
|
|
408
|
-
*
|
|
435
|
+
* if (isFilled(value)) {
|
|
436
|
+
* return value === 'foo';
|
|
437
|
+
* }
|
|
438
|
+
* return true;
|
|
409
439
|
* },
|
|
410
440
|
* message: "The value should be 'foo'"
|
|
411
|
-
* })
|
|
441
|
+
* });
|
|
412
442
|
*
|
|
443
|
+
* // Rule with parameters
|
|
444
|
+
* export const minCustom = createRule({
|
|
445
|
+
* validator(value: Maybe<number>, min: number) {
|
|
446
|
+
* if (isFilled(value)) {
|
|
447
|
+
* return value >= min;
|
|
448
|
+
* }
|
|
449
|
+
* return true;
|
|
450
|
+
* },
|
|
451
|
+
* message: ({ $params: [min] }) => `Value must be at least ${min}`
|
|
452
|
+
* });
|
|
453
|
+
*
|
|
454
|
+
* // Usage
|
|
455
|
+
* useRegle({ name: '' }, { name: { isFoo } });
|
|
456
|
+
* useRegle({ count: 0 }, { count: { minCustom: minCustom(5) } });
|
|
413
457
|
* ```
|
|
414
458
|
*
|
|
415
|
-
*
|
|
459
|
+
* @see {@link https://reglejs.dev/core-concepts/rules/reusable-rules Documentation}
|
|
416
460
|
*/
|
|
417
461
|
function createRule(definition) {
|
|
418
462
|
if (typeof definition.validator === "function") {
|
|
@@ -538,6 +582,20 @@ function createGlobalState(stateFactory) {
|
|
|
538
582
|
});
|
|
539
583
|
}
|
|
540
584
|
|
|
585
|
+
function mergeBooleanGroupProperties(entries, property) {
|
|
586
|
+
return entries.some((entry) => {
|
|
587
|
+
if (!property) return false;
|
|
588
|
+
return entry?.[property];
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
function mergeArrayGroupProperties(entries, property) {
|
|
592
|
+
if (!property) return [];
|
|
593
|
+
return entries.reduce((all, entry) => {
|
|
594
|
+
const fetchedProperty = entry?.[property] || [];
|
|
595
|
+
return all.concat(fetchedProperty);
|
|
596
|
+
}, []);
|
|
597
|
+
}
|
|
598
|
+
|
|
541
599
|
/**
|
|
542
600
|
* Inspired by Vuelidate storage
|
|
543
601
|
*/
|
|
@@ -1140,8 +1198,7 @@ function createReactiveFieldStatus({ state, rulesDef, customMessages, path, cach
|
|
|
1140
1198
|
return extractRulesTooltips({ field: { $rules: $rules.value } });
|
|
1141
1199
|
});
|
|
1142
1200
|
const $ready = computed(() => {
|
|
1143
|
-
|
|
1144
|
-
return $anyDirty.value && !($invalid.value || $pending.value);
|
|
1201
|
+
return !($invalid.value || $pending.value);
|
|
1145
1202
|
});
|
|
1146
1203
|
const $pending = computed(() => {
|
|
1147
1204
|
if (triggerPunishment.value || !$rewardEarly$1.value) return Object.entries($rules.value).some(([_, ruleResult]) => {
|
|
@@ -2083,8 +2140,7 @@ function createReactiveNestedStatus({ rulesDef, state, path = "", cachePath, roo
|
|
|
2083
2140
|
return true;
|
|
2084
2141
|
});
|
|
2085
2142
|
const $ready = computed(() => {
|
|
2086
|
-
|
|
2087
|
-
return $anyDirty.value && !($invalid.value || $pending.value);
|
|
2143
|
+
return !($invalid.value || $pending.value);
|
|
2088
2144
|
});
|
|
2089
2145
|
const $localPending = ref(false);
|
|
2090
2146
|
const $pending = computed(() => {
|
|
@@ -2504,6 +2560,7 @@ function useRegleDevtoolsRegistry() {
|
|
|
2504
2560
|
watchers.value.set(id, stopHandle);
|
|
2505
2561
|
}
|
|
2506
2562
|
return {
|
|
2563
|
+
devtoolsApi,
|
|
2507
2564
|
register,
|
|
2508
2565
|
unregister,
|
|
2509
2566
|
getAll,
|
|
@@ -2521,7 +2578,7 @@ const regleDevtoolsRegistry = useRegleDevtoolsRegistry();
|
|
|
2521
2578
|
*/
|
|
2522
2579
|
function registerRegleInstance(r$, options) {
|
|
2523
2580
|
if (typeof window === "undefined") return;
|
|
2524
|
-
if (!inject(regleSymbol) && !regleDevtoolsRegistry.loggedWarning.value) {
|
|
2581
|
+
if (!inject(regleSymbol) && !regleDevtoolsRegistry.loggedWarning.value && !!regleDevtoolsRegistry.devtoolsApi) {
|
|
2525
2582
|
regleDevtoolsRegistry.loggedWarning.value = true;
|
|
2526
2583
|
console.warn(`📏 Regle Devtools are not available. Install Regle plugin in your app to enable them. https://reglejs.dev/introduction/devtools`);
|
|
2527
2584
|
return;
|
|
@@ -2985,7 +3042,7 @@ function filterInspectorTree(nodes, filter) {
|
|
|
2985
3042
|
return filtered;
|
|
2986
3043
|
}
|
|
2987
3044
|
|
|
2988
|
-
var version$1 = "1.
|
|
3045
|
+
var version$1 = "1.14.0-beta.1";
|
|
2989
3046
|
|
|
2990
3047
|
function createDevtools(app) {
|
|
2991
3048
|
setupDevtoolsPlugin({
|
|
@@ -3188,23 +3245,37 @@ function createUseRegleComposable(customRules, options, shortcuts) {
|
|
|
3188
3245
|
return useRegle$1;
|
|
3189
3246
|
}
|
|
3190
3247
|
/**
|
|
3191
|
-
* useRegle serves as the foundation for validation logic.
|
|
3248
|
+
* `useRegle` serves as the foundation for validation logic.
|
|
3249
|
+
* It transforms your data and validation rules into a powerful, reactive validation system.
|
|
3192
3250
|
*
|
|
3193
|
-
*
|
|
3251
|
+
* @param state - Your form data (plain object, ref, reactive object, or structure with nested refs)
|
|
3252
|
+
* @param rules - Validation rules that should align with the structure of your state
|
|
3253
|
+
* @param modifiers - Optional configuration to customize regle behavior
|
|
3254
|
+
* @returns An object containing `r$` - the reactive validation state
|
|
3194
3255
|
*
|
|
3195
|
-
* @
|
|
3196
|
-
* @param rules - These should align with the structure of your state.
|
|
3197
|
-
* @param modifiers - Customize regle behaviour
|
|
3198
|
-
*
|
|
3256
|
+
* @example
|
|
3199
3257
|
* ```ts
|
|
3200
3258
|
* import { useRegle } from '@regle/core';
|
|
3201
|
-
import { required } from '@regle/rules';
|
|
3202
|
-
|
|
3203
|
-
const { r$ } = useRegle(
|
|
3204
|
-
email:
|
|
3205
|
-
|
|
3259
|
+
* import { required, email, minLength } from '@regle/rules';
|
|
3260
|
+
*
|
|
3261
|
+
* const { r$ } = useRegle(
|
|
3262
|
+
* { name: '', email: '' },
|
|
3263
|
+
* {
|
|
3264
|
+
* name: { required, minLength: minLength(2) },
|
|
3265
|
+
* email: { required, email }
|
|
3266
|
+
* }
|
|
3267
|
+
* );
|
|
3268
|
+
*
|
|
3269
|
+
* // Access validation state
|
|
3270
|
+
* r$.$valid // Whether all validations pass
|
|
3271
|
+
* r$.$value // The current form values
|
|
3272
|
+
* r$.name.$errors // Errors for the name field
|
|
3273
|
+
*
|
|
3274
|
+
* // Trigger validation
|
|
3275
|
+
* const result = await r$.$validate();
|
|
3206
3276
|
* ```
|
|
3207
|
-
*
|
|
3277
|
+
*
|
|
3278
|
+
* @see {@link https://reglejs.dev/core-concepts/ Documentation}
|
|
3208
3279
|
*/
|
|
3209
3280
|
const useRegle = createUseRegleComposable();
|
|
3210
3281
|
|
|
@@ -3215,11 +3286,31 @@ function createInferRuleHelper() {
|
|
|
3215
3286
|
return inferRules$1;
|
|
3216
3287
|
}
|
|
3217
3288
|
/**
|
|
3218
|
-
*
|
|
3219
|
-
* It
|
|
3289
|
+
* Type helper to provide autocomplete and type-checking for your form rules.
|
|
3290
|
+
* It returns the rules without any processing - useful with computed rules.
|
|
3220
3291
|
*
|
|
3221
3292
|
* @param state - The state reference
|
|
3222
3293
|
* @param rules - Your rule tree
|
|
3294
|
+
* @returns The rules object (passthrough)
|
|
3295
|
+
*
|
|
3296
|
+
* @example
|
|
3297
|
+
* ```ts
|
|
3298
|
+
* import { inferRules, useRegle } from '@regle/core';
|
|
3299
|
+
* import { required, minLength } from '@regle/rules';
|
|
3300
|
+
*
|
|
3301
|
+
* const state = ref({ name: '' });
|
|
3302
|
+
*
|
|
3303
|
+
* // inferRules preserves TypeScript autocompletion
|
|
3304
|
+
* const rules = computed(() => {
|
|
3305
|
+
* return inferRules(state, {
|
|
3306
|
+
* name: { required, minLength: minLength(2) }
|
|
3307
|
+
* })
|
|
3308
|
+
* });
|
|
3309
|
+
*
|
|
3310
|
+
* const { r$ } = useRegle(state, rules);
|
|
3311
|
+
* ```
|
|
3312
|
+
*
|
|
3313
|
+
* @see {@link https://reglejs.dev/core-concepts/#dynamic-rules-object Documentation}
|
|
3223
3314
|
*/
|
|
3224
3315
|
const inferRules = createInferRuleHelper();
|
|
3225
3316
|
|
|
@@ -3256,21 +3347,34 @@ function createUseRulesComposable(customRules, options, shortcuts) {
|
|
|
3256
3347
|
return useRules$1;
|
|
3257
3348
|
}
|
|
3258
3349
|
/**
|
|
3259
|
-
* useRules is a
|
|
3350
|
+
* `useRules` is a variant of `useRegle` that doesn't require you to provide initial state.
|
|
3351
|
+
* It creates an empty state based on your rules structure and implements the Standard Schema spec.
|
|
3260
3352
|
*
|
|
3261
|
-
*
|
|
3353
|
+
* This is useful when you want to define validation rules first and infer the state type from them.
|
|
3262
3354
|
*
|
|
3263
|
-
* @param rules - Your rules object
|
|
3264
|
-
* @param modifiers -
|
|
3265
|
-
*
|
|
3355
|
+
* @param rules - Your validation rules object
|
|
3356
|
+
* @param modifiers - Optional configuration to customize regle behavior
|
|
3357
|
+
* @returns The reactive validation state (implements StandardSchemaV1)
|
|
3358
|
+
*
|
|
3359
|
+
* @example
|
|
3266
3360
|
* ```ts
|
|
3267
|
-
* import { useRules } from '@regle/core';
|
|
3268
|
-
import { required } from '@regle/rules';
|
|
3269
|
-
|
|
3270
|
-
const
|
|
3271
|
-
|
|
3272
|
-
}
|
|
3361
|
+
* import { useRules, type InferInput } from '@regle/core';
|
|
3362
|
+
* import { required, string, email } from '@regle/rules';
|
|
3363
|
+
*
|
|
3364
|
+
* const r$ = useRules({
|
|
3365
|
+
* name: { required, string },
|
|
3366
|
+
* email: { required, email }
|
|
3367
|
+
* });
|
|
3368
|
+
*
|
|
3369
|
+
* // State is automatically created and typed
|
|
3370
|
+
* r$.$value.name // string | null
|
|
3371
|
+
* r$.$value.email // string | null
|
|
3372
|
+
*
|
|
3373
|
+
* // Can be used with Standard Schema compatible libraries
|
|
3374
|
+
* const result = await r$['~standard'].validate({ name: '', email: '' });
|
|
3273
3375
|
* ```
|
|
3376
|
+
*
|
|
3377
|
+
* @see {@link https://reglejs.dev/common-usage/standard-schema#userules Documentation}
|
|
3274
3378
|
*/
|
|
3275
3379
|
const useRules = createUseRulesComposable();
|
|
3276
3380
|
|
|
@@ -3304,16 +3408,43 @@ function applyMarkStatic(value) {
|
|
|
3304
3408
|
}
|
|
3305
3409
|
|
|
3306
3410
|
/**
|
|
3307
|
-
* Define a global
|
|
3411
|
+
* Define a global Regle configuration to customize the validation behavior across your application.
|
|
3412
|
+
*
|
|
3413
|
+
* Features:
|
|
3308
3414
|
* - Customize built-in rules messages
|
|
3309
|
-
* - Add your custom rules
|
|
3310
|
-
* - Define global modifiers
|
|
3311
|
-
* - Define shortcuts
|
|
3415
|
+
* - Add your custom rules with full type inference
|
|
3416
|
+
* - Define global modifiers (lazy, rewardEarly, etc.)
|
|
3417
|
+
* - Define shortcuts for common validation patterns
|
|
3418
|
+
*
|
|
3419
|
+
* @param options - Configuration options
|
|
3420
|
+
* @param options.rules - Factory function returning custom rules
|
|
3421
|
+
* @param options.modifiers - Global behavior modifiers
|
|
3422
|
+
* @param options.shortcuts - Reusable validation shortcuts
|
|
3423
|
+
* @returns Object containing typed `useRegle`, `inferRules`, and `useRules` functions
|
|
3424
|
+
*
|
|
3425
|
+
* @example
|
|
3426
|
+
* ```ts
|
|
3427
|
+
* import { defineRegleConfig } from '@regle/core';
|
|
3428
|
+
* import { required, withMessage } from '@regle/rules';
|
|
3312
3429
|
*
|
|
3313
|
-
*
|
|
3430
|
+
* export const { useRegle, inferRules, useRules } = defineRegleConfig({
|
|
3431
|
+
* rules: () => ({
|
|
3432
|
+
* // Override default required message
|
|
3433
|
+
* required: withMessage(required, 'This field cannot be empty'),
|
|
3434
|
+
* // Add custom rule
|
|
3435
|
+
* myCustomRule: createRule({
|
|
3436
|
+
* validator: (value) => value === 'valid',
|
|
3437
|
+
* message: 'Invalid value'
|
|
3438
|
+
* })
|
|
3439
|
+
* }),
|
|
3440
|
+
* modifiers: {
|
|
3441
|
+
* lazy: true,
|
|
3442
|
+
* rewardEarly: true
|
|
3443
|
+
* }
|
|
3444
|
+
* });
|
|
3445
|
+
* ```
|
|
3314
3446
|
*
|
|
3315
|
-
*
|
|
3316
|
-
* - an `inferRules` helper that can typecheck your custom rules
|
|
3447
|
+
* @see {@link https://reglejs.dev/advanced-usage/global-config Documentation}
|
|
3317
3448
|
*/
|
|
3318
3449
|
function defineRegleConfig({ rules, modifiers, shortcuts }) {
|
|
3319
3450
|
const useRegle$1 = createUseRegleComposable(rules, modifiers, shortcuts);
|
|
@@ -3335,12 +3466,31 @@ function defineRegleConfig({ rules, modifiers, shortcuts }) {
|
|
|
3335
3466
|
};
|
|
3336
3467
|
}
|
|
3337
3468
|
/**
|
|
3338
|
-
* Extend an already created custom `useRegle`
|
|
3469
|
+
* Extend an already created custom `useRegle` configuration with additional rules, modifiers, or shortcuts.
|
|
3339
3470
|
*
|
|
3340
|
-
*
|
|
3471
|
+
* @param regle - The existing useRegle function to extend
|
|
3472
|
+
* @param options - Additional configuration to merge
|
|
3473
|
+
* @param options.rules - Additional custom rules
|
|
3474
|
+
* @param options.modifiers - Additional modifiers to merge
|
|
3475
|
+
* @param options.shortcuts - Additional shortcuts to merge
|
|
3476
|
+
* @returns Object containing the extended `useRegle` and `inferRules` functions
|
|
3341
3477
|
*
|
|
3342
|
-
*
|
|
3343
|
-
*
|
|
3478
|
+
* @example
|
|
3479
|
+
* ```ts
|
|
3480
|
+
* import { extendRegleConfig } from '@regle/core';
|
|
3481
|
+
* import { baseUseRegle } from './base-config';
|
|
3482
|
+
*
|
|
3483
|
+
* export const { useRegle, inferRules } = extendRegleConfig(baseUseRegle, {
|
|
3484
|
+
* rules: () => ({
|
|
3485
|
+
* additionalRule: myNewRule
|
|
3486
|
+
* }),
|
|
3487
|
+
* modifiers: {
|
|
3488
|
+
* rewardEarly: true
|
|
3489
|
+
* }
|
|
3490
|
+
* });
|
|
3491
|
+
* ```
|
|
3492
|
+
*
|
|
3493
|
+
* @see {@link https://reglejs.dev/advanced-usage/global-config Documentation}
|
|
3344
3494
|
*/
|
|
3345
3495
|
function extendRegleConfig(regle, { rules, modifiers, shortcuts }) {
|
|
3346
3496
|
const rootConfig = regle.__config ?? {};
|
|
@@ -3362,6 +3512,44 @@ function extendRegleConfig(regle, { rules, modifiers, shortcuts }) {
|
|
|
3362
3512
|
};
|
|
3363
3513
|
}
|
|
3364
3514
|
|
|
3515
|
+
/**
|
|
3516
|
+
* Merge multiple Regle instances into a single validation state.
|
|
3517
|
+
* Useful for combining multiple forms or validation scopes.
|
|
3518
|
+
*
|
|
3519
|
+
* @param regles - An object containing named Regle instances to merge
|
|
3520
|
+
* @param _scoped - Internal flag for scoped validation (default: false)
|
|
3521
|
+
* @returns A merged validation state with all instances' properties combined
|
|
3522
|
+
*
|
|
3523
|
+
* @example
|
|
3524
|
+
* ```ts
|
|
3525
|
+
* import { useRegle, mergeRegles } from '@regle/core';
|
|
3526
|
+
* import { required } from '@regle/rules';
|
|
3527
|
+
*
|
|
3528
|
+
* // Create separate validation instances
|
|
3529
|
+
* const { r$: personalInfo } = useRegle(
|
|
3530
|
+
* { name: '', email: '' },
|
|
3531
|
+
* { name: { required }, email: { required } }
|
|
3532
|
+
* );
|
|
3533
|
+
*
|
|
3534
|
+
* const { r$: address } = useRegle(
|
|
3535
|
+
* { street: '', city: '' },
|
|
3536
|
+
* { street: { required }, city: { required } }
|
|
3537
|
+
* );
|
|
3538
|
+
*
|
|
3539
|
+
* // Merge them together
|
|
3540
|
+
* const merged$ = mergeRegles({
|
|
3541
|
+
* personalInfo,
|
|
3542
|
+
* address
|
|
3543
|
+
* });
|
|
3544
|
+
*
|
|
3545
|
+
* // Access combined state
|
|
3546
|
+
* merged$.$valid // true when ALL forms are valid
|
|
3547
|
+
* merged$.$errors // { personalInfo: {...}, address: {...} }
|
|
3548
|
+
* await merged$.$validate() // Validates all forms
|
|
3549
|
+
* ```
|
|
3550
|
+
*
|
|
3551
|
+
* @see {@link https://reglejs.dev/advanced-usage/merge-regles Documentation}
|
|
3552
|
+
*/
|
|
3365
3553
|
function mergeRegles(regles, _scoped) {
|
|
3366
3554
|
const scoped = _scoped == null ? false : _scoped;
|
|
3367
3555
|
const $value = computed({
|
|
@@ -3629,6 +3817,35 @@ function createUseScopedRegleComposable(instances, customUseRegle) {
|
|
|
3629
3817
|
return { useScopedRegle: useScopedRegle$1 };
|
|
3630
3818
|
}
|
|
3631
3819
|
|
|
3820
|
+
/**
|
|
3821
|
+
* Create a scoped validation system for collecting and validating multiple form instances.
|
|
3822
|
+
* Useful for dynamic forms, multi-step wizards, or component-based form architectures.
|
|
3823
|
+
*
|
|
3824
|
+
* @param options - Configuration options
|
|
3825
|
+
* @param options.customUseRegle - Custom useRegle instance with your global config
|
|
3826
|
+
* @param options.customStore - External ref to store collected instances
|
|
3827
|
+
* @param options.asRecord - If true, collect instances in a Record (requires `id` param in useScopedRegle)
|
|
3828
|
+
* @returns Object containing `useScopedRegle` and `useCollectScope` functions
|
|
3829
|
+
*
|
|
3830
|
+
* @example
|
|
3831
|
+
* ```ts
|
|
3832
|
+
* // scoped-config.ts
|
|
3833
|
+
* import { createScopedUseRegle } from '@regle/core';
|
|
3834
|
+
*
|
|
3835
|
+
* export const { useScopedRegle, useCollectScope } = createScopedUseRegle();
|
|
3836
|
+
*
|
|
3837
|
+
* // ChildComponent.vue
|
|
3838
|
+
* const { r$ } = useScopedRegle(state, rules, {
|
|
3839
|
+
* namespace: 'myForm'
|
|
3840
|
+
* });
|
|
3841
|
+
*
|
|
3842
|
+
* // ParentComponent.vue
|
|
3843
|
+
* const { r$: collectedR$ } = useCollectScope('myForm');
|
|
3844
|
+
* await collectedR$.$validate(); // Validates all child forms
|
|
3845
|
+
* ```
|
|
3846
|
+
*
|
|
3847
|
+
* @see {@link https://reglejs.dev/advanced-usage/scoped-validation Documentation}
|
|
3848
|
+
*/
|
|
3632
3849
|
function createScopedUseRegle(options) {
|
|
3633
3850
|
const instances = (options?.customStore ? () => {
|
|
3634
3851
|
if (options.customStore) {
|
|
@@ -3649,24 +3866,42 @@ function createScopedUseRegle(options) {
|
|
|
3649
3866
|
const { useCollectScope, useScopedRegle } = createScopedUseRegle();
|
|
3650
3867
|
|
|
3651
3868
|
/**
|
|
3652
|
-
*
|
|
3869
|
+
* Create variant-based validation rules that depend on a discriminant field value.
|
|
3870
|
+
* Useful for union types where different fields are required based on a type discriminant.
|
|
3653
3871
|
*
|
|
3654
|
-
* Autocomplete may not work
|
|
3872
|
+
* Note: Autocomplete may not fully work due to TypeScript limitations.
|
|
3655
3873
|
*
|
|
3874
|
+
* @param root - The reactive state object
|
|
3875
|
+
* @param discriminantKey - The key used to discriminate between variants
|
|
3876
|
+
* @param variants - Array of variant rule definitions using `literal` for type matching
|
|
3877
|
+
* @returns A computed ref containing the currently active variant rules
|
|
3878
|
+
*
|
|
3879
|
+
* @example
|
|
3656
3880
|
* ```ts
|
|
3657
|
-
*
|
|
3658
|
-
*
|
|
3659
|
-
*
|
|
3660
|
-
*
|
|
3661
|
-
*
|
|
3662
|
-
*
|
|
3663
|
-
*
|
|
3664
|
-
*
|
|
3665
|
-
*
|
|
3666
|
-
*
|
|
3667
|
-
*
|
|
3668
|
-
*
|
|
3881
|
+
* import { useRegle, createVariant } from '@regle/core';
|
|
3882
|
+
* import { required, email, literal } from '@regle/rules';
|
|
3883
|
+
*
|
|
3884
|
+
* const state = ref({
|
|
3885
|
+
* type: 'EMAIL' as 'EMAIL' | 'GITHUB',
|
|
3886
|
+
* email: '',
|
|
3887
|
+
* username: ''
|
|
3888
|
+
* });
|
|
3889
|
+
*
|
|
3890
|
+
* // ⚠️ Use getter syntax for your rules
|
|
3891
|
+
* const { r$ } = useRegle(state, () => {
|
|
3892
|
+
* const variant = createVariant(state, 'type', [
|
|
3893
|
+
* { type: { literal: literal('EMAIL') }, email: { required, email } },
|
|
3894
|
+
* { type: { literal: literal('GITHUB') }, username: { required } },
|
|
3895
|
+
* { type: { required } }, // Default case
|
|
3896
|
+
* ]);
|
|
3897
|
+
*
|
|
3898
|
+
* return {
|
|
3899
|
+
* ...variant.value,
|
|
3900
|
+
* };
|
|
3901
|
+
* });
|
|
3669
3902
|
* ```
|
|
3903
|
+
*
|
|
3904
|
+
* @see {@link https://reglejs.dev/advanced-usage/variants Documentation}
|
|
3670
3905
|
*/
|
|
3671
3906
|
function createVariant(root, discriminantKey, variants) {
|
|
3672
3907
|
const watchableRoot = computed(() => toValue(root)[discriminantKey]);
|
|
@@ -3686,13 +3921,25 @@ function createVariant(root, discriminantKey, variants) {
|
|
|
3686
3921
|
});
|
|
3687
3922
|
}
|
|
3688
3923
|
/**
|
|
3689
|
-
*
|
|
3924
|
+
* Type guard to narrow a variant field to a specific discriminated value.
|
|
3925
|
+
* Enables type-safe access to variant-specific fields.
|
|
3690
3926
|
*
|
|
3927
|
+
* @param root - The Regle status object
|
|
3928
|
+
* @param discriminantKey - The key used to discriminate between variants
|
|
3929
|
+
* @param discriminantValue - The specific value to narrow to
|
|
3930
|
+
* @returns `true` if the discriminant matches, with TypeScript narrowing the type
|
|
3931
|
+
*
|
|
3932
|
+
* @example
|
|
3691
3933
|
* ```ts
|
|
3934
|
+
* import { narrowVariant } from '@regle/core';
|
|
3935
|
+
*
|
|
3692
3936
|
* if (narrowVariant(r$, 'type', 'EMAIL')) {
|
|
3693
|
-
*
|
|
3937
|
+
* // TypeScript knows r$.email exists here
|
|
3938
|
+
* r$.email.$value = 'user@example.com';
|
|
3694
3939
|
* }
|
|
3695
3940
|
* ```
|
|
3941
|
+
*
|
|
3942
|
+
* @see {@link https://reglejs.dev/advanced-usage/variants Documentation}
|
|
3696
3943
|
*/
|
|
3697
3944
|
function narrowVariant(root, discriminantKey, discriminantValue) {
|
|
3698
3945
|
return !!root && isObject(root[discriminantKey]) && "$value" in root[discriminantKey] && root[discriminantKey]?.$value === discriminantValue;
|
|
@@ -3712,31 +3959,57 @@ function variantToRef(root, discriminantKey, discriminantValue, _options) {
|
|
|
3712
3959
|
}
|
|
3713
3960
|
|
|
3714
3961
|
/**
|
|
3715
|
-
* Helper method to wrap
|
|
3962
|
+
* Helper method to wrap a raw rules object with type inference.
|
|
3963
|
+
* Provides autocomplete and type-checking without processing.
|
|
3716
3964
|
*
|
|
3717
|
-
*
|
|
3965
|
+
* @param rules - The rules object to wrap
|
|
3966
|
+
* @returns The same rules object (passthrough)
|
|
3718
3967
|
*
|
|
3968
|
+
* @example
|
|
3719
3969
|
* ```ts
|
|
3720
|
-
*
|
|
3970
|
+
* import { defineRules } from '@regle/core';
|
|
3971
|
+
* import { required, string } from '@regle/rules';
|
|
3972
|
+
*
|
|
3973
|
+
* // defineRules helps catch structure errors
|
|
3974
|
+
* const rules = defineRules({
|
|
3975
|
+
* firstName: { required, string },
|
|
3976
|
+
* lastName: { required, string }
|
|
3977
|
+
* });
|
|
3721
3978
|
* ```
|
|
3979
|
+
*
|
|
3980
|
+
* @see {@link https://reglejs.dev/common-usage/standard-schema Documentation}
|
|
3722
3981
|
*/
|
|
3723
3982
|
function defineRules(rules) {
|
|
3724
3983
|
return rules;
|
|
3725
3984
|
}
|
|
3726
3985
|
/**
|
|
3727
|
-
* Refine a
|
|
3986
|
+
* Refine a rules object to add rules that depend on the state values.
|
|
3987
|
+
* Inspired by Zod's `refine`, this allows writing dynamic rules while maintaining type safety.
|
|
3728
3988
|
*
|
|
3729
|
-
* @
|
|
3989
|
+
* @param rules - The base rules object
|
|
3990
|
+
* @param refinement - A function that receives the typed state and returns additional rules
|
|
3991
|
+
* @returns A function that, given the state ref, returns the merged rules
|
|
3730
3992
|
*
|
|
3993
|
+
* @example
|
|
3731
3994
|
* ```ts
|
|
3995
|
+
* import { refineRules, type InferInput } from '@regle/core';
|
|
3996
|
+
* import { required, string, sameAs } from '@regle/rules';
|
|
3997
|
+
*
|
|
3732
3998
|
* const rules = refineRules({
|
|
3733
|
-
*
|
|
3734
|
-
* }, (state) => {
|
|
3735
|
-
*
|
|
3736
|
-
*
|
|
3737
|
-
*
|
|
3738
|
-
*
|
|
3999
|
+
* password: { required, string },
|
|
4000
|
+
* }, (state) => ({
|
|
4001
|
+
* // state is typed based on the base rules
|
|
4002
|
+
* confirmPassword: {
|
|
4003
|
+
* required,
|
|
4004
|
+
* sameAs: sameAs(() => state.value.password)
|
|
4005
|
+
* }
|
|
4006
|
+
* }));
|
|
4007
|
+
*
|
|
4008
|
+
* type State = InferInput<typeof rules>;
|
|
4009
|
+
* // { password: string; confirmPassword: string }
|
|
3739
4010
|
* ```
|
|
4011
|
+
*
|
|
4012
|
+
* @see {@link https://reglejs.dev/common-usage/standard-schema#refinerules Documentation}
|
|
3740
4013
|
*/
|
|
3741
4014
|
function refineRules(rules, refinement) {
|
|
3742
4015
|
return (state) => merge({ ...rules }, refinement(state));
|