Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

typanion

Package Overview
Dependencies
Maintainers
1
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

typanion - npm Package Compare versions

Comparing version 1.0.1 to 2.0.0

63

lib/index.d.ts

@@ -5,23 +5,52 @@ type Trait<Type> = {

type InferType<U> = U extends Trait<infer V> ? V : never;
type Test<U, V extends U> = (value: U) => value is V;
type Validator<U, V extends U> = Test<U, V> & Trait<V>;
type AnyValidator = Validator<any, any>;
type LooseTest<U> = (value: U, errors?: string[], p?: string) => boolean;
type StrictTest<U, V extends U> = (value: U, errors?: string[], p?: string) => value is V;
type LooseValidator<U, V> = LooseTest<U> & Trait<V>;
type StrictValidator<U, V extends U> = StrictTest<U, V> & Trait<V>;
type AnyStrictValidator = StrictValidator<any, any>;
declare const simpleKeyRegExp: RegExp;
declare const uuid4RegExp: RegExp;
declare const makeTrait: <U>(value: U) => <V>() => U & Trait<V>;
declare function makeValidator<U, V extends U>({ test }: {
test: Test<U, V>;
}): Test<U, V> & Trait<V>;
declare const literal: <T>(expected: T) => Test<unknown, T> & Trait<T>;
declare const string: () => Test<unknown, string> & Trait<string>;
declare const array: <T extends Validator<any, any>>(spec: T) => Test<unknown, InferType<T>[]> & Trait<InferType<T>[]>;
declare const object: <T extends { [P in keyof T]: Validator<any, any>; }>(spec: T, { allowUnknownKeys, }?: {
test: StrictTest<U, V>;
}): StrictValidator<U, V>;
declare function makeValidator<U, V extends U>({ test }: {
test: LooseTest<U>;
}): LooseValidator<U, V>;
declare function getPrintable(value: unknown): string;
declare function addKey(p: string | undefined, key: string | number): string;
declare function pushError(errors: string[] | null | undefined, p: string | undefined, message: string): boolean;
declare const isUnknown: () => StrictValidator<unknown, unknown>;
declare const isLiteral: <T>(expected: T) => StrictValidator<unknown, T>;
declare const isString: () => StrictValidator<unknown, string>;
declare const isBoolean: () => StrictValidator<unknown, boolean>;
declare const isNumber: () => StrictValidator<unknown, boolean>;
declare const isArray: <T extends StrictValidator<any, any>>(spec: T) => StrictValidator<unknown, InferType<T>[]>;
declare const isObject: <T extends { [P in keyof T]: StrictValidator<any, any>; }>(props: T, { allowUnknownKeys, }?: {
allowUnknownKeys?: boolean | undefined;
}) => Test<unknown, { [P_1 in keyof T]: InferType<T[P_1]>; }> & Trait<{ [P_1 in keyof T]: InferType<T[P_1]>; }>;
declare const oneOf: <T extends Validator<any, any>>(specs: T[]) => Test<unknown, InferType<T>> & Trait<InferType<T>>;
declare const cascade: <T extends Validator<any, any>>(spec: T, followups: Test<InferType<T>, InferType<T>>[]) => Test<unknown, InferType<T>> & Trait<InferType<T>>;
declare const minLength: <T extends {
}) => StrictValidator<unknown, { [P_1 in keyof T]: InferType<T[P_1]>; }>;
declare const isOneOf: <T extends StrictValidator<any, any>>(specs: T[], { exclusive, }?: {
exclusive?: boolean | undefined;
}) => StrictValidator<unknown, InferType<T>>;
declare const applyCascade: <T extends StrictValidator<any, any>>(spec: T, followups: (StrictTest<InferType<T>, InferType<T>> | LooseTest<InferType<T>>)[]) => StrictValidator<unknown, InferType<T>>;
declare const isOptional: <T extends StrictValidator<any, any>>(spec: T) => StrictValidator<unknown, InferType<T> | undefined>;
declare const isNullable: <T extends StrictValidator<any, any>>(spec: T) => StrictValidator<unknown, InferType<T> | null>;
declare const hasMinLength: <T extends {
length: number;
}>(length: number) => Test<T, T> & Trait<T>;
declare const maxLength: <T extends {
}>(length: number) => LooseValidator<T, T>;
declare const hasMaxLength: <T extends {
length: number;
}>(length: number) => Test<T, T> & Trait<T>;
export { Trait, InferType, Test, Validator, AnyValidator, makeTrait, makeValidator, literal, string, array, object, oneOf, cascade, minLength, maxLength };
}>(length: number) => LooseValidator<T, T>;
declare const hasExactLength: <T extends {
length: number;
}>(length: number) => LooseValidator<T, T>;
declare const isAtLeast: (n: number) => LooseValidator<number, number>;
declare const isAtMost: (n: number) => LooseValidator<number, number>;
declare const isInInclusiveRange: (a: number, b: number) => LooseValidator<number, number>;
declare const isInExclusiveRange: (a: number, b: number) => LooseValidator<number, number>;
declare const isInteger: (a: number, b: number) => LooseValidator<number, number>;
declare const matchesRegExp: (regExp: RegExp) => LooseValidator<string, string>;
declare const isLowerCase: () => LooseValidator<string, string>;
declare const isUpperCase: () => LooseValidator<string, string>;
declare const isUUID4: () => LooseValidator<string, string>;
export { Trait, InferType, LooseTest, StrictTest, LooseValidator, StrictValidator, AnyStrictValidator, simpleKeyRegExp, uuid4RegExp, makeTrait, makeValidator, getPrintable, addKey, pushError, isUnknown, isLiteral, isString, isBoolean, isNumber, isArray, isObject, isOneOf, applyCascade, isOptional, isNullable, hasMinLength, hasMaxLength, hasExactLength, isAtLeast, isAtMost, isInInclusiveRange, isInExclusiveRange, isInteger, matchesRegExp, isLowerCase, isUpperCase, isUUID4 };

@@ -5,2 +5,4 @@ 'use strict';

const simpleKeyRegExp = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
const uuid4RegExp = /^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}$/i;
const makeTrait = (value) => () => {

@@ -12,74 +14,274 @@ return value;

}
const literal = (expected) => makeValidator({
test: (value) => {
return value === expected;
function getPrintable(value) {
if (value === null)
return `null`;
if (value === undefined)
return `undefined`;
if (value === ``)
return `an empty string`;
return JSON.stringify(value);
}
function addKey(p, key) {
if (typeof key === `number`) {
return `${p !== null && p !== void 0 ? p : `.`}[${key}]`;
}
else if (simpleKeyRegExp.test(key)) {
return `${p !== null && p !== void 0 ? p : ``}.${key}`;
}
else {
return `${p !== null && p !== void 0 ? p : `.`}[${JSON.stringify(key)}]`;
}
}
function pushError(errors, p, message) {
errors === null || errors === void 0 ? void 0 : errors.push(`${p !== null && p !== void 0 ? p : `.`}: ${message}`);
return false;
}
const isUnknown = () => makeValidator({
test: (value, errors, p) => {
return true;
},
});
const string = () => makeValidator({
test: (value) => {
return typeof value === `string`;
const isLiteral = (expected) => makeValidator({
test: (value, errors, p) => {
const res = value === expected;
if (!res)
pushError(errors, p, `Expected a literal (got ${getPrintable(expected)})`);
return res;
},
});
const array = (spec) => makeValidator({
test: (value) => {
const isString = () => makeValidator({
test: (value, errors, p) => {
const res = typeof value === `string`;
if (!res)
pushError(errors, p, `Expected a string (got ${getPrintable(value)})`);
return res;
},
});
const isBoolean = () => makeValidator({
test: (value, errors, p) => {
const res = typeof value === `boolean`;
if (!res)
pushError(errors, p, `Expected a boolean (got ${getPrintable(value)})`);
return res;
},
});
const isNumber = () => makeValidator({
test: (value, errors, p) => {
const res = typeof value === `number`;
if (!res)
pushError(errors, p, `Expected a number (got ${getPrintable(value)})`);
return res;
},
});
const isArray = (spec) => makeValidator({
test: (value, errors, p) => {
if (!Array.isArray(value))
return false;
return value.every(value => spec(value));
return pushError(errors, p, `Expected an array (got ${getPrintable(value)})`);
let valid = true;
for (let t = 0, T = value.length; t < T; ++t)
valid = spec(value[t], errors, addKey(p, t)) && valid;
return valid;
},
});
const object = (spec, { allowUnknownKeys = false, } = {}) => {
const specKeys = Object.keys(spec);
const isObject = (props, { allowUnknownKeys = false, } = {}) => {
const specKeys = Object.keys(props);
return makeValidator({
test: (value) => {
test: (value, errors, p) => {
if (typeof value !== `object` || value === null)
return false;
if (!allowUnknownKeys) {
const valueKeys = Object.keys(value);
if (valueKeys.length !== specKeys.length) {
return false;
return pushError(errors, p, `Expected an object (got ${getPrintable(value)})`);
const keys = new Set([
...specKeys,
...Object.keys(value),
]);
let valid = true;
for (const key of keys) {
const spec = props[key];
const sub = value[key];
if (typeof spec !== `undefined`) {
valid = spec(sub, errors, addKey(p, key)) && valid;
}
else if (!allowUnknownKeys) {
valid = pushError(errors, addKey(p, key), `Extraneous property (got ${getPrintable(sub)})`);
}
}
return specKeys.every(name => {
const propertyName = name;
const subSpec = spec[propertyName];
const subValue = value[name];
return subSpec(subValue);
});
return valid;
},
});
};
const oneOf = (specs) => makeValidator({
test: (value) => {
return specs.some(spec => spec(value));
const isOneOf = (specs, { exclusive = false, } = {}) => makeValidator({
test: (value, errors, p) => {
const matches = [];
const errorBuffer = typeof errors !== `undefined`
? [] : undefined;
for (let t = 0, T = specs.length; t < T; ++t) {
const subErrors = typeof errors !== `undefined`
? [] : undefined;
if (specs[t](value, subErrors, `${p !== null && p !== void 0 ? p : `.`}#${t + 1}`)) {
matches.push(`#${t + 1}`);
if (!exclusive) {
break;
}
}
else {
errorBuffer === null || errorBuffer === void 0 ? void 0 : errorBuffer.push(subErrors[0]);
}
}
if (matches.length === 1)
return true;
if (matches.length > 1)
pushError(errors, p, `Expected to match exactly a single predicate (matched ${matches.join(`, `)})`);
else
errors === null || errors === void 0 ? void 0 : errors.push(...errorBuffer);
return false;
},
});
const cascade = (spec, followups) => makeValidator({
test: (value) => {
if (!spec(value))
const applyCascade = (spec, followups) => makeValidator({
test: (value, errors, p) => {
if (!spec(value, errors, p))
return false;
return followups.every(spec => {
return spec(value);
return spec(value, errors, p);
});
},
});
const minLength = (length) => makeValidator({
test: (value) => {
return value.length >= length;
const isOptional = (spec) => makeValidator({
test: (value, errors, p) => {
if (typeof value === `undefined`)
return true;
return spec(value, errors, p);
},
});
const maxLength = (length) => makeValidator({
test: (value) => {
return value.length <= length;
const isNullable = (spec) => makeValidator({
test: (value, errors, p) => {
if (value === null)
return true;
return spec(value, errors, p);
},
});
const hasMinLength = (length) => makeValidator({
test: (value, errors, p) => {
const res = value.length >= length;
if (!res)
pushError(errors, p, `Expected to have a length of at least ${length} elements (got ${value.length})`);
return res;
},
});
const hasMaxLength = (length) => makeValidator({
test: (value, errors, p) => {
const res = value.length <= length;
if (!res)
pushError(errors, p, `Expected to have a length of at most ${length} elements (got ${value.length})`);
return res;
},
});
const hasExactLength = (length) => makeValidator({
test: (value, errors, p) => {
const res = value.length <= length;
if (!res)
pushError(errors, p, `Expected to have a length of exactly ${length} elements (got ${value.length})`);
return res;
},
});
const isAtLeast = (n) => makeValidator({
test: (value, errors, p) => {
const res = value >= n;
if (!res)
pushError(errors, p, `Expected to be at least ${n} (got ${value})`);
return res;
},
});
const isAtMost = (n) => makeValidator({
test: (value, errors, p) => {
const res = value <= n;
if (!res)
pushError(errors, p, `Expected to be at most ${n} (got ${value})`);
return res;
},
});
const isInInclusiveRange = (a, b) => makeValidator({
test: (value, errors, p) => {
const res = value >= a && value <= b;
if (!res)
pushError(errors, p, `Expected to be in the [${a}; ${b}] range (got ${value})`);
return res;
},
});
const isInExclusiveRange = (a, b) => makeValidator({
test: (value, errors, p) => {
const res = value >= a && value < b;
if (!res)
pushError(errors, p, `Expected to be in the [${a}; ${b}[ range (got ${value})`);
return res;
},
});
const isInteger = (a, b) => makeValidator({
test: (value, errors, p) => {
const res = value === Math.round(value);
if (!res)
pushError(errors, p, `Expected to be an integer (got ${value})`);
return res;
},
});
const matchesRegExp = (regExp) => makeValidator({
test: (value, errors, p) => {
const res = regExp.test(value);
if (!res)
pushError(errors, p, `Expected to match the pattern ${regExp.toString()} (got ${getPrintable(value)})`);
return res;
},
});
const isLowerCase = () => makeValidator({
test: (value, errors, p) => {
const res = value === value.toLowerCase();
if (!res)
pushError(errors, p, `Expected to be all-lowercase (got ${value})`);
return res;
},
});
const isUpperCase = () => makeValidator({
test: (value, errors, p) => {
const res = value === value.toLowerCase();
if (!res)
pushError(errors, p, `Expected to be all-uppercase (got ${value})`);
return res;
},
});
const isUUID4 = () => makeValidator({
test: (value, errors, p) => {
const res = uuid4RegExp.test(value);
if (!res)
pushError(errors, p, `Expected to be a valid UUID v4 (got ${getPrintable(value)})`);
return res;
},
});
exports.array = array;
exports.cascade = cascade;
exports.literal = literal;
exports.addKey = addKey;
exports.applyCascade = applyCascade;
exports.getPrintable = getPrintable;
exports.hasExactLength = hasExactLength;
exports.hasMaxLength = hasMaxLength;
exports.hasMinLength = hasMinLength;
exports.isArray = isArray;
exports.isAtLeast = isAtLeast;
exports.isAtMost = isAtMost;
exports.isBoolean = isBoolean;
exports.isInExclusiveRange = isInExclusiveRange;
exports.isInInclusiveRange = isInInclusiveRange;
exports.isInteger = isInteger;
exports.isLiteral = isLiteral;
exports.isLowerCase = isLowerCase;
exports.isNullable = isNullable;
exports.isNumber = isNumber;
exports.isObject = isObject;
exports.isOneOf = isOneOf;
exports.isOptional = isOptional;
exports.isString = isString;
exports.isUUID4 = isUUID4;
exports.isUnknown = isUnknown;
exports.isUpperCase = isUpperCase;
exports.makeTrait = makeTrait;
exports.makeValidator = makeValidator;
exports.maxLength = maxLength;
exports.minLength = minLength;
exports.object = object;
exports.oneOf = oneOf;
exports.string = string;
exports.matchesRegExp = matchesRegExp;
exports.pushError = pushError;
exports.simpleKeyRegExp = simpleKeyRegExp;
exports.uuid4RegExp = uuid4RegExp;
{
"name": "typanion",
"version": "1.0.1",
"version": "2.0.0",
"main": "lib/index",

@@ -5,0 +5,0 @@ "license": "MIT",

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

# Clipanion
# Typanion
> Type-safe CLI library with no dependencies
> Static and runtime type assertion library with no dependencies

@@ -15,7 +15,8 @@ [![](https://img.shields.io/npm/v/typanion.svg)]() [![](https://img.shields.io/npm/l/typanion.svg)]() [![](https://img.shields.io/badge/developed%20with-Yarn%202-blue)](https://github.com/yarnpkg/berry)

- Typanion can validate nested arbitrary data structures
- Typanion is type-safe; it uses [type predicates](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards)
- Typanion allows you to derive types from your schemas
- Typanion can validate nested arbitrary data structures
- Typanion is type-safe; it uses [type predicates](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards)
- Typanion allows you to derive types from your schemas
- Typanion can report detailed error reports
Note: Typanion's standard library isn't huge at the moment (mostly strings, arrays, shapes), more types are expected in future versions.
Compared to [yup](https://github.com/jquense/yup), Typanion has a better inference support for TypeScript + supports `isOneOf`. It's functional API makes it very easy to tree shake, which is another bonus (although the library isn't very large in itself).

@@ -27,7 +28,7 @@ ## Usage

```ts
import * as type from 'typanion';
import * as t from 'typanion';
const movie = type.object({
title: type.string(),
description: type.string(),
const isMovie = t.isObject({
title: t.isString(),
description: t.isString(),
});

@@ -41,3 +42,3 @@ ```

if (movie(userData)) {
if (isMovie(userData)) {
console.log(userData.title);

@@ -47,13 +48,24 @@ }

You can derive the type from the schema for use in other functions:
Passing a second parameter allows you to retrieve detailed errors:
```ts
import * as type from 'typanion';
const userData = JSON.parse(input);
const errors: string[] = [];
const movie = type.object({
title: type.string(),
description: type.string(),
if (!isMovie(userData, errors)) {
console.log(errors);
}
```
You can derive the type from the schema and use it in other functions:
```ts
import * as t from 'typanion';
const isMovie = t.isObject({
title: t.isString(),
description: t.isString(),
});
type Movie = type.InferType<typeof movie>;
type Movie = t.InferType<typeof isMovie>;

@@ -66,15 +78,15 @@ // Then just use your alias:

Types can be kept in separate variables if needed:
Schemas can be stored in multiple variables if needed:
```ts
import * as type from 'typanion';
import * as t from 'typanion';
const actor = type.object({
name: type.string();
const isActor = t.isObject({
name: t.isString();
});
const movie = type.object({
title: type.string(),
description: type.string(),
actors: type.array(actor),
const isMovie = t.isObject({
title: t.isString(),
description: t.isString(),
actors: t.isArray(isActor),
});

@@ -87,23 +99,55 @@ ```

- `array(spec)` will ensure that the values are arrays whose values all match the specified schema.
- `isArray(spec)` will ensure that the values are arrays whose values all match the specified schema.
- `cascade(spec, [specA, specB, ...])` will ensure that the values all match `spec` and, if they do, run the followup validations as well. Since those followups will not contribute to the inference (only the lead schema will), you'll typically want to put here anything that's a logical validation, rather than a typed one (cf the [Cascading Predicates](#Cascading-predicate) section).
- `isBoolean()` will ensure that the values are all booleans. Note that to specifically check for either `true` or `false`, you can look for `isLiteral`.
- `literal(value)` will ensure that the values are strictly equal to the specified expected value. It's an handy tool that you can combine with `oneOf` and `object` to parse structures similar to Redux actions, etc.
- `isLiteral(value)` will ensure that the values are strictly equal to the specified expected value. It's an handy tool that you can combine with `oneOf` and `object` to parse structures similar to Redux actions, etc. Note that you'll need to annotate your value with `as const` in order to let TypeScript know that the exact value matters (otherwise it'll cast it to `string` instead).
- `object(props)` will ensure that the values are plain old objects whose properties match the given shape.
- `isNumber()` will ensure that the values are all numbers.
- `oneOf([specA, specB])` will ensure that the values all match any of the provided schema. As a result, the inferred type is the union of all candidates.
- `isObject(props)` will ensure that the values are plain old objects whose properties match the given shape.
- `string()` will ensure that the values are all regular strings.
- `isString()` will ensure that the values are all regular strings.
- `isUnknown()` will accept whatever is the input without validating it, but without refining the type inference either. Note that by default `isUnknown` will forbid `undefined` and `null`, but this can be switched off by explicitly allowing them via `isOptional` and `isNullable`.
### Helper predicates
- `applyCascade(spec, [specA, specB, ...])` will ensure that the values all match `spec` and, if they do, run the followup validations as well. Since those followups will not contribute to the inference (only the lead schema will), you'll typically want to put here anything that's a logical validation, rather than a typed one (cf the [Cascading Predicates](#Cascading-predicate) section).
- `isOneOf([specA, specB])` will ensure that the values all match any of the provided schema. As a result, the inferred type is the union of all candidates. The predicate supports an option, `exclusive`, which ensures that only one variant matches.
- `isOptional(spec)` will add `undefined` as an allowed value for the given specification.
- `isNullable(spec)` will add `null` as an allowed value for the given specification.
### Cascading predicates
- `maxLength` will ensure that the values all have a `length` property at most equal to the specified value.
- `hasExactLength` will ensure that the values all have a `length` property exactly equal to the specified value.
- `minLength` will ensure that the values all have a `length` property at least equal to the specified value.
- `hasMaxLength` will ensure that the values all have a `length` property at most equal to the specified value.
- `hasMinLength` will ensure that the values all have a `length` property at least equal to the specified value.
- `isAtLeast` will ensure that the values compare positively with the specified value.
- `isAtMost` will ensure that the values compare positively with the specified value.
- `isInExclusiveRange` will ensure that the values compare positively with the specified value.
- `isInInclusiveRange` will ensure that the values compare positively with the specified value.
- `isInteger` will ensure that the values are round integers.
- `isLowerCase` will ensure that the values only contain lowercase characters.
- `isUpperCase` will ensure that the values only contain uppercase characters.
- `isUUID4` will ensure that the values are valid UUID 4 strings.
- `matchesRegExp` will ensure that the values all match the given regular expression.
## License (MIT)
> **Copyright © 2019 Mael Nison**
> **Copyright © 2020 Mael Nison**
>

@@ -110,0 +154,0 @@ > Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

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