@sanity/validation 3.14.4 → 6.12.0-next.46
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/LICENSE +1 -1
- package/README.md +29 -0
- package/lib/_internal.d.ts +93 -0
- package/lib/_internal.js +39 -0
- package/lib/_internal.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +2 -1306
- package/lib/validateDocument-C77_Oewa.js +843 -0
- package/lib/validateDocument-C77_Oewa.js.map +1 -0
- package/lib/validateDocument-CBOsd748.d.ts +199 -0
- package/package.json +53 -45
- package/lib/dts/src/index.d.ts +0 -50
- package/lib/index.cjs.mjs +0 -9
- package/lib/index.esm.js +0 -1286
- package/lib/index.esm.js.map +0 -1
- package/lib/index.js.map +0 -1
- package/src/Rule.ts +0 -424
- package/src/ValidationError.ts +0 -32
- package/src/index.ts +0 -9
- package/src/inferFromSchema.ts +0 -19
- package/src/inferFromSchemaType.ts +0 -50
- package/src/util/convertToValidationMarker.ts +0 -84
- package/src/util/deepEquals.ts +0 -77
- package/src/util/escapeRegex.ts +0 -5
- package/src/util/normalizeValidationRules.test.ts +0 -170
- package/src/util/normalizeValidationRules.ts +0 -118
- package/src/util/pathToString.ts +0 -21
- package/src/util/requestIdleCallback.ts +0 -31
- package/src/util/typeString.test.ts +0 -27
- package/src/util/typeString.ts +0 -23
- package/src/validateDocument.test.ts +0 -703
- package/src/validateDocument.ts +0 -240
- package/src/validators/arrayValidator.ts +0 -100
- package/src/validators/booleanValidator.ts +0 -16
- package/src/validators/dateValidator.ts +0 -113
- package/src/validators/genericValidator.ts +0 -117
- package/src/validators/numberValidator.ts +0 -66
- package/src/validators/objectValidator.ts +0 -64
- package/src/validators/slugValidator.ts +0 -117
- package/src/validators/stringValidator.ts +0 -120
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import {NumberSchemaType, SchemaType, StringSchemaType} from '@sanity/types'
|
|
2
|
-
import RuleClass from '../Rule'
|
|
3
|
-
import normalizeValidationRules from './normalizeValidationRules'
|
|
4
|
-
|
|
5
|
-
describe('normalizeValidationRules', () => {
|
|
6
|
-
// see `infer.test.ts` for more related tests.
|
|
7
|
-
// note the Schema.compile runs this function indirectly via `inferFromSchema`
|
|
8
|
-
it('utilizes schema types to infer base rules', () => {
|
|
9
|
-
const coolNumberType: NumberSchemaType = {
|
|
10
|
-
jsonType: 'number',
|
|
11
|
-
name: 'coolNumber',
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const rules = normalizeValidationRules(coolNumberType)
|
|
15
|
-
expect(rules).toHaveLength(1)
|
|
16
|
-
const [rule] = rules
|
|
17
|
-
|
|
18
|
-
expect(rule).toBeInstanceOf(RuleClass)
|
|
19
|
-
expect(rule._rules).toMatchObject([
|
|
20
|
-
{
|
|
21
|
-
constraint: 'Number',
|
|
22
|
-
flag: 'type',
|
|
23
|
-
},
|
|
24
|
-
])
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
it('follows the type chain to determine the base rule', () => {
|
|
28
|
-
const sickDatetime = {
|
|
29
|
-
type: {
|
|
30
|
-
type: {
|
|
31
|
-
jsonType: 'string',
|
|
32
|
-
},
|
|
33
|
-
name: 'datetime',
|
|
34
|
-
},
|
|
35
|
-
name: 'sickDatetime',
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const rules = normalizeValidationRules(sickDatetime as SchemaType)
|
|
39
|
-
expect(rules).toHaveLength(1)
|
|
40
|
-
const [rule] = rules
|
|
41
|
-
|
|
42
|
-
// type chain is applied from inner to outer so the resulting type should be
|
|
43
|
-
// date instead of string
|
|
44
|
-
expect(rule._rules).toMatchObject([
|
|
45
|
-
{
|
|
46
|
-
constraint: 'Date',
|
|
47
|
-
flag: 'type',
|
|
48
|
-
},
|
|
49
|
-
])
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
it('converts a validation function to a rule instance', () => {
|
|
53
|
-
const coolStringType: StringSchemaType = {
|
|
54
|
-
jsonType: 'string',
|
|
55
|
-
name: 'coolString',
|
|
56
|
-
validation: (rule) => rule.uppercase(),
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const rules = normalizeValidationRules(coolStringType)
|
|
60
|
-
expect(rules).toHaveLength(1)
|
|
61
|
-
const [rule] = rules
|
|
62
|
-
|
|
63
|
-
expect(rule).toBeInstanceOf(RuleClass)
|
|
64
|
-
expect(rule._rules).toMatchObject([
|
|
65
|
-
{
|
|
66
|
-
constraint: 'String',
|
|
67
|
-
flag: 'type',
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
constraint: 'uppercase',
|
|
71
|
-
flag: 'stringCasing',
|
|
72
|
-
},
|
|
73
|
-
])
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
it('converts falsy values to an empty array', () => {
|
|
77
|
-
expect(normalizeValidationRules(undefined)).toEqual([])
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
it('converts schema list options with titles to `rule.valid` constraints', () => {
|
|
81
|
-
const stringTypeWithOptions: StringSchemaType = {
|
|
82
|
-
jsonType: 'string',
|
|
83
|
-
name: 'stringTypeWithOptions',
|
|
84
|
-
options: {
|
|
85
|
-
list: [
|
|
86
|
-
{title: 'Blue', value: 'blue'},
|
|
87
|
-
{title: 'Red', value: 'red'},
|
|
88
|
-
],
|
|
89
|
-
},
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const rules = normalizeValidationRules(stringTypeWithOptions)
|
|
93
|
-
expect(rules).toHaveLength(1)
|
|
94
|
-
const [rule] = rules
|
|
95
|
-
|
|
96
|
-
expect(rule).toBeInstanceOf(RuleClass)
|
|
97
|
-
expect(rule._rules).toMatchObject([
|
|
98
|
-
{
|
|
99
|
-
constraint: 'String',
|
|
100
|
-
flag: 'type',
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
constraint: ['blue', 'red'],
|
|
104
|
-
flag: 'valid',
|
|
105
|
-
},
|
|
106
|
-
])
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
it('converts schema list options with strings only to `rule.valid` constraints', () => {
|
|
110
|
-
const stringTypeWithOptions: StringSchemaType = {
|
|
111
|
-
jsonType: 'string',
|
|
112
|
-
name: 'stringTypeWithOptions',
|
|
113
|
-
options: {
|
|
114
|
-
list: ['blue', 'red'],
|
|
115
|
-
},
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const rules = normalizeValidationRules(stringTypeWithOptions)
|
|
119
|
-
expect(rules).toHaveLength(1)
|
|
120
|
-
const [rule] = rules
|
|
121
|
-
|
|
122
|
-
expect(rule).toBeInstanceOf(RuleClass)
|
|
123
|
-
expect(rule._rules).toMatchObject([
|
|
124
|
-
{
|
|
125
|
-
constraint: 'String',
|
|
126
|
-
flag: 'type',
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
constraint: ['blue', 'red'],
|
|
130
|
-
flag: 'valid',
|
|
131
|
-
},
|
|
132
|
-
])
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
it('converts arrays of validation', () => {
|
|
136
|
-
const coolNumberType: NumberSchemaType = {
|
|
137
|
-
jsonType: 'number',
|
|
138
|
-
name: 'coolNumber',
|
|
139
|
-
validation: [(rule) => rule.greaterThan(3), RuleClass.number().lessThan(5)],
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const rules = normalizeValidationRules(coolNumberType)
|
|
143
|
-
expect(rules).toHaveLength(2)
|
|
144
|
-
const [first, second] = rules
|
|
145
|
-
|
|
146
|
-
expect(first).toBeInstanceOf(RuleClass)
|
|
147
|
-
expect(first._rules).toMatchObject([
|
|
148
|
-
{
|
|
149
|
-
constraint: 'Number',
|
|
150
|
-
flag: 'type',
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
constraint: 3,
|
|
154
|
-
flag: 'greaterThan',
|
|
155
|
-
},
|
|
156
|
-
])
|
|
157
|
-
|
|
158
|
-
expect(second).toBeInstanceOf(RuleClass)
|
|
159
|
-
expect(second._rules).toMatchObject([
|
|
160
|
-
{
|
|
161
|
-
constraint: 'Number',
|
|
162
|
-
flag: 'type',
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
constraint: 5,
|
|
166
|
-
flag: 'lessThan',
|
|
167
|
-
},
|
|
168
|
-
])
|
|
169
|
-
})
|
|
170
|
-
})
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import {SchemaType, Rule, RuleTypeConstraint} from '@sanity/types'
|
|
2
|
-
import RuleClass from '../Rule'
|
|
3
|
-
import {slugValidator} from '../validators/slugValidator'
|
|
4
|
-
|
|
5
|
-
const ruleConstraintTypes: {[P in Lowercase<RuleTypeConstraint>]: true} = {
|
|
6
|
-
array: true,
|
|
7
|
-
boolean: true,
|
|
8
|
-
date: true,
|
|
9
|
-
number: true,
|
|
10
|
-
object: true,
|
|
11
|
-
string: true,
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const isRuleConstraint = (typeString: string): typeString is Lowercase<RuleTypeConstraint> =>
|
|
15
|
-
typeString in ruleConstraintTypes
|
|
16
|
-
|
|
17
|
-
function getTypeChain(type: SchemaType | undefined, visited: Set<SchemaType>): SchemaType[] {
|
|
18
|
-
if (!type) return []
|
|
19
|
-
if (visited.has(type)) return []
|
|
20
|
-
|
|
21
|
-
visited.add(type)
|
|
22
|
-
|
|
23
|
-
const next = type.type ? getTypeChain(type.type, visited) : []
|
|
24
|
-
return [...next, type]
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function baseRuleReducer(inputRule: Rule, type: SchemaType) {
|
|
28
|
-
let baseRule = inputRule
|
|
29
|
-
|
|
30
|
-
if (isRuleConstraint(type.jsonType)) {
|
|
31
|
-
baseRule = baseRule.type(type.jsonType)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const typeOptionsList =
|
|
35
|
-
// if type.options is truthy
|
|
36
|
-
type?.options &&
|
|
37
|
-
// and type.options is an object (non-null from the previous)
|
|
38
|
-
typeof type.options === 'object' &&
|
|
39
|
-
// and if `list` is in options
|
|
40
|
-
'list' in type.options &&
|
|
41
|
-
// then finally access the list
|
|
42
|
-
type.options.list
|
|
43
|
-
|
|
44
|
-
if (Array.isArray(typeOptionsList)) {
|
|
45
|
-
baseRule = baseRule.valid(
|
|
46
|
-
typeOptionsList.map((option) => extractValueFromListOption(option, type))
|
|
47
|
-
)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (type.name === 'datetime') return baseRule.type('Date')
|
|
51
|
-
if (type.name === 'date') return baseRule.type('Date')
|
|
52
|
-
if (type.name === 'url') return baseRule.uri()
|
|
53
|
-
if (type.name === 'slug') return baseRule.custom(slugValidator)
|
|
54
|
-
if (type.name === 'reference') return baseRule.reference()
|
|
55
|
-
if (type.name === 'email') return baseRule.email()
|
|
56
|
-
return baseRule
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function hasValueField(typeDef: SchemaType | undefined): boolean {
|
|
60
|
-
if (!typeDef) return false
|
|
61
|
-
if (!('fields' in typeDef) && typeDef.type) return hasValueField(typeDef.type)
|
|
62
|
-
if (!('fields' in typeDef)) return false
|
|
63
|
-
if (!Array.isArray(typeDef.fields)) return false
|
|
64
|
-
return typeDef.fields.some((field) => field.name === 'value')
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function extractValueFromListOption(option: unknown, typeDef: SchemaType): unknown {
|
|
68
|
-
// If you define a `list` option with object items, where the item has a `value` field,
|
|
69
|
-
// we don't want to treat that as the value but rather the surrounding object
|
|
70
|
-
// This differs from the case where you have a title/value pair setup for a string/number, for instance
|
|
71
|
-
if (typeDef.jsonType === 'object' && hasValueField(typeDef)) return option
|
|
72
|
-
|
|
73
|
-
return (option as Record<string, unknown>).value === undefined
|
|
74
|
-
? option
|
|
75
|
-
: (option as Record<string, unknown>).value
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Takes in `SchemaValidationValue` and returns an array of `Rule` instances.
|
|
80
|
-
*/
|
|
81
|
-
export default function normalizeValidationRules(typeDef: SchemaType | undefined): Rule[] {
|
|
82
|
-
if (!typeDef) {
|
|
83
|
-
return []
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const validation = typeDef.validation
|
|
87
|
-
|
|
88
|
-
if (Array.isArray(validation)) {
|
|
89
|
-
return validation.flatMap((i) =>
|
|
90
|
-
normalizeValidationRules({
|
|
91
|
-
...typeDef,
|
|
92
|
-
validation: i,
|
|
93
|
-
})
|
|
94
|
-
)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (validation instanceof RuleClass) {
|
|
98
|
-
return [validation]
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const baseRule =
|
|
102
|
-
// using an object + Object.values to de-dupe the type chain by type name
|
|
103
|
-
Object.values(
|
|
104
|
-
getTypeChain(typeDef, new Set()).reduce<Record<string, SchemaType>>((acc, type) => {
|
|
105
|
-
acc[type.name] = type
|
|
106
|
-
return acc
|
|
107
|
-
}, {})
|
|
108
|
-
).reduce(baseRuleReducer, new RuleClass(typeDef))
|
|
109
|
-
|
|
110
|
-
if (!validation) {
|
|
111
|
-
return [baseRule]
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return normalizeValidationRules({
|
|
115
|
-
...typeDef,
|
|
116
|
-
validation: validation(baseRule),
|
|
117
|
-
})
|
|
118
|
-
}
|
package/src/util/pathToString.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import {Path, isKeyedObject} from '@sanity/types'
|
|
2
|
-
|
|
3
|
-
export default function pathToString(path: Path | undefined = []): string {
|
|
4
|
-
return path.reduce<string>((target, segment, i) => {
|
|
5
|
-
const segmentType = typeof segment
|
|
6
|
-
if (segmentType === 'number') {
|
|
7
|
-
return `${target}[${segment}]`
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
if (segmentType === 'string') {
|
|
11
|
-
const separator = i === 0 ? '' : '.'
|
|
12
|
-
return `${target}${separator}${segment}`
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (isKeyedObject(segment)) {
|
|
16
|
-
return `${target}[_key=="${segment._key}"]`
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
throw new Error(`Unsupported path segment "${segment}"`)
|
|
20
|
-
}, '')
|
|
21
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Simple requestIdleCallback polyfill
|
|
3
|
-
* Can be removed when all browsers support requestIdleCallback: https://caniuse.com/requestidlecallback
|
|
4
|
-
* @param callback -
|
|
5
|
-
* @param options -
|
|
6
|
-
*/
|
|
7
|
-
const requestIdleCallbackShim: typeof window.requestIdleCallback = function requestIdleCallbackShim(
|
|
8
|
-
callback,
|
|
9
|
-
options?
|
|
10
|
-
): number {
|
|
11
|
-
const start = Date.now()
|
|
12
|
-
return window.setTimeout(() => {
|
|
13
|
-
callback({
|
|
14
|
-
didTimeout: false,
|
|
15
|
-
timeRemaining() {
|
|
16
|
-
return Math.max(0, Date.now() - start)
|
|
17
|
-
},
|
|
18
|
-
})
|
|
19
|
-
}, 0)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const cancelIdleCallbackShim: typeof window.cancelIdleCallback = function cancelIdleCallbackShim(
|
|
23
|
-
handle: number
|
|
24
|
-
): void {
|
|
25
|
-
return window.clearTimeout(handle)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const win = typeof window === 'undefined' ? undefined : window
|
|
29
|
-
|
|
30
|
-
export const requestIdleCallback = win?.requestIdleCallback || requestIdleCallbackShim
|
|
31
|
-
export const cancelIdleCallback = win?.cancelIdleCallback || cancelIdleCallbackShim
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import typeString from './typeString'
|
|
2
|
-
|
|
3
|
-
describe('typeString', () => {
|
|
4
|
-
it('returns the a type string of built in types', () => {
|
|
5
|
-
expect(typeString({})).toBe('Object')
|
|
6
|
-
expect(
|
|
7
|
-
typeString(function () {
|
|
8
|
-
// intentionally blank
|
|
9
|
-
})
|
|
10
|
-
).toBe('Function')
|
|
11
|
-
expect(typeString(['hey'])).toBe('Array')
|
|
12
|
-
expect(typeString('some string')).toBe('String')
|
|
13
|
-
expect(typeString(false)).toBe('Boolean')
|
|
14
|
-
expect(typeString(5)).toBe('Number')
|
|
15
|
-
expect(typeString(new Date())).toBe('Date')
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
it('returns a type string string using the constructor', () => {
|
|
19
|
-
class ExampleClass {}
|
|
20
|
-
expect(typeString(new ExampleClass())).toBe('ExampleClass')
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
it('returns a type string for null or undefined', () => {
|
|
24
|
-
expect(typeString(null)).toBe('null')
|
|
25
|
-
expect(typeString(undefined)).toBe('undefined')
|
|
26
|
-
})
|
|
27
|
-
})
|
package/src/util/typeString.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
// this file was adapted from a previous dependency `type-of-is`
|
|
2
|
-
// https://github.com/stephenhandley/type-of-is/blob/7138a7e79f5af7c286bf8123f60843a91aaebf38/index.js
|
|
3
|
-
const _toString = {}.toString
|
|
4
|
-
|
|
5
|
-
const builtIns = [Object, Function, Array, String, Boolean, Number, Date, RegExp, Error]
|
|
6
|
-
|
|
7
|
-
function isBuiltIn(_constructor: unknown) {
|
|
8
|
-
for (let i = 0; i < builtIns.length; i++) {
|
|
9
|
-
if (builtIns[i] === _constructor) return true
|
|
10
|
-
}
|
|
11
|
-
return false
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export default function typeString(obj: unknown): string {
|
|
15
|
-
// [object Blah] -> Blah
|
|
16
|
-
const stringType = _toString.call(obj).slice(8, -1)
|
|
17
|
-
if (obj === null || obj === undefined) return stringType.toLowerCase()
|
|
18
|
-
|
|
19
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
20
|
-
const constructorType = (obj as object).constructor
|
|
21
|
-
if (constructorType && !isBuiltIn(constructorType)) return constructorType.name
|
|
22
|
-
return stringType
|
|
23
|
-
}
|