@globalbrain/sefirot 4.48.0 → 4.49.0
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/lib/blocks/lens/Rule.ts
CHANGED
|
@@ -1,19 +1,83 @@
|
|
|
1
1
|
export type Rule =
|
|
2
2
|
| MaxLengthRule
|
|
3
|
+
| MinLengthRule
|
|
4
|
+
| MinValueRule
|
|
5
|
+
| MaxValueRule
|
|
3
6
|
| RequiredRule
|
|
4
7
|
| UniqueRule
|
|
8
|
+
| EmailRule
|
|
9
|
+
| UrlRule
|
|
10
|
+
| DecimalRule
|
|
11
|
+
| DecimalOrHyphenRule
|
|
12
|
+
| PositiveIntegerRule
|
|
13
|
+
| NegativeIntegerRule
|
|
14
|
+
| ZeroOrPositiveIntegerRule
|
|
15
|
+
| ZeroOrNegativeIntegerRule
|
|
16
|
+
| CheckedRule
|
|
5
17
|
| SlackChannelLinkRule
|
|
6
18
|
| SlackChannelNameRule
|
|
7
19
|
| BeforeRule
|
|
8
20
|
| BeforeOrEqualRule
|
|
9
21
|
| AfterRule
|
|
10
22
|
| AfterOrEqualRule
|
|
23
|
+
| EachRule
|
|
11
24
|
|
|
12
25
|
export interface MaxLengthRule {
|
|
13
26
|
type: 'max_length'
|
|
14
27
|
length: number
|
|
15
28
|
}
|
|
16
29
|
|
|
30
|
+
export interface MinLengthRule {
|
|
31
|
+
type: 'min_length'
|
|
32
|
+
length: number
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface MinValueRule {
|
|
36
|
+
type: 'min_value'
|
|
37
|
+
value: number
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface MaxValueRule {
|
|
41
|
+
type: 'max_value'
|
|
42
|
+
value: number
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface EmailRule {
|
|
46
|
+
type: 'email'
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface UrlRule {
|
|
50
|
+
type: 'url'
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface DecimalRule {
|
|
54
|
+
type: 'decimal'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface DecimalOrHyphenRule {
|
|
58
|
+
type: 'decimal_or_hyphen'
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface PositiveIntegerRule {
|
|
62
|
+
type: 'positive_integer'
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface NegativeIntegerRule {
|
|
66
|
+
type: 'negative_integer'
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface ZeroOrPositiveIntegerRule {
|
|
70
|
+
type: 'zero_or_positive_integer'
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface ZeroOrNegativeIntegerRule {
|
|
74
|
+
type: 'zero_or_negative_integer'
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface CheckedRule {
|
|
78
|
+
type: 'checked'
|
|
79
|
+
}
|
|
80
|
+
|
|
17
81
|
export interface RequiredRule {
|
|
18
82
|
type: 'required'
|
|
19
83
|
}
|
|
@@ -50,3 +114,12 @@ export interface AfterOrEqualRule {
|
|
|
50
114
|
type: 'after_or_equal'
|
|
51
115
|
date: string
|
|
52
116
|
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Applies the nested `rules` to every element of an array value, mirroring
|
|
120
|
+
* Laravel's `field.*` wildcard on the backend.
|
|
121
|
+
*/
|
|
122
|
+
export interface EachRule {
|
|
123
|
+
type: 'each'
|
|
124
|
+
rules: Rule[]
|
|
125
|
+
}
|
|
@@ -5,30 +5,90 @@ import {
|
|
|
5
5
|
afterOrEqual,
|
|
6
6
|
before,
|
|
7
7
|
beforeOrEqual,
|
|
8
|
+
checked,
|
|
9
|
+
decimal,
|
|
10
|
+
decimalOrHyphen,
|
|
11
|
+
email,
|
|
8
12
|
maxLength,
|
|
13
|
+
maxValue,
|
|
14
|
+
minLength,
|
|
15
|
+
minValue,
|
|
16
|
+
negativeInteger,
|
|
17
|
+
positiveInteger,
|
|
9
18
|
required,
|
|
19
|
+
rule,
|
|
10
20
|
slackChannelLink,
|
|
11
|
-
slackChannelName
|
|
21
|
+
slackChannelName,
|
|
22
|
+
url,
|
|
23
|
+
zeroOrNegativeInteger,
|
|
24
|
+
zeroOrPositiveInteger
|
|
12
25
|
} from '../../../validation/rules'
|
|
13
|
-
import { type Rule } from '../Rule'
|
|
26
|
+
import { type EachRule, type Rule } from '../Rule'
|
|
14
27
|
|
|
15
28
|
/**
|
|
16
29
|
* Maps field rules to vuelidate validation rules.
|
|
17
30
|
*/
|
|
18
31
|
export function map(rules: Rule[]): ValidationArgs {
|
|
19
|
-
|
|
32
|
+
const carry = rules.reduce((carry: ValidationArgs<any>, rule: Rule) => {
|
|
33
|
+
// `each` rules are handled separately below so that multiple of them on the
|
|
34
|
+
// same field compose rather than overwrite.
|
|
35
|
+
if (rule.type === 'each') {
|
|
36
|
+
return carry
|
|
37
|
+
}
|
|
20
38
|
const mapped = mapRule(rule)
|
|
21
39
|
if (mapped) {
|
|
22
40
|
carry[rule.type] = mapped
|
|
23
41
|
}
|
|
24
42
|
return carry
|
|
25
43
|
}, {})
|
|
44
|
+
|
|
45
|
+
// `each` validates every element of an array value rather than the value
|
|
46
|
+
// itself, so it maps to a single per-element validator (see `mapEach`). If a
|
|
47
|
+
// field carries more than one `each` rule, merge their child rules so every
|
|
48
|
+
// wildcard rule runs — the backend accumulates them the same way. A single
|
|
49
|
+
// `each` is the common case.
|
|
50
|
+
const eachRules = rules.filter((rule): rule is EachRule => rule.type === 'each')
|
|
51
|
+
if (eachRules.length) {
|
|
52
|
+
carry.each = mapEach({ type: 'each', rules: eachRules.flatMap((rule) => rule.rules) })
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return carry
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Builds a validator that applies an `each` rule's nested rules to every
|
|
60
|
+
* element of an array value. vuelidate's `forEach` only handles arrays of
|
|
61
|
+
* objects, so for the scalar arrays Lens fields hold (multi-select values,
|
|
62
|
+
* related ids) we run each element through the mapped child validators
|
|
63
|
+
* directly. Mirrors the backend, which expands the same rules onto Laravel's
|
|
64
|
+
* `key.*` wildcard. A non-array value fails; an empty/absent value is left to
|
|
65
|
+
* `required` (the rule is optional on its own).
|
|
66
|
+
*/
|
|
67
|
+
function mapEach(eachRule: EachRule): ValidationRuleWithParams {
|
|
68
|
+
// Map each child rule straight to a validator rather than through the
|
|
69
|
+
// type-keyed `map()` object, so two child rules of the same family are both
|
|
70
|
+
// kept (the backend's `key.*` expansion is additive and de-dupes nothing).
|
|
71
|
+
// Server-only children (e.g. `unique`) map to null and are dropped.
|
|
72
|
+
const childValidators = eachRule.rules
|
|
73
|
+
.map((r) => (r.type === 'each' ? mapEach(r) : mapRule(r)))
|
|
74
|
+
.filter((v): v is ValidationRuleWithParams => v !== null)
|
|
75
|
+
|
|
76
|
+
return rule((value) =>
|
|
77
|
+
Array.isArray(value)
|
|
78
|
+
&& value.every((item) => childValidators.every((v) => v.$validator(item, {}, {}) === true))
|
|
79
|
+
)
|
|
26
80
|
}
|
|
27
81
|
|
|
28
|
-
function mapRule(rule: Rule): ValidationRuleWithParams | null {
|
|
82
|
+
function mapRule(rule: Exclude<Rule, EachRule>): ValidationRuleWithParams | null {
|
|
29
83
|
switch (rule.type) {
|
|
30
84
|
case 'max_length':
|
|
31
85
|
return maxLength(rule.length)
|
|
86
|
+
case 'min_length':
|
|
87
|
+
return minLength(rule.length)
|
|
88
|
+
case 'min_value':
|
|
89
|
+
return minValue(rule.value)
|
|
90
|
+
case 'max_value':
|
|
91
|
+
return maxValue(rule.value)
|
|
32
92
|
case 'required':
|
|
33
93
|
return required()
|
|
34
94
|
case 'unique':
|
|
@@ -36,6 +96,24 @@ function mapRule(rule: Rule): ValidationRuleWithParams | null {
|
|
|
36
96
|
// database). The backend enforces it and returns a 422 with field
|
|
37
97
|
// errors, so there is no client-side equivalent to apply here.
|
|
38
98
|
return null
|
|
99
|
+
case 'email':
|
|
100
|
+
return email()
|
|
101
|
+
case 'url':
|
|
102
|
+
return url()
|
|
103
|
+
case 'decimal':
|
|
104
|
+
return decimal()
|
|
105
|
+
case 'decimal_or_hyphen':
|
|
106
|
+
return decimalOrHyphen()
|
|
107
|
+
case 'positive_integer':
|
|
108
|
+
return positiveInteger()
|
|
109
|
+
case 'negative_integer':
|
|
110
|
+
return negativeInteger()
|
|
111
|
+
case 'zero_or_positive_integer':
|
|
112
|
+
return zeroOrPositiveInteger()
|
|
113
|
+
case 'zero_or_negative_integer':
|
|
114
|
+
return zeroOrNegativeInteger()
|
|
115
|
+
case 'checked':
|
|
116
|
+
return checked()
|
|
39
117
|
case 'slack_channel_link':
|
|
40
118
|
return slackChannelLink()
|
|
41
119
|
case 'slack_channel_name':
|
package/lib/composables/Error.ts
CHANGED
|
@@ -216,8 +216,8 @@ export function useErrorHandler({
|
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
const statusCode = getHttpStatusCode(e)
|
|
219
|
-
if (!statusCode || statusCode
|
|
220
|
-
//
|
|
219
|
+
if (!statusCode || statusCode <= 400 || statusCode >= 500) {
|
|
220
|
+
// ^ report 400 too because it might be caused by a bug in the frontend code
|
|
221
221
|
|
|
222
222
|
const $ = instance && instance.$
|
|
223
223
|
const metadata = $ && {
|