Skip to content

Commit

Permalink
Add support for ULID validation
Browse files Browse the repository at this point in the history
  • Loading branch information
simoneNEMO committed Jun 8, 2024
1 parent 4799157 commit 9597cf1
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export const messages = {
'notIn': 'The selected {{ field }} is invalid',
'ipAddress': 'The {{ field }} field must be a valid IP address',
'uuid': 'The {{ field }} field must be a valid UUID',
'ulid': 'The {{ field }} field must be a valid ULID',
'hexCode': 'The {{ field }} field must be a valid hex color code',

'boolean': 'The value must be a boolean',
Expand Down
9 changes: 9 additions & 0 deletions src/schema/string/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
urlRule,
jwtRule,
uuidRule,
ulidRule,
trimRule,
ibanRule,
alphaRule,
Expand Down Expand Up @@ -66,6 +67,7 @@ export class VineString extends BaseLiteralType<string, string, string> {
url: urlRule,
iban: ibanRule,
uuid: uuidRule,
ulid: ulidRule,
trim: trimRule,
email: emailRule,
alpha: alphaRule,
Expand Down Expand Up @@ -327,6 +329,13 @@ export class VineString extends BaseLiteralType<string, string, string> {
return this.use(uuidRule(...args))
}

/**
* Validates the value to be a valid ULID
*/
ulid() {
return this.use(ulidRule())
}

/**
* Validates the value contains ASCII characters only
*/
Expand Down
13 changes: 13 additions & 0 deletions src/schema/string/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,19 @@ export const uuidRule = createRule<{ version?: (1 | 2 | 3 | 4 | 5)[] } | undefin
}
)

/**
* Validates the value to be a valid ULID
*/
export const ulidRule = createRule((value, _, field) => {
if (!field.isValid) {
return
}

if (!helpers.isULID(value as string)) {
field.report(messages.ulid, 'ulid', field)
}
})

/**
* Validates the value contains ASCII characters only
*/
Expand Down
19 changes: 19 additions & 0 deletions src/vine/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ import type { FieldContext } from '../types.js'
const BOOLEAN_POSITIVES = ['1', 1, 'true', true, 'on']
const BOOLEAN_NEGATIVES = ['0', 0, 'false', false]

const ULID = /^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/

/**
* Collection of helpers used across the codebase to coerce
* and type-check values from HTML forms.
Expand Down Expand Up @@ -228,6 +230,23 @@ export const helpers = {
'US',
] as const,

/**
* Check if the value is a valid ULID
*/
isULID(value: unknown): boolean {
if (typeof value !== 'string') {
return false
}

// Largest valid ULID is '7ZZZZZZZZZZZZZZZZZZZZZZZZZ'
// https://github.com/ulid/spec#overflow-errors-when-parsing-base32-strings
if (value[0] > '7') {
return false
}

return ULID.test(value)
},

/**
* Check if the value is a valid color hexcode
*/
Expand Down
41 changes: 41 additions & 0 deletions tests/unit/rules/string.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
passportRule,
postalCodeRule,
uuidRule,
ulidRule,
asciiRule,
ibanRule,
jwtRule,
Expand Down Expand Up @@ -1288,6 +1289,46 @@ test.group('String | uuid', () => {
.run(stringRuleValidator)
})

test.group('String | ulid', () => {
test('validate {value}')
.with([
{
errorsCount: 1,
rule: ulidRule(),
value: 22,
error: 'The dummy field must be a string',
},
{
errorsCount: 1,
rule: ulidRule(),
value: 22,
bail: false,
error: 'The dummy field must be a string',
},
{
errorsCount: 1,
rule: ulidRule(),
value: '1999010301',
error: 'The dummy field must be a valid ULID',
},
{
rule: ulidRule(),
value: '01HZW62CR5FNVW4PSXVXC1HTZF',
},
{
rule: ulidRule(),
value: '7ZZZZZZZZZZZZZZZZZZZZZZZZZ',
},
{
errorsCount: 1,
rule: ulidRule(),
value: '80000000000000000000000000',
error: 'The dummy field must be a valid ULID',
},
])
.run(stringRuleValidator)
})

test.group('String | ascii', () => {
test('validate {value}')
.with([
Expand Down
6 changes: 6 additions & 0 deletions tests/unit/schema/string.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
passportRule,
postalCodeRule,
uuidRule,
ulidRule,
asciiRule,
ibanRule,
jwtRule,
Expand Down Expand Up @@ -667,6 +668,11 @@ test.group('VineString | applying rules', () => {
schema: vine.string().uuid(),
rule: uuidRule(),
},
{
name: 'ulid',
schema: vine.string().ulid(),
rule: ulidRule(),
},
{
name: 'ascii',
schema: vine.string().ascii(),
Expand Down

0 comments on commit 9597cf1

Please sign in to comment.