Skip to content

Commit 8e9347b

Browse files
committed
feat: shorthand functions
1 parent 155e993 commit 8e9347b

16 files changed

Lines changed: 132 additions & 76 deletions

File tree

packages/core/src/core.ts

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { StandardSchemaV1 } from '@standard-schema/spec'
22

33
const kSchema = Symbol.for('schemastery')
4-
const kValidationError = Symbol.for('ValidationError')
54

6-
export interface ParseOptions {
5+
export interface ValidateOptions {
76
autofix?: boolean
87
ignore?: (data: any, schema: Schema) => boolean
98
path?: PropertyKey[]
@@ -38,7 +37,7 @@ export abstract class Schema<S = any, T extends S = S> implements StandardSchema
3837
},
3938
}
4039

41-
abstract validate(value: unknown, options: ParseOptions): Schema.Result<T>
40+
abstract validate(value: unknown, options: ValidateOptions): Schema.Result<T>
4241

4342
format(): string {
4443
return this.type
@@ -61,30 +60,3 @@ export abstract class Schema<S = any, T extends S = S> implements StandardSchema
6160
Object.defineProperty(Schema.prototype, kSchema, {
6261
value: true,
6362
})
64-
65-
export class ValidationError extends TypeError {
66-
name = 'ValidationError'
67-
68-
constructor(message: string, public options: ParseOptions) {
69-
let prefix = '$'
70-
for (const segment of options.path || []) {
71-
if (typeof segment === 'string') {
72-
prefix += '.' + segment
73-
} else if (typeof segment === 'number') {
74-
prefix += '[' + segment + ']'
75-
} else if (typeof segment === 'symbol') {
76-
prefix += `[Symbol(${segment.toString()})]`
77-
}
78-
}
79-
if (prefix.startsWith('.')) prefix = prefix.slice(1)
80-
super((prefix === '$' ? '' : `${prefix} `) + message)
81-
}
82-
83-
static is(error: any): error is ValidationError {
84-
return !!error?.[kValidationError]
85-
}
86-
}
87-
88-
Object.defineProperty(ValidationError.prototype, kValidationError, {
89-
value: true,
90-
})

packages/core/src/schema/any.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
import { ParseOptions, Schema } from '../core.ts'
1+
import { ValidateOptions, Schema } from '../core.ts'
22

3-
export namespace $Any {}
3+
namespace $Any {}
44

5-
export class $Any<T> extends Schema<T> {
5+
class $Any<T> extends Schema<T> {
66
type = 'any'
77

8-
validate(value: unknown, options: ParseOptions) {
8+
validate(value: unknown, options: ValidateOptions) {
99
return { value: value as T }
1010
}
1111
}
12+
13+
export { $Any as Any }
14+
15+
export function any<T = any>() {
16+
return new $Any<T>()
17+
}

packages/core/src/schema/array.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
import { ParseOptions, Schema } from '../core.ts'
1+
import { ValidateOptions, Schema } from '../core.ts'
22

33
const isArray = (value: unknown): value is readonly unknown[] => Array.isArray(value)
44

5-
export namespace $Array {
5+
namespace $Array {
66
export interface Options<S, T extends S = S> {
77
inner: Schema<S, T>
88
length?: Schema<number>
99
}
1010
}
1111

12-
export class $Array<S, T extends S = S> extends Schema<readonly S[], T[]> {
12+
class $Array<S, T extends S = S> extends Schema<readonly S[], T[]> {
1313
type = 'array'
1414
options: $Array.Options<S, T>
1515

@@ -27,7 +27,7 @@ export class $Array<S, T extends S = S> extends Schema<readonly S[], T[]> {
2727
return `Array<${this.options.inner.format()}>`
2828
}
2929

30-
validate(value: unknown, options: ParseOptions) {
30+
validate(value: unknown, options: ValidateOptions) {
3131
if (!isArray(value)) return this.failure(value, options.path)
3232
if (this.options.length) {
3333
const result = this.options.length.validate(value.length, options)
@@ -52,3 +52,9 @@ export class $Array<S, T extends S = S> extends Schema<readonly S[], T[]> {
5252
return { value: values }
5353
}
5454
}
55+
56+
export { $Array as Array }
57+
58+
export function array<S, T extends S = S>(inner: Schema<S, T>) {
59+
return new $Array(inner)
60+
}
Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1-
import { ParseOptions, Schema } from '../core.ts'
1+
import { ValidateOptions, Schema } from '../core.ts'
22

3-
export class $Boolean extends Schema<boolean> {
3+
class $Boolean extends Schema<boolean> {
44
type = 'boolean'
55

6-
validate(value: unknown, options: ParseOptions) {
6+
validate(value: unknown, options: ValidateOptions) {
77
if (typeof value !== 'boolean') return this.failure(value, options.path)
88
return { value }
99
}
1010
}
11+
12+
export { $Boolean as Boolean }
13+
14+
export function boolean() {
15+
return new $Boolean()
16+
}

packages/core/src/schema/const.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { deepEqual } from 'cosmokit'
2-
import { ParseOptions, Schema } from '../core.ts'
2+
import { ValidateOptions, Schema } from '../core.ts'
33

4-
export namespace $Const {
4+
namespace $Const {
55
export interface Options<T> {
66
value: T
77
}
88
}
99

10-
export class $Const<T> extends Schema<T> {
10+
class $Const<T> extends Schema<T> {
1111
type = 'const'
1212
options: $Const.Options<T>
1313

@@ -22,10 +22,16 @@ export class $Const<T> extends Schema<T> {
2222
: String(this.options.value)
2323
}
2424

25-
validate(value: unknown, options: ParseOptions) {
25+
validate(value: unknown, options: ValidateOptions) {
2626
if (!deepEqual(value, this.options.value, true)) {
2727
return this.failure(value, options.path)
2828
}
2929
return { value: value as T }
3030
}
3131
}
32+
33+
function $const<T>(value: T) {
34+
return new $Const(value)
35+
}
36+
37+
export { $Const as Const, $const as const }

packages/core/src/schema/dict.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import { ParseOptions, Schema } from '../core.ts'
1+
import { ValidateOptions, Schema } from '../core.ts'
22

3-
export namespace $Dict {
3+
namespace $Dict {
44
export interface Options<S, T extends S = S> {
55
inner: Schema<S, T>
66
key?: Schema<string>
77
}
88
}
99

10-
export class $Dict<S, T extends S = S> extends Schema<Readonly<Record<string, S>>, Record<string, T>> {
10+
class $Dict<S, T extends S = S> extends Schema<Readonly<Record<string, S>>, Record<string, T>> {
1111
type = 'dict'
1212
options: $Dict.Options<S, T>
1313

@@ -25,7 +25,7 @@ export class $Dict<S, T extends S = S> extends Schema<Readonly<Record<string, S>
2525
return `Record<${this.options.key ? this.options.key.format() : 'string'}, ${this.options.inner.format()}>`
2626
}
2727

28-
validate(value: unknown, options: ParseOptions) {
28+
validate(value: unknown, options: ValidateOptions) {
2929
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
3030
return this.failure(value, options.path)
3131
}
@@ -52,3 +52,9 @@ export class $Dict<S, T extends S = S> extends Schema<Readonly<Record<string, S>
5252
return { value: values }
5353
}
5454
}
55+
56+
export { $Dict as Dict }
57+
58+
export function dict<S, T extends S = S>(inner: Schema<S, T>) {
59+
return new $Dict(inner)
60+
}
Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1-
import { ParseOptions, Schema } from '../core.ts'
1+
import { ValidateOptions, Schema } from '../core.ts'
22

3-
export class $Function extends Schema<Function> {
3+
class $Function extends Schema<Function> {
44
type = 'function'
55

6-
validate(value: unknown, options: ParseOptions) {
6+
validate(value: unknown, options: ValidateOptions) {
77
if (typeof value !== 'function') return this.failure(value, options.path)
88
return { value }
99
}
1010
}
11+
12+
function $function() {
13+
return new $Function()
14+
}
15+
16+
export { $Function as Function, $function as function }

packages/core/src/schema/intersect.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,7 @@ class $Intersect<S, T extends S = S> extends Schema<S, T> {
3939
}
4040

4141
export { $Intersect as Intersect }
42+
43+
export function intersect(items: Schema[]) {
44+
return new $Intersect(items)
45+
}

packages/core/src/schema/is.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { isNullable } from 'cosmokit'
2-
import { ParseOptions, Schema } from '../core.ts'
2+
import { ValidateOptions, Schema } from '../core.ts'
33

4-
export namespace $Is {
4+
namespace $Is {
55
export interface Options {
66
constructor: { name: string }
77
}
88
}
99

10-
export class $Is<T> extends Schema<T> {
10+
class $Is<T> extends Schema<T> {
1111
type = 'is'
1212
options: $Is.Options
1313

@@ -20,7 +20,7 @@ export class $Is<T> extends Schema<T> {
2020
return this.options.constructor.name
2121
}
2222

23-
validate(value: unknown, options: ParseOptions) {
23+
validate(value: unknown, options: ValidateOptions) {
2424
let isValid: boolean
2525
if (typeof this.options.constructor === 'function') {
2626
isValid = value instanceof this.options.constructor
@@ -42,3 +42,9 @@ export class $Is<T> extends Schema<T> {
4242
return { value: value as T }
4343
}
4444
}
45+
46+
export { $Is as Is }
47+
48+
export function is<T>(constructor: { new (...args: any[]): T } | { name: string }) {
49+
return new $Is<T>(constructor)
50+
}

packages/core/src/schema/never.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
import { ParseOptions, Schema } from '../core.ts'
1+
import { ValidateOptions, Schema } from '../core.ts'
22

3-
export namespace $Never {}
3+
namespace $Never {}
44

5-
export class $Never<T> extends Schema<T> {
5+
class $Never extends Schema<never> {
66
type = 'never'
77

8-
validate(value: unknown, options: ParseOptions) {
8+
validate(value: unknown, options: ValidateOptions) {
99
return this.failure(value, options.path)
1010
}
1111
}
12+
13+
export { $Never as Never }
14+
15+
export function never() {
16+
return new $Never()
17+
}

0 commit comments

Comments
 (0)