sanity-advanced-validators 0.0.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/LICENSE +21 -0
- package/README.md +474 -0
- package/dist/fileExtension.cjs +41 -0
- package/dist/fileExtension.test.cjs +18973 -0
- package/dist/index.cjs +128 -0
- package/dist/index.test.cjs +18932 -0
- package/dist/lib/getPeer.cjs +35 -0
- package/dist/lib/index.cjs +37 -0
- package/dist/maxDepth.cjs +37 -0
- package/dist/maxDepth.test.cjs +18971 -0
- package/dist/maxDimensions.cjs +43 -0
- package/dist/maxDimensions.test.cjs +18972 -0
- package/dist/minDimensions.cjs +43 -0
- package/dist/minDimensions.test.cjs +18972 -0
- package/dist/referencedDocumentRequires.cjs +44 -0
- package/dist/referencedDocumentRequires.test.cjs +18997 -0
- package/dist/requiredIfPeerEq.cjs +54 -0
- package/dist/requiredIfPeerEq.test.cjs +18989 -0
- package/dist/requiredIfPeerNeq.cjs +54 -0
- package/dist/requiredIfPeerNeq.test.cjs +18989 -0
- package/dist/requiredIfSlugEq.cjs +38 -0
- package/dist/requiredIfSlugEq.test.cjs +19010 -0
- package/dist/requiredIfSlugNeq.cjs +38 -0
- package/dist/requiredIfSlugNeq.test.cjs +18980 -0
- package/package.json +43 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Eric Jacobsen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
# Sanity Advanced Validators
|
|
2
|
+
|
|
3
|
+
(note: this is a WIP, I don’t know a lot about publishing NPM packages, hopefully coming soon)
|
|
4
|
+
|
|
5
|
+
This package includes a set of Sanity validators for aggressive and weird edge cases. Please let me know if you find these helpful!
|
|
6
|
+
|
|
7
|
+
Note that every validator can accept an optional custom error message as its last parameter. `minDimensions` lists one example; all the others work the same way.
|
|
8
|
+
|
|
9
|
+
## Tools
|
|
10
|
+
|
|
11
|
+
- [fileExtension](#fileExtension)
|
|
12
|
+
- [minDimensions](#minDimensions)
|
|
13
|
+
- [maxDimensions](#maxDimensions)
|
|
14
|
+
- [requiredIfPeerEq](#requiredIfPeerEq)
|
|
15
|
+
- [requiredIfPeerNeq](#requiredIfPeerNeq)
|
|
16
|
+
- [requiredIfSlugEq](#requiredIfSlugEq)
|
|
17
|
+
- [requiredIfSlugNeq](#requiredIfSlugNeq)
|
|
18
|
+
- [referencedDocumentRequires](#referencedDocumentRequires)
|
|
19
|
+
- [maxDepth](#maxDepth)
|
|
20
|
+
|
|
21
|
+
## Mega-example
|
|
22
|
+
|
|
23
|
+
Imagine that you’ve got a document that has an optional video file — but it's required on the `/about` page. If the video exists, it must either MP4 or MOV, and have a poster image that's between 1250x800 and 2500x1600 in size.
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
const Page = defineType({
|
|
27
|
+
name: "page",
|
|
28
|
+
type: "document",
|
|
29
|
+
fields: [
|
|
30
|
+
defineField({
|
|
31
|
+
name: 'slug',
|
|
32
|
+
type: 'slug'
|
|
33
|
+
}),
|
|
34
|
+
defineField({
|
|
35
|
+
name: "someVideoFile",
|
|
36
|
+
type: "file",
|
|
37
|
+
validation: (rule) =>
|
|
38
|
+
rule.requiredIfSlugEq('about')
|
|
39
|
+
.custom(fileExtension(['mp4', 'mov']))
|
|
40
|
+
})
|
|
41
|
+
defineField({
|
|
42
|
+
name: "posterImage",
|
|
43
|
+
type: "image",
|
|
44
|
+
hidden: ({ parent }) => parent.someVideoFile === null,
|
|
45
|
+
validation: (rule) =>
|
|
46
|
+
rule.requiredIfPeerNeq('someVideoFile', null)
|
|
47
|
+
.custom(minDimensions({ x: 1250, y: 800 }))
|
|
48
|
+
.custom(maxDimensions({ x: 2500, y: 1600 })),
|
|
49
|
+
})
|
|
50
|
+
]
|
|
51
|
+
})
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Examples
|
|
55
|
+
|
|
56
|
+
### fileType
|
|
57
|
+
|
|
58
|
+
Enforces that an uploaded file asset is of a certain format.
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { fileExtension } from "sanity-advanced-validation"
|
|
62
|
+
|
|
63
|
+
const Page = defineType({
|
|
64
|
+
name: "page",
|
|
65
|
+
type: "document",
|
|
66
|
+
fields: [
|
|
67
|
+
defineField({
|
|
68
|
+
name: "catalog",
|
|
69
|
+
type: "file",
|
|
70
|
+
validation: (rule) => rule.custom(fileType("pdf")),
|
|
71
|
+
}),
|
|
72
|
+
defineField({
|
|
73
|
+
name: "video",
|
|
74
|
+
type: "file",
|
|
75
|
+
validation: (rule) => rule.custom(fileExtension(["mp4", "mov", "webm"])),
|
|
76
|
+
}),
|
|
77
|
+
],
|
|
78
|
+
})
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### minDimensions
|
|
82
|
+
|
|
83
|
+
Enforces that an uploaded image asset is at minimum certain dimensions.
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import { minDimensions } from "sanity-advanced-validation"
|
|
87
|
+
|
|
88
|
+
const ImageWithCaption = defineType({
|
|
89
|
+
name: "imageWithCaption",
|
|
90
|
+
type: "object",
|
|
91
|
+
fields: [
|
|
92
|
+
defineField({
|
|
93
|
+
name: "caption",
|
|
94
|
+
type: "string",
|
|
95
|
+
}),
|
|
96
|
+
defineField({
|
|
97
|
+
name: "image",
|
|
98
|
+
type: "image",
|
|
99
|
+
validation: (rule) => rule.custom(minDimensions({ x: 100, y: 100 })),
|
|
100
|
+
}),
|
|
101
|
+
],
|
|
102
|
+
})
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
You can also enforce on only one dimension, or feed a custom error message:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
defineField({
|
|
109
|
+
name: "image",
|
|
110
|
+
type: "image",
|
|
111
|
+
description: "At least 100px wide; as tall as you like.",
|
|
112
|
+
validation: (rule) => rule.custom(
|
|
113
|
+
minDimensions(
|
|
114
|
+
{ x: 100 },
|
|
115
|
+
"Uh oh, your image is {width} pixels wide. That’s less than {x}!"
|
|
116
|
+
)
|
|
117
|
+
),
|
|
118
|
+
})
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### maxDimensions
|
|
122
|
+
|
|
123
|
+
Enforces that an uploaded image asset is at most certain dimensions.
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
import { maxDimensions } from "sanity-advanced-validation"
|
|
127
|
+
|
|
128
|
+
const ImageWithCaption = defineType({
|
|
129
|
+
name: "imageWithCaption",
|
|
130
|
+
type: "object",
|
|
131
|
+
fields: [
|
|
132
|
+
defineField({
|
|
133
|
+
name: "caption",
|
|
134
|
+
type: "string",
|
|
135
|
+
}),
|
|
136
|
+
defineField({
|
|
137
|
+
name: "image",
|
|
138
|
+
type: "image",
|
|
139
|
+
validation: (rule) => rule.custom(maxDimensions({ x: 2000, y: 2000 })),
|
|
140
|
+
}),
|
|
141
|
+
],
|
|
142
|
+
})
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Chain for min and max dimensions:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
defineField({
|
|
149
|
+
name: "image",
|
|
150
|
+
type: "image",
|
|
151
|
+
description: "Min: 100x100, max: 2000x2000.",
|
|
152
|
+
validation: (rule) =>
|
|
153
|
+
rule
|
|
154
|
+
.required()
|
|
155
|
+
.custom(minDimensions({ x: 1000, y: 1000 }))
|
|
156
|
+
.custom(maxDimensions({ x: 2000, y: 2000 })),
|
|
157
|
+
})
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### requiredIfPeerEq
|
|
161
|
+
|
|
162
|
+
For a given object that has multiple fields, mark a field as `required` if a peer has a particular value.
|
|
163
|
+
|
|
164
|
+
_note:_ This does not work for slugs, because they have to match a nested `.current` value. Use the [requiredIfSlugEq validator](#requiredIfSlugEq) instead.
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
import {requiredIfPeerEq} from 'sanity-advanced-validation'
|
|
168
|
+
|
|
169
|
+
defineType({
|
|
170
|
+
name: 'person',
|
|
171
|
+
type: 'object',
|
|
172
|
+
fields: [
|
|
173
|
+
defineField({
|
|
174
|
+
name: 'name',
|
|
175
|
+
type: 'string'
|
|
176
|
+
}),
|
|
177
|
+
defineField({
|
|
178
|
+
name: 'occupation',
|
|
179
|
+
type: 'string',
|
|
180
|
+
options: {
|
|
181
|
+
list: ['doctor', 'lawyer', 'software engineer']
|
|
182
|
+
}
|
|
183
|
+
})
|
|
184
|
+
defineField({
|
|
185
|
+
name: 'favoriteLanguage',
|
|
186
|
+
type: 'string',
|
|
187
|
+
options: {
|
|
188
|
+
list: [
|
|
189
|
+
'javascript', 'rust', 'python', 'swift'
|
|
190
|
+
]
|
|
191
|
+
}
|
|
192
|
+
hidden: ({parent}) => parent.occuption !== 'software engineer',
|
|
193
|
+
validation: rule => rule.custom(requiredIfPeerEq('occupation', 'software engineer'))
|
|
194
|
+
}),
|
|
195
|
+
],
|
|
196
|
+
})
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
This also works for null. It’s very effective!
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
defineType({
|
|
203
|
+
name: 'person',
|
|
204
|
+
type: 'object',
|
|
205
|
+
fields: [
|
|
206
|
+
defineField({
|
|
207
|
+
name: 'name',
|
|
208
|
+
type: 'string'
|
|
209
|
+
}),
|
|
210
|
+
defineField({
|
|
211
|
+
name: 'email',
|
|
212
|
+
type: 'string',
|
|
213
|
+
})
|
|
214
|
+
defineField({
|
|
215
|
+
name: 'phone',
|
|
216
|
+
type: 'string',
|
|
217
|
+
validation: rule => rule.custom(requiredIfPeerEq(
|
|
218
|
+
'email',
|
|
219
|
+
null,
|
|
220
|
+
"If you don’t have an email address, please provide a phone number."
|
|
221
|
+
))
|
|
222
|
+
})
|
|
223
|
+
],
|
|
224
|
+
})
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
And it even works for arrays.
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
defineType({
|
|
231
|
+
name: 'person',
|
|
232
|
+
type: 'object',
|
|
233
|
+
fields: [
|
|
234
|
+
defineField({
|
|
235
|
+
name: 'name',
|
|
236
|
+
type: 'string'
|
|
237
|
+
}),
|
|
238
|
+
defineType({
|
|
239
|
+
name: 'person',
|
|
240
|
+
type: 'object',
|
|
241
|
+
fields: [
|
|
242
|
+
defineField({
|
|
243
|
+
name: 'name',
|
|
244
|
+
type: 'string'
|
|
245
|
+
}),
|
|
246
|
+
defineField({
|
|
247
|
+
name: 'occupation',
|
|
248
|
+
type: 'string',
|
|
249
|
+
options: {
|
|
250
|
+
list: ['doctor', 'lawyer', 'software engineer']
|
|
251
|
+
}
|
|
252
|
+
}),
|
|
253
|
+
defineField({
|
|
254
|
+
name: 'explanation',
|
|
255
|
+
description: 'Why are you wasting your life this way?',
|
|
256
|
+
type: 'text',
|
|
257
|
+
hidden: ({parent}) => parent.occuption === 'software engineer',
|
|
258
|
+
validation: rule => rule.custom(requiredIfPeerEq('occupation', ['doctor', 'lawyer']))
|
|
259
|
+
})
|
|
260
|
+
],
|
|
261
|
+
})
|
|
262
|
+
],
|
|
263
|
+
})
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### requiredIfPeerNeq
|
|
267
|
+
|
|
268
|
+
For a given object that has multiple fields, mark a field as `required` if a peer does _not_ have a particular value.
|
|
269
|
+
|
|
270
|
+
_note:_ This does not work for slugs, because they have to match a nested `.current` value. Use the [requiredIfSlugNeq validator](#requiredIfSlugNeq) instead.
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
import {requiredIfPeerNeq} from 'sanity-advanced-validation'
|
|
274
|
+
|
|
275
|
+
defineType({
|
|
276
|
+
name: 'person',
|
|
277
|
+
type: 'object',
|
|
278
|
+
fields: [
|
|
279
|
+
defineField({
|
|
280
|
+
name: 'name',
|
|
281
|
+
type: 'string'
|
|
282
|
+
}),
|
|
283
|
+
defineField({
|
|
284
|
+
name: 'occupation',
|
|
285
|
+
type: 'string',
|
|
286
|
+
options: {
|
|
287
|
+
list: ['doctor', 'lawyer', 'software engineer']
|
|
288
|
+
}
|
|
289
|
+
})
|
|
290
|
+
defineField({
|
|
291
|
+
name: 'why',
|
|
292
|
+
description: 'Why are you wasting your life this way?',
|
|
293
|
+
type: 'text',
|
|
294
|
+
hidden: ({parent}) => parent.occuption === 'software engineer',
|
|
295
|
+
validation: rule => rule.custom(requiredIfPeerNeq('occupation', 'software engineer'))
|
|
296
|
+
}),
|
|
297
|
+
],
|
|
298
|
+
})
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### requiredIfSlugEq
|
|
302
|
+
|
|
303
|
+
Require for matching slugs.
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
import {requiredIfSlugEq} from 'sanity-advanced-validation'
|
|
307
|
+
|
|
308
|
+
defineType({
|
|
309
|
+
name: 'page',
|
|
310
|
+
type: 'document',
|
|
311
|
+
fields: [
|
|
312
|
+
defineField({
|
|
313
|
+
name: 'slug',
|
|
314
|
+
type: 'slug'
|
|
315
|
+
}),
|
|
316
|
+
defineField({
|
|
317
|
+
name: 'questionsAndAnswers',
|
|
318
|
+
type: 'array',
|
|
319
|
+
of: [
|
|
320
|
+
{type: 'qaItem'}
|
|
321
|
+
],
|
|
322
|
+
validation: rule => rule.custom(requiredIfSlugEq('faq'))
|
|
323
|
+
hidden: ({parent}) => parent.slug.current !== 'faq'
|
|
324
|
+
})
|
|
325
|
+
]
|
|
326
|
+
})
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
And this can apply to multiple slugs…
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
defineField({
|
|
333
|
+
name: "questionsAndAnswers",
|
|
334
|
+
validation: (rule) => rule.custom(requiredIfSlugEq(["faq", "about"])),
|
|
335
|
+
}),
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### requiredIfSlugNeq
|
|
339
|
+
|
|
340
|
+
Require fields on pages that don't match one or more slugs.
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
import {requiredIfSlugNeq} from 'sanity-advanced-validation'
|
|
344
|
+
|
|
345
|
+
defineType({
|
|
346
|
+
name: 'page',
|
|
347
|
+
type: 'document',
|
|
348
|
+
fields: [
|
|
349
|
+
defineField({
|
|
350
|
+
name: 'slug',
|
|
351
|
+
type: 'slug'
|
|
352
|
+
}),
|
|
353
|
+
defineField({
|
|
354
|
+
name: 'subnav',
|
|
355
|
+
description: 'Subnav is required on documents that aren't '/home'`,
|
|
356
|
+
type: 'array',
|
|
357
|
+
of: [
|
|
358
|
+
{type: 'navLink'}
|
|
359
|
+
],
|
|
360
|
+
validation: rule => rule.custom(requiredIfSlugNeq('home'))
|
|
361
|
+
hidden: ({parent}) => parent.slug.current !== 'home'
|
|
362
|
+
})
|
|
363
|
+
]
|
|
364
|
+
})
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### referencedDocumentRequires
|
|
368
|
+
|
|
369
|
+
You might want to enforce some validation on a referred document. This validator enforces that a given value is not null in the referenced document.
|
|
370
|
+
|
|
371
|
+
```typescript
|
|
372
|
+
defineField({
|
|
373
|
+
name: 'refferedArticle',
|
|
374
|
+
description: 'An article (must include a valid poster image)',
|
|
375
|
+
type: 'reference',
|
|
376
|
+
to: [{type: 'article'}],
|
|
377
|
+
validation: (rule) => rule.custom(referencedDocumentRequires('article', 'poster')),
|
|
378
|
+
}),
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### maxDepth
|
|
382
|
+
|
|
383
|
+
It can be useful to have a nested type. This often comes up when making some kind of navigation tree, like…
|
|
384
|
+
|
|
385
|
+
```
|
|
386
|
+
- Home
|
|
387
|
+
- About
|
|
388
|
+
- Articles
|
|
389
|
+
- First Article
|
|
390
|
+
- Second Article
|
|
391
|
+
- Articles about Trees
|
|
392
|
+
- Article about Elm Trees
|
|
393
|
+
- Article about Willow Trees
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
Sanity can handle this without breaking a sweat:
|
|
397
|
+
|
|
398
|
+
```typescript
|
|
399
|
+
const navigation = defineType({
|
|
400
|
+
name: "navigation",
|
|
401
|
+
type: "document",
|
|
402
|
+
fields: [
|
|
403
|
+
defineField({
|
|
404
|
+
name: "links",
|
|
405
|
+
type: "array",
|
|
406
|
+
of: [{ type: navLink }],
|
|
407
|
+
}),
|
|
408
|
+
],
|
|
409
|
+
})
|
|
410
|
+
|
|
411
|
+
const navLink = defineType({
|
|
412
|
+
name: "navLink",
|
|
413
|
+
type: "object",
|
|
414
|
+
fields: [
|
|
415
|
+
defineField({
|
|
416
|
+
name: "link",
|
|
417
|
+
type: "url",
|
|
418
|
+
}),
|
|
419
|
+
defineField({
|
|
420
|
+
name: "label",
|
|
421
|
+
type: "string",
|
|
422
|
+
}),
|
|
423
|
+
defineField({
|
|
424
|
+
name: "subnav",
|
|
425
|
+
type: "array",
|
|
426
|
+
of: [{ type: navigation }], // < circular reference
|
|
427
|
+
}),
|
|
428
|
+
],
|
|
429
|
+
})
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
… but your users might get a little stupid with this, and you may want to enforce navigations only going _n_ layers deep.
|
|
433
|
+
|
|
434
|
+
```typescript
|
|
435
|
+
import { maxDepth } from "sanity-advanced-validation"
|
|
436
|
+
|
|
437
|
+
const navLink = defineType({
|
|
438
|
+
// …
|
|
439
|
+
fields: [
|
|
440
|
+
// …
|
|
441
|
+
defineField({
|
|
442
|
+
name: "subnav",
|
|
443
|
+
type: "array",
|
|
444
|
+
of: [{ type: navigation }],
|
|
445
|
+
validation: (rule) => rule.custom(maxDepth(3, "subnav")),
|
|
446
|
+
}),
|
|
447
|
+
],
|
|
448
|
+
})
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
This will enforce that a subnav list can embed in a subnav, which can also be embedded in a subnav — but no further.
|
|
452
|
+
|
|
453
|
+
_Note to any Sanity dev who looks at this_: I’d love to include similar logic on my `hidden:` attribute, but I don’t think that’t possible without a `path` array in the `hidden` context that’s similar to the one fed to the `ValidationContext` (todo: type this correctly). Wouldn’t this be cool?
|
|
454
|
+
|
|
455
|
+
```typescript
|
|
456
|
+
defineField({
|
|
457
|
+
name: "subnav",
|
|
458
|
+
type: "array",
|
|
459
|
+
of: [{ type: navigation }],
|
|
460
|
+
hidden: ({ path }) => {
|
|
461
|
+
let regex = new RegExp(String.raw`topLevelItems|subNav`)
|
|
462
|
+
const paths = context.path.filter((e) => e.match(/topLevelItems|subnav/))
|
|
463
|
+
return paths.length > 3
|
|
464
|
+
},
|
|
465
|
+
})
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
## Extending these and writing your own
|
|
469
|
+
|
|
470
|
+
Most of these validators rely on a function called `getPeer()`. If you’re thinking about picking this apart and writing your own custom validator, take a close look at how these validators use it.
|
|
471
|
+
|
|
472
|
+
## MOAR
|
|
473
|
+
|
|
474
|
+
Do you have any ideas or edge cases that these validators don’t cover? Leave an issue, maybe I can hack it out.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/fileExtension.ts
|
|
21
|
+
var fileExtension_exports = {};
|
|
22
|
+
__export(fileExtension_exports, {
|
|
23
|
+
fileExtension: () => fileExtension
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(fileExtension_exports);
|
|
26
|
+
var import_asset_utils = require("@sanity/asset-utils");
|
|
27
|
+
var fileExtension = (validFileExtension, message = `Image must be of type {validFileExtension}`) => (value) => {
|
|
28
|
+
if (!value || !value.asset) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
const validExtensions = typeof validFileExtension === "string" ? [validFileExtension] : validFileExtension;
|
|
32
|
+
const filetype = (0, import_asset_utils.getExtension)(value.asset._ref);
|
|
33
|
+
if (!validExtensions.includes(filetype)) {
|
|
34
|
+
return message.replace("{validFileExtension}", validExtensions.join(", or "));
|
|
35
|
+
}
|
|
36
|
+
return true;
|
|
37
|
+
};
|
|
38
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
39
|
+
0 && (module.exports = {
|
|
40
|
+
fileExtension
|
|
41
|
+
});
|