New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

schemastery

Package Overview
Dependencies
Maintainers
0
Versions
61
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

schemastery - npm Package Compare versions

Comparing version 3.14.7 to 3.15.0

19

lib/index.d.ts

@@ -1,2 +0,2 @@

import { Dict } from 'cosmokit';
import { Binary, Dict } from 'cosmokit';
declare const kSchema: unique symbol;

@@ -10,3 +10,3 @@ declare global {

type TypeT<X> = ReturnType<From<X>>;
type Resolve = (data: any, schema: Schema, options?: Options, strict?: boolean) => [any, any?];
type Resolve = (data: any, schema: Schema, options: Options, strict?: boolean) => [any, any?];
type IntersectS<X> = From<X> extends Schema<infer S, unknown> ? S : never;

@@ -30,3 +30,3 @@ type IntersectT<X> = Inverse<From<X>> extends ((arg: infer T) => void) ? T : never;

extend(type: string, resolve: Resolve): void;
any(): Schema<any>;
any<T = any>(): Schema<T>;
never(): Schema<never>;

@@ -40,2 +40,5 @@ const<const T>(value: T): Schema<T>;

date(): Schema<string | Date, Date>;
regExp(flag?: string): Schema<string | RegExp, RegExp>;
arrayBuffer(): Schema<Binary.Source, ArrayBufferLike>;
arrayBuffer(encoding: 'hex' | 'base64'): Schema<Binary.Source | string, ArrayBufferLike>;
bitset<K extends string>(bits: Partial<Record<K, number>>): Schema<number | readonly K[], number>;

@@ -50,3 +53,4 @@ function(): Schema<Function, (...args: any[]) => any>;

intersect<const X>(list: readonly X[]): Schema<IntersectS<X>, IntersectT<X>>;
transform<X, T>(inner: X, callback: (value: TypeS<X>) => T, preserve?: boolean): Schema<TypeS<X>, T>;
transform<X, T>(inner: X, callback: (value: TypeS<X>, options: Schemastery.Options) => T, preserve?: boolean): Schema<TypeS<X>, T>;
ValidationError: typeof ValidationError;
}

@@ -56,2 +60,3 @@ interface Options {

ignore?(data: any, schema: Schema): boolean;
path?: (keyof any)[];
}

@@ -124,4 +129,10 @@ interface Meta<T = any> {

}
declare class ValidationError extends TypeError {
options: Schemastery.Options;
name: string;
constructor(message: string, options: Schemastery.Options);
static is(error: any): error is ValidationError;
}
type Schema<S = any, T = S> = Schemastery<S, T>;
declare const Schema: Schemastery.Static;
export = Schema;
{
"name": "schemastery",
"description": "Type driven schema validator",
"version": "3.14.7",
"version": "3.15.0",
"main": "lib/index.cjs",

@@ -6,0 +6,0 @@ "module": "lib/index.mjs",

@@ -1,4 +0,5 @@

import { clone, deepEqual, Dict, filterKeys, isNullable, isPlainObject, pick, valueMap } from 'cosmokit'
import { Binary, clone, deepEqual, Dict, filterKeys, isNullable, isPlainObject, pick, valueMap } from 'cosmokit'
const kSchema = Symbol.for('schemastery')
const kValidationError = Symbol.for('ValidationError')

@@ -22,3 +23,3 @@ declare global {

export type TypeT<X> = ReturnType<From<X>>
export type Resolve = (data: any, schema: Schema, options?: Options, strict?: boolean) => [any, any?]
export type Resolve = (data: any, schema: Schema, options: Options, strict?: boolean) => [any, any?]

@@ -41,3 +42,3 @@ export type IntersectS<X> = From<X> extends Schema<infer S, unknown> ? S : never

extend(type: string, resolve: Resolve): void
any(): Schema<any>
any<T = any>(): Schema<T>
never(): Schema<never>

@@ -51,2 +52,5 @@ const<const T>(value: T): Schema<T>

date(): Schema<string | Date, Date>
regExp(flag?: string): Schema<string | RegExp, RegExp>
arrayBuffer(): Schema<Binary.Source, ArrayBufferLike>
arrayBuffer(encoding: 'hex' | 'base64'): Schema<Binary.Source | string, ArrayBufferLike>
bitset<K extends string>(bits: Partial<Record<K, number>>): Schema<number | readonly K[], number>

@@ -61,3 +65,4 @@ function(): Schema<Function, (...args: any[]) => any>

intersect<const X>(list: readonly X[]): Schema<IntersectS<X>, IntersectT<X>>
transform<X, T>(inner: X, callback: (value: TypeS<X>) => T, preserve?: boolean): Schema<TypeS<X>, T>
transform<X, T>(inner: X, callback: (value: TypeS<X>, options: Schemastery.Options) => T, preserve?: boolean): Schema<TypeS<X>, T>
ValidationError: typeof ValidationError
}

@@ -68,2 +73,3 @@

ignore?(data: any, schema: Schema): boolean
path?: (keyof any)[]
}

@@ -140,6 +146,33 @@

class ValidationError extends TypeError {
name = 'ValidationError'
constructor(message: string, public options: Schemastery.Options) {
let prefix = '$'
for (const segment of options.path || []) {
if (typeof segment === 'string') {
prefix += '.' + segment
} else if (typeof segment === 'number') {
prefix += '[' + segment + ']'
} else if (typeof segment === 'symbol') {
prefix += `[Symbol(${segment.toString()})]`
}
}
if (prefix.startsWith('.')) prefix = prefix.slice(1)
super((prefix === '$' ? '' : `${prefix} `) + message)
}
static is(error: any): error is ValidationError {
return !!error?.[kValidationError]
}
}
Object.defineProperty(ValidationError.prototype, kValidationError, {
value: true,
})
type Schema<S = any, T = S> = Schemastery<S, T>
const Schema = function (options: Schema) {
const schema = function (data: any, options?: Schemastery.Options) {
const schema = function (data: any, options: Schemastery.Options = {}) {
return Schema.resolve(data, schema, options)[0]

@@ -179,2 +212,4 @@ } as Schema

Schema.ValidationError = ValidationError
let refs: Record<number, Schema> | undefined

@@ -321,3 +356,3 @@

try {
Schema.resolve(value, schema)
Schema.resolve(value, schema, {})
return schema.simplify(value)

@@ -361,3 +396,3 @@ } catch {}

if (isNullable(data)) {
if (schema.meta.required) throw new TypeError(`missing required value`)
if (schema.meta.required) throw new ValidationError(`missing required value`, options)
let current = schema

@@ -374,3 +409,3 @@ let fallback = schema.meta.default

const callback = resolvers[schema.type]
if (!callback) throw new TypeError(`unsupported type "${schema.type}"`)
if (!callback) throw new ValidationError(`unsupported type "${schema.type}"`, options)

@@ -416,5 +451,5 @@ try {

Schema.is(Date),
Schema.transform(Schema.string().role('datetime'), (value) => {
Schema.transform(Schema.string().role('datetime'), (value, options) => {
const date = new Date(value)
if (isNaN(+date)) throw new TypeError(`invalid date "${value}"`)
if (isNaN(+date)) throw new ValidationError(`invalid date "${value}"`, options)
return date

@@ -425,2 +460,35 @@ }, true),

Schema.regExp = function regExp(flag = '') {
return Schema.union([
Schema.is(RegExp),
Schema.transform(Schema.string().role('regexp', { flag }), (value, options) => {
try {
return new RegExp(value, flag)
} catch (e: any) {
throw new ValidationError(e.message, options)
}
}, true),
])
}
Schema.arrayBuffer = function arrayBuffer(encoding?: 'hex' | 'base64') {
return Schema.union([
Schema.is(ArrayBuffer),
Schema.is(SharedArrayBuffer),
Schema.transform(Schema.any<ArrayBufferView>(), (value, options) => {
if (Binary.isSource(value)) return Binary.fromSource(value)
throw new ValidationError(`expected ArrayBufferSource but got ${value}`, options)
}, true),
...encoding ? [Schema.transform(Schema.string(), (value, options) => {
try {
return encoding === 'base64'
? Binary.fromBase64(value)
: Binary.fromHex(value)
} catch (e: any) {
throw new ValidationError(e.message, options)
}
}, true)] as const : [],
])
}
Schema.extend('any', (data) => {

@@ -430,24 +498,24 @@ return [data]

Schema.extend('never', (data) => {
throw new TypeError(`expected nullable but got ${data}`)
Schema.extend('never', (data, _, options) => {
throw new ValidationError(`expected nullable but got ${data}`, options)
})
Schema.extend('const', (data, { value }) => {
if (data === value) return [value]
throw new TypeError(`expected ${value} but got ${data}`)
Schema.extend('const', (data, { value }, options) => {
if (deepEqual(data, value)) return [value]
throw new ValidationError(`expected ${value} but got ${data}`, options)
})
function checkWithinRange(data: number, meta: Schemastery.Meta<any>, description: string, skipMin = false) {
function checkWithinRange(data: number, meta: Schemastery.Meta<any>, description: string, options: Schemastery.Options, skipMin = false) {
const { max = Infinity, min = -Infinity } = meta
if (data > max) throw new TypeError(`expected ${description} <= ${max} but got ${data}`)
if (data < min && !skipMin) throw new TypeError(`expected ${description} >= ${min} but got ${data}`)
if (data > max) throw new ValidationError(`expected ${description} <= ${max} but got ${data}`, options)
if (data < min && !skipMin) throw new ValidationError(`expected ${description} >= ${min} but got ${data}`, options)
}
Schema.extend('string', (data, { meta }) => {
if (typeof data !== 'string') throw new TypeError(`expected string but got ${data}`)
Schema.extend('string', (data, { meta }, options) => {
if (typeof data !== 'string') throw new ValidationError(`expected string but got ${data}`, options)
if (meta.pattern) {
const regexp = new RegExp(meta.pattern.source, meta.pattern.flags)
if (!regexp.test(data)) throw new TypeError(`expect string to match regexp ${regexp}`)
if (!regexp.test(data)) throw new ValidationError(`expect string to match regexp ${regexp}`, options)
}
checkWithinRange(data.length, meta, 'string length')
checkWithinRange(data.length, meta, 'string length', options)
return [data]

@@ -477,8 +545,8 @@ })

Schema.extend('number', (data, { meta }) => {
if (typeof data !== 'number') throw new TypeError(`expected number but got ${data}`)
checkWithinRange(data, meta, 'number')
Schema.extend('number', (data, { meta }, options) => {
if (typeof data !== 'number') throw new ValidationError(`expected number but got ${data}`, options)
checkWithinRange(data, meta, 'number', options)
const { step } = meta
if (step && !isMultipleOf(data, meta.min ?? 0, step)) {
throw new TypeError(`expected number multiple of ${step} but got ${data}`)
throw new ValidationError(`expected number multiple of ${step} but got ${data}`, options)
}

@@ -488,8 +556,8 @@ return [data]

Schema.extend('boolean', (data) => {
Schema.extend('boolean', (data, _, options) => {
if (typeof data === 'boolean') return [data]
throw new TypeError(`expected boolean but got ${data}`)
throw new ValidationError(`expected boolean but got ${data}`, options)
})
Schema.extend('bitset', (data, { bits, meta }) => {
Schema.extend('bitset', (data, { bits, meta }, options) => {
let value = 0, keys: string[] = []

@@ -506,7 +574,7 @@ if (typeof data === 'number') {

for (const key of keys) {
if (typeof key !== 'string') throw new TypeError(`expected string but got ${key}`)
if (typeof key !== 'string') throw new ValidationError(`expected string but got ${key}`, options)
if (key in bits!) value |= bits![key]!
}
} else {
throw new TypeError(`expected number or array but got ${data}`)
throw new ValidationError(`expected number or array but got ${data}`, options)
}

@@ -517,15 +585,18 @@ if (value === meta.default) return [value]

Schema.extend('function', (data) => {
Schema.extend('function', (data, _, options) => {
if (typeof data === 'function') return [data]
throw new TypeError(`expected function but got ${data}`)
throw new ValidationError(`expected function but got ${data}`, options)
})
Schema.extend('is', (data, { callback }) => {
Schema.extend('is', (data, { callback }, options) => {
if (data instanceof callback!) return [data]
throw new TypeError(`expected ${callback!.name} but got ${data}`)
throw new ValidationError(`expected ${callback!.name} but got ${data}`, options)
})
function property(data: any, key: keyof any, schema: Schema, options?: Schemastery.Options) {
function property(data: any, key: keyof any, schema: Schema, options: Schemastery.Options) {
try {
const [value, adapted] = Schema.resolve(data[key], schema, options)
const [value, adapted] = Schema.resolve(data[key], schema, {
...options,
path: [...options.path || [], key],
})
if (adapted !== undefined) data[key] = adapted

@@ -541,4 +612,4 @@ return value

Schema.extend('array', (data, { inner, meta }, options) => {
if (!Array.isArray(data)) throw new TypeError(`expected array but got ${data}`)
checkWithinRange(data.length, meta, 'array length', !isNullable(inner!.meta.default))
if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options)
checkWithinRange(data.length, meta, 'array length', options, !isNullable(inner!.meta.default))
return [data.map((_, index) => property(data, index, inner!, options))]

@@ -548,3 +619,3 @@ })

Schema.extend('dict', (data, { inner, sKey }, options, strict) => {
if (!isPlainObject(data)) throw new TypeError(`expected object but got ${data}`)
if (!isPlainObject(data)) throw new ValidationError(`expected object but got ${data}`, options)
const result: any = {}

@@ -554,3 +625,3 @@ for (const key in data) {

try {
rKey = Schema.resolve(key, sKey!)[0]
rKey = Schema.resolve(key, sKey!, options)[0]
} catch (error) {

@@ -568,3 +639,3 @@ if (strict) continue

Schema.extend('tuple', (data, { list }, options, strict) => {
if (!Array.isArray(data)) throw new TypeError(`expected array but got ${data}`)
if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options)
const result = list!.map((inner, index) => property(data, index, inner, options))

@@ -584,3 +655,3 @@ if (strict) return [result]

Schema.extend('object', (data, { dict }, options, strict) => {
if (!isPlainObject(data)) throw new TypeError(`expected object but got ${data}`)
if (!isPlainObject(data)) throw new ValidationError(`expected object but got ${data}`, options)
const result: any = {}

@@ -606,3 +677,3 @@ for (const key in dict) {

}
throw new TypeError(`expected ${toString()} but got ${JSON.stringify(data)}`)
throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options)
})

@@ -618,7 +689,7 @@

} else if (typeof result !== typeof value) {
throw new TypeError(`expected ${toString()} but got ${JSON.stringify(data)}`)
throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options)
} else if (typeof value === 'object') {
merge(result ??= {}, value)
} else if (result !== value) {
throw new TypeError(`expected ${toString()} but got ${JSON.stringify(data)}`)
throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options)
}

@@ -625,0 +696,0 @@ }

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc