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

schemastery

Package Overview
Dependencies
Maintainers
1
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 2.0.0 to 2.1.0

56

lib/index.d.ts

@@ -1,3 +0,3 @@

declare type Dict<T = any> = {
[key: string]: T;
declare type Dict<T = any, K extends string = string> = {
[key in K]?: T;
};

@@ -10,2 +10,3 @@ declare type Intersect<U> = (U extends any ? (arg: U) => void : never) extends ((arg: infer I) => void) ? I : never;

new (data?: null): T;
[kSchema]: true;
toJSON(): Schema.Base<T>;

@@ -20,7 +21,11 @@ required(): Schema<S, T>;

export declare namespace Schema {
export type TypeS<X> = X extends Schema<infer S, unknown> ? S : never;
export type TypeT<X> = ReturnType<Extract<X, Schema>>;
export type From<T> = T extends string | number | boolean ? Schema<T> : T extends Schema ? T : T extends typeof String ? Schema<string> : T extends typeof Number ? Schema<number> : T extends typeof Boolean ? Schema<boolean> : T extends Constructor<infer S> ? Schema<S> : never;
type _TypeS<X> = X extends Schema<infer S, unknown> ? S : never;
type _TypeT<X> = ReturnType<Extract<X, Schema>>;
export type TypeS<X> = _TypeS<From<X>>;
export type TypeT<X> = _TypeT<From<X>>;
export type Resolve = (data: any, schema?: Schema, strict?: boolean) => [any, any?];
export interface Base<T = any> {
type: string;
sKey?: Schema;
inner?: Schema;

@@ -41,11 +46,19 @@ list?: Schema[];

}
type TupleS<X extends readonly unknown[]> = X extends readonly [infer L, ...infer R] ? [TypeS<L>?, ...TupleS<R>] : any[];
type TupleT<X extends readonly unknown[]> = X extends readonly [infer L, ...infer R] ? [TypeT<L>?, ...TupleT<R>] : any[];
type ObjectS<X extends Dict<Schema>> = {
type TupleS<X extends readonly any[]> = X extends readonly [infer L, ...infer R] ? [TypeS<L>?, ...TupleS<R>] : any[];
type TupleT<X extends readonly any[]> = X extends readonly [infer L, ...infer R] ? [TypeT<L>?, ...TupleT<R>] : any[];
type ObjectS<X extends Dict> = {
[K in keyof X]?: TypeS<X[K]>;
} & Dict;
type ObjectT<X extends Dict<Schema>> = {
type ObjectT<X extends Dict> = {
[K in keyof X]?: TypeT<X[K]>;
} & Dict;
export interface Types {
type Constructor<T = any> = new (...args: any[]) => T;
export interface Static {
<T = any>(options: Base<T>): Schema<T>;
new <T = any>(options: Base<T>): Schema<T>;
prototype: Schema;
resolve: Resolve;
from<T>(source: T): Schema<From<T>>;
property(data: any, key: keyof any, schema?: Schema): any;
extend(type: string, resolve: Resolve): void;
any(): Schema<any>;

@@ -57,22 +70,15 @@ never(): Schema<never>;

boolean(): Schema<boolean>;
array<S, T>(inner: Schema<S, T>): Schema<S[], T[]>;
dict<S, T>(inner: Schema<S, T>): Schema<Dict<S>, Dict<T>>;
tuple<X extends readonly Schema[]>(list: X): Schema<TupleS<X>, TupleT<X>>;
object<X extends Dict<Schema>>(dict: X): Schema<ObjectS<X>, ObjectT<X>>;
union<X extends Schema>(list: readonly X[]): Schema<TypeS<X>, TypeT<X>>;
intersect<X extends Schema>(list: readonly X[]): Schema<Intersect<TypeS<X>>, Intersect<TypeT<X>>>;
transform<S, T>(inner: Schema<S>, callback: (value: S) => T): Schema<S, T>;
is<T>(constructor: Constructor<T>): Schema<T>;
array<X>(inner: X): Schema<TypeS<X>[], TypeT<X>[]>;
dict<X, Y extends string | Schema<any, string>>(inner: X, sKey?: Y): Schema<Dict<TypeS<X>, TypeS<Y>>, Dict<TypeT<X>, TypeT<Y>>>;
tuple<X extends readonly any[]>(list: X): Schema<TupleS<X>, TupleT<X>>;
object<X extends Dict>(dict: X): Schema<ObjectS<X>, ObjectT<X>>;
union<X>(list: readonly X[]): Schema<TypeS<X>, TypeT<X>>;
intersect<X>(list: readonly X[]): Schema<Intersect<TypeS<X>>, Intersect<TypeT<X>>>;
transform<X, T>(inner: X, callback: (value: TypeS<X>) => T): Schema<TypeS<X>, T>;
}
export interface Static extends Types {
prototype: Schema;
resolve: Resolve;
property(data: any, key: keyof any, schema?: Schema): any;
extend<K extends keyof Types>(type: K, resolve: Resolve, keys?: (keyof Base)[], meta?: Meta): void;
select<T extends string>(values: T[] | Record<T, string>): Schema<T>;
<T = any>(options: Base<T>): Schema<T>;
new <T = any>(options: Base<T>): Schema<T>;
}
export {};
}
declare const kSchema: unique symbol;
export declare const Schema: Schema.Static;
export default Schema;

@@ -10,5 +10,3 @@ "use strict";

}
function valueMap(object, transform) {
return Object.fromEntries(Object.entries(object).map(([key, value]) => [key, transform(value, key)]));
}
const kSchema = Symbol('schemastery');
exports.Schema = function (options) {

@@ -24,2 +22,3 @@ const schema = function (data) {

exports.Schema.prototype = Object.create(Function.prototype);
exports.Schema.prototype[kSchema] = true;
exports.Schema.prototype.toJSON = function toJSON() {

@@ -45,16 +44,4 @@ return { ...this };

const resolvers = {};
exports.Schema.extend = function extend(type, resolve, keys, meta) {
exports.Schema.extend = function extend(type, resolve) {
resolvers[type] = resolve;
if (!keys)
return;
Object.assign(exports.Schema, {
[type](...args) {
const schema = new exports.Schema({ type });
keys.forEach((key, index) => {
schema[key] = args[index];
});
Object.assign(schema.meta, meta);
return schema;
},
});
};

@@ -83,8 +70,30 @@ exports.Schema.resolve = function resolve(data, schema, hint) {

};
exports.Schema.from = function from(source) {
if (isNullable(source)) {
return exports.Schema.any();
}
else if (['string', 'number', 'boolean'].includes(typeof source)) {
return exports.Schema.const(source).required();
}
else if (source[kSchema]) {
return source;
}
else if (typeof source === 'function') {
switch (source) {
case String: return exports.Schema.string();
case Number: return exports.Schema.number();
case Boolean: return exports.Schema.boolean();
default: return exports.Schema.is(source);
}
}
else {
throw new TypeError(`cannot infer schema from ${source}`);
}
};
exports.Schema.extend('any', (data) => {
return [data];
}, []);
});
exports.Schema.extend('never', (data) => {
throw new TypeError(`expected nullable but got ${data}`);
}, []);
});
exports.Schema.extend('const', (data, { value }) => {

@@ -94,3 +103,3 @@ if (data === value)

throw new TypeError(`expected ${value} but got ${data}`);
}, ['value']);
});
exports.Schema.extend('string', (data) => {

@@ -100,3 +109,3 @@ if (typeof data === 'string')

throw new TypeError(`expected string but got ${data}`);
}, []);
});
exports.Schema.extend('number', (data) => {

@@ -106,3 +115,3 @@ if (typeof data === 'number')

throw new TypeError(`expected number but got ${data}`);
}, []);
});
exports.Schema.extend('boolean', (data) => {

@@ -112,3 +121,8 @@ if (typeof data === 'boolean')

throw new TypeError(`expected boolean but got ${data}`);
}, []);
});
exports.Schema.extend('is', (data, { callback }) => {
if (data instanceof callback)
return [data];
throw new TypeError(`expected instance of ${callback.name} but got ${data}`);
});
exports.Schema.extend('array', (data, { inner }) => {

@@ -118,8 +132,23 @@ if (!Array.isArray(data))

return [data.map((_, index) => exports.Schema.property(data, index, inner))];
}, ['inner']);
exports.Schema.extend('dict', (data, { inner }) => {
});
exports.Schema.extend('dict', (data, { inner, sKey }, strict) => {
if (!isObject(data))
throw new TypeError(`expected dict but got ${data}`);
return [valueMap(data, (_, key) => exports.Schema.property(data, key, inner))];
}, ['inner']);
const result = {};
for (const key in data) {
let rKey;
try {
rKey = exports.Schema.resolve(key, sKey)[0];
}
catch (error) {
if (strict)
continue;
throw error;
}
result[rKey] = exports.Schema.property(data, key, inner);
data[rKey] = data[key];
delete data[key];
}
return [result];
});
exports.Schema.extend('tuple', (data, { list }, strict) => {

@@ -133,3 +162,3 @@ if (!Array.isArray(data))

return [result];
}, ['list']);
});
function merge(result, data) {

@@ -155,3 +184,3 @@ for (const key in data) {

return [result];
}, ['dict']);
});
exports.Schema.extend('union', (data, { list }) => {

@@ -168,3 +197,3 @@ const messages = [];

throw new TypeError(`expected union but got ${JSON.stringify(data)}`);
}, ['list']);
});
exports.Schema.extend('intersect', (data, { list }) => {

@@ -179,3 +208,3 @@ const result = {};

return [result];
}, ['list']);
});
exports.Schema.extend('transform', (data, { inner, callback }) => {

@@ -197,11 +226,42 @@ const [result, adapted = data] = exports.Schema.resolve(data, inner, true);

}
}, ['inner', 'callback']);
exports.Schema.select = function select(values) {
if (Array.isArray(values))
values = Object.fromEntries(values.map((value) => [value, value]));
const list = Array.isArray(values)
? values.map((value) => exports.Schema.const(value).description(value))
: Object.entries(values).map(([key, value]) => exports.Schema.const(key).description(value));
return exports.Schema.union(list);
};
});
function defineMethod(name, keys) {
Object.assign(exports.Schema, {
[name](...args) {
const schema = new exports.Schema({ type: name });
keys.forEach((key, index) => {
switch (key) {
case 'sKey':
schema.sKey = exports.Schema.from(args[index]);
break;
case 'inner':
schema.inner = exports.Schema.from(args[index]);
break;
case 'list':
schema.list = args[index].map(exports.Schema.from);
break;
case 'dict':
schema.dict = Object.fromEntries(Object.entries(args[index]).map(([key, value]) => [key, exports.Schema.from(value)]));
break;
default: schema[key] = args[index];
}
});
return schema;
},
});
}
defineMethod('is', ['callback']);
defineMethod('any', []);
defineMethod('never', []);
defineMethod('const', ['value']);
defineMethod('string', []);
defineMethod('number', []);
defineMethod('boolean', []);
defineMethod('array', ['inner']);
defineMethod('dict', ['inner', 'sKey']);
defineMethod('tuple', ['list']);
defineMethod('object', ['dict']);
defineMethod('union', ['list']);
defineMethod('intersect', ['list']);
defineMethod('transform', ['inner', 'callback']);
exports.default = exports.Schema;
{
"name": "schemastery",
"description": "Yet another schema validator",
"version": "2.0.0",
"version": "2.1.0",
"main": "index.js",

@@ -6,0 +6,0 @@ "typings": "lib/index.d.ts",

# Schemastery
[![npm](https://img.shields.io/npm/v/schemastery?style=flat-square)](https://www.npmjs.com/package/schemastery)
Yet another schema validator.

@@ -7,5 +9,5 @@

- **Lightweight.** No dependencies.
- **Lightweight.** Zero dependencies.
- **Easy to use.** You can use any schema as a function or constructor directly.
- **Powerful.** Schemastery supports some advanced types such as `transform`.
- **Powerful.** Schemastery supports some advanced types such as `union`, `intersect` and `transform`.
- **Extensible.** You can create your own schema types via `Schema.extend()`.

@@ -34,3 +36,3 @@ - **Serializable.** Schema objects can be serialized into JSON and then be hydrated in another environment.

interface Config {
foo?: 'red' | 'blue'
foo: Record<string, string>
bar: string[]

@@ -40,12 +42,12 @@ }

const Config = Schema.object({
foo: Schema.select(['red', 'blue']).default('red'),
bar: Schema.array(Schema.string()),
foo: Schema.dict(Schema.string()).default({}),
bar: Schema.array(Schema.string()).default([]),
})
// config is an instance of Config
// in this case, that is { foo: red, bar: [] }
// in this case, that is { foo: {}, bar: [] }
const config = new Config()
```
## Builtin Types
## Basic Types

@@ -76,2 +78,13 @@ ### Schema.any()

### Schema.const(value)
Assert that the value is equal to the given constant.
```js
const validate = Schema.const(10)
validate(10) // 10
validate(0) // TypeError
```
### Schema.number()

@@ -86,3 +99,2 @@

validate(1) // 1
validate(Number()) // 0
validate('') // TypeError

@@ -101,3 +113,2 @@ ```

validate('foo') // 'foo'
validate(String()) // ''
```

@@ -115,5 +126,16 @@

validate(true) // true
validate(Boolean()) // false
```
### Schema.is(constructor)
Assert that the value is an instance of the given constructor.
```js
const validate = Schema.is(RegExp)
validate() // undefined
validate(/foo/) // /foo/
validate('foo') // TypeError
```
### Schema.array(value)

@@ -216,3 +238,3 @@

validaate() // 1
validate() // 1
validate('0') // TypeError

@@ -222,6 +244,85 @@ validate(10) // 11

## Instance Methods
### schema.required()
Assert that the value is not nullable.
### schema.default(value)
Set the fallback value when nullable.
### schema.description(text)
Set the description of the schema.
## Shorthand Syntax
Some shorthand syntax is available for inner types.
- `Schema.any()` -> `undefined`
- `Schema.string()` -> `String`
- `Schema.number()` -> `Number`
- `Schema.boolean()` -> `Boolean`
- `Schema.const(1)` -> `1` (only for primitive types)
- `Schema.is(Date)` -> `Date`
```js
Schema.array(String) // Schema.array(Schema.string())
Schema.union([1, 2]) // Schema.union([Schema.const(1), Schema.const(2)])
Schema.dict(RegExp) // Schema.dict(Schema.is(RegExp))
```
## Advanced Examples
Here are some examples which demonstrate how to define advanced types.
### Enumeration
```js
const Enum = Schema.union(['red', 'blue'])
Enum('red') // 'red'
Enum('blue') // 'blue'
Enum('green') // TypeError
```
### ToString
```js
const ToString = Schema.transform(Schema.any(), v => String(v))
ToString('') // ''
ToString(0) // '0'
ToString({}) // '{}'
```
### Listable
```js
const Listable = Schema.union([
Schema.array(Schema.number()),
Schema.transform(Schema.number(), n => [n]),
]).default([])
Listable() // []
Listable(0) // [0]
Listable([1, 2]) // [1, 2]
```
### Alias
```js
const Config = Schema.dict(Schema.number(), Schema.union([
'foo',
Schema.transform('bar', () => 'foo'),
]))
Config({ foo: 1 }) // { foo: 1 }
Config({ bar: 2 }) // { foo: 2 }
Config({ bar: '3' }) // TypeError
```
## Extensibility
Use `Schema.extend()` to create a new type.
## Serializability

@@ -228,0 +329,0 @@

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