UNPKG

2.48 kBPlain TextView Raw
1import Ajv from 'ajv'
2import type { Options } from 'ajv'
3
4const AJV_OPTIONS: Options = {
5 removeAdditional: true,
6 allErrors: true,
7 // https://ajv.js.org/options.html#usedefaults
8 useDefaults: 'empty', // this will mutate your input!
9 // these are important and kept same as default:
10 // https://ajv.js.org/options.html#coercetypes
11 coerceTypes: false, // while `false` - it won't mutate your input
12}
13
14/**
15 * Create Ajv with modified defaults.
16 *
17 * https://ajv.js.org/options.html
18 */
19export function getAjv(opt?: Options): Ajv {
20 const ajv = new Ajv({
21 ...AJV_OPTIONS,
22 ...opt,
23 })
24
25 // Add custom formats
26 addCustomAjvFormats(ajv)
27
28 // Adds ajv "formats"
29 // https://ajv.js.org/guide/formats.html
30 require('ajv-formats')(ajv)
31
32 // https://ajv.js.org/packages/ajv-keywords.html
33 require('ajv-keywords')(ajv, [
34 'transform', // trim, toLowerCase, etc.
35 'uniqueItemProperties',
36 'instanceof',
37 ])
38
39 // Adds $merge, $patch keywords
40 // https://github.com/ajv-validator/ajv-merge-patch
41 require('ajv-merge-patch')(ajv)
42
43 return ajv
44}
45
46function addCustomAjvFormats(ajv: Ajv): Ajv {
47 return (
48 ajv
49 .addFormat('id', /^[a-z0-9_]{6,64}$/)
50 .addFormat('slug', /^[a-z0-9-]+$/)
51 .addFormat('semVer', /^[0-9]+\.[0-9]+\.[0-9]+$/)
52 // IETF language tag (https://en.wikipedia.org/wiki/IETF_language_tag)
53 .addFormat('languageTag', /^[a-z]{2}(-[A-Z]{2})?$/)
54 .addFormat('countryCode', /^[A-Z]{2}$/)
55 .addFormat('currency', /^[A-Z]{3}$/)
56 .addFormat('unixTimestamp', {
57 type: 'number',
58 validate: (n: number) => {
59 // 16725225600 is 2500-01-01 in seconds
60 return n >= 0 && n < 16725225600
61 },
62 })
63 .addFormat('unixTimestampMillis', {
64 type: 'number',
65 validate: (n: number) => {
66 // 16725225600000 is 2500-01-01 in milliseconds
67 return n >= 0 && n < 16725225600000
68 },
69 })
70 .addFormat('utcOffset', {
71 type: 'number',
72 validate: (n: number) => {
73 // min: -14 hours
74 // max +14 hours
75 // multipleOf 15 (minutes)
76 return n >= -14 * 60 && n <= 14 * 60 && Number.isInteger(n)
77 },
78 })
79 .addFormat('utcOffsetHours', {
80 type: 'number',
81 validate: (n: number) => {
82 // min: -14 hours
83 // max +14 hours
84 // multipleOf 15 (minutes)
85 return n >= -14 && n <= 14 && Number.isInteger(n)
86 },
87 })
88 )
89}