Comparing version 0.0.2 to 0.0.3
@@ -68,6 +68,6 @@ declare const GUBU: { | ||
declare const Optional: Builder; | ||
declare const Empty: Builder; | ||
declare const Any: Builder; | ||
declare const None: Builder; | ||
declare const One: Builder; | ||
declare const Some: Builder; | ||
declare const All: Builder; | ||
@@ -81,5 +81,6 @@ declare const Before: Builder; | ||
declare function buildize(invs?: any): ValSpec; | ||
declare function gubuError(val: any, state: State, text?: string, why?: string): ErrDesc; | ||
declare function makeErr(val: any, state: State, text?: string, why?: string): ErrDesc; | ||
declare type GubuShape = (<T>(inroot?: T, inctx?: any) => T) & { | ||
spec: () => any; | ||
gubu: typeof GUBU; | ||
}; | ||
@@ -94,2 +95,3 @@ declare type Gubu = typeof make & { | ||
Define: typeof Define; | ||
Empty: typeof Empty; | ||
None: typeof None; | ||
@@ -101,6 +103,5 @@ One: typeof One; | ||
Required: typeof Required; | ||
Some: typeof Some; | ||
}; | ||
declare const G$: (spec: any) => ValSpec; | ||
declare const gubu: Gubu; | ||
declare const Gubu: Gubu; | ||
declare const GAfter: Builder; | ||
@@ -112,2 +113,3 @@ declare const GAll: Builder; | ||
declare const GDefine: Builder; | ||
declare const GEmpty: Builder; | ||
declare const GNone: Builder; | ||
@@ -119,4 +121,3 @@ declare const GOne: Builder; | ||
declare const GRequired: Builder; | ||
declare const GSome: Builder; | ||
export type { Validate, Update, Context, Builder, ValSpec, State, }; | ||
export { gubu, G$, norm, buildize, gubuError, After, All, Any, Before, Closed, Define, None, One, Optional, Refer, Rename, Required, Some, GAfter, GAll, GAny, GBefore, GClosed, GDefine, GNone, GOne, GOptional, GRefer, GRename, GRequired, GSome, }; | ||
export { Gubu, G$, norm, buildize, makeErr, After, All, Any, Before, Closed, Define, Empty, None, One, Optional, Refer, Rename, Required, GAfter, GAll, GAny, GBefore, GClosed, GDefine, GEmpty, GNone, GOne, GOptional, GRefer, GRename, GRequired, }; |
95
gubu.js
"use strict"; | ||
/* Copyright (c) 2021 Richard Rodger, MIT License */ | ||
/* Copyright (c) 2021 Richard Rodger and other contributors, MIT License */ | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
@@ -7,8 +7,10 @@ return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.GSome = exports.GRequired = exports.GRename = exports.GRefer = exports.GOptional = exports.GOne = exports.GNone = exports.GDefine = exports.GClosed = exports.GBefore = exports.GAny = exports.GAll = exports.GAfter = exports.Some = exports.Required = exports.Rename = exports.Refer = exports.Optional = exports.One = exports.None = exports.Define = exports.Closed = exports.Before = exports.Any = exports.All = exports.After = exports.gubuError = exports.buildize = exports.norm = exports.G$ = exports.gubu = void 0; | ||
exports.GRequired = exports.GRename = exports.GRefer = exports.GOptional = exports.GOne = exports.GNone = exports.GEmpty = exports.GDefine = exports.GClosed = exports.GBefore = exports.GAny = exports.GAll = exports.GAfter = exports.Required = exports.Rename = exports.Refer = exports.Optional = exports.One = exports.None = exports.Empty = exports.Define = exports.Closed = exports.Before = exports.Any = exports.All = exports.After = exports.makeErr = exports.buildize = exports.norm = exports.G$ = exports.Gubu = void 0; | ||
/* | ||
* NOTE: `undefined` is not considered a value or type, and thus means 'any'. | ||
*/ | ||
// TODO: custom undefined handling? | ||
// TODO: closed on array | ||
// TODO: composable? | ||
// TODO: function deref? | ||
// TODO: test Some, or drop? | ||
// TODO: BigInt spec roundtrip test | ||
@@ -62,3 +64,3 @@ // TODO: Only - builder, exact values | ||
function norm(spec) { | ||
var _a, _b, _c, _d, _e, _f; | ||
var _a, _b, _c, _d, _e, _f, _g; | ||
// Is this a (possibly incomplete) ValSpec? | ||
@@ -117,4 +119,11 @@ if (null != spec && ((_a = spec.$) === null || _a === void 0 ? void 0 : _a.gubu$)) { | ||
} | ||
else if (spec.gubu === GUBU || true === ((_d = spec.$) === null || _d === void 0 ? void 0 : _d.gubu)) { | ||
let gs = (spec === null || spec === void 0 ? void 0 : spec.spec) ? spec.spec() : spec; | ||
t = gs.t; | ||
v = gs.v; | ||
r = gs.r; | ||
u = gs.u; | ||
} | ||
else if ((undefined === spec.prototype && Function === spec.constructor) || | ||
Function === ((_d = spec.prototype) === null || _d === void 0 ? void 0 : _d.constructor)) { | ||
Function === ((_e = spec.prototype) === null || _e === void 0 ? void 0 : _e.constructor)) { | ||
t = 'custom'; | ||
@@ -126,3 +135,3 @@ b = v; | ||
r = true; | ||
u.n = (_f = (_e = v.prototype) === null || _e === void 0 ? void 0 : _e.constructor) === null || _f === void 0 ? void 0 : _f.name; | ||
u.n = (_g = (_f = v.prototype) === null || _f === void 0 ? void 0 : _f.constructor) === null || _g === void 0 ? void 0 : _g.name; | ||
u.i = v; | ||
@@ -306,3 +315,3 @@ } | ||
if ('none' === t) { | ||
terr.push(makeErr('none', sval, path, dI, vs, 1070)); | ||
terr.push(makeErrImpl('none', sval, path, dI, vs, 1070)); | ||
} | ||
@@ -313,3 +322,3 @@ else if ('object' === t) { | ||
if (vs.r && undefined === sval) { | ||
terr.push(makeErr('required', sval, path, dI, vs, 1010)); | ||
terr.push(makeErrImpl('required', sval, path, dI, vs, 1010)); | ||
} | ||
@@ -322,3 +331,3 @@ else if ( | ||
// console.log('SVAL Q') | ||
terr.push(makeErr('type', sval, path, dI, vs, 1020)); | ||
terr.push(makeErrImpl('type', sval, path, dI, vs, 1020)); | ||
} | ||
@@ -335,7 +344,7 @@ else { | ||
if (vs.r && undefined === sval) { | ||
terr.push(makeErr('required', sval, path, dI, vs, 1030)); | ||
terr.push(makeErrImpl('required', sval, path, dI, vs, 1030)); | ||
} | ||
// else if (null != sval && !Array.isArray(sval)) { | ||
else if (undefined !== sval && !Array.isArray(sval)) { | ||
terr.push(makeErr('type', sval, path, dI, vs, 1040)); | ||
terr.push(makeErrImpl('type', sval, path, dI, vs, 1040)); | ||
} | ||
@@ -365,3 +374,3 @@ else { | ||
{ | ||
terr.push(makeErr('type', sval, path, dI, vs, 1050)); | ||
terr.push(makeErrImpl('type', sval, path, dI, vs, 1050)); | ||
pass = false; | ||
@@ -372,3 +381,3 @@ } | ||
if (vs.r) { | ||
terr.push(makeErr('required', sval, path, dI, vs, 1060)); | ||
terr.push(makeErrImpl('required', sval, path, dI, vs, 1060)); | ||
pass = false; | ||
@@ -381,2 +390,12 @@ } | ||
} | ||
// Empty strings fail if string is required. Use Empty to allow. | ||
else if ('string' === t && '' === sval) { | ||
if (vs.r && !vs.u.empty) { | ||
terr.push(makeErrImpl('required', sval, path, dI, vs, 1080)); | ||
} | ||
// Optional empty strings take the default, unless Empty allows. | ||
else if (!vs.u.empty) { | ||
src[key] = vs.v; | ||
} | ||
} | ||
} | ||
@@ -457,2 +476,3 @@ if (vs.a) { | ||
}; | ||
gubuShape.gubu = GUBU; | ||
return gubuShape; | ||
@@ -479,3 +499,3 @@ } | ||
else { | ||
state.terr.push(makeErr(w, sval, state.path, state.dI, state.node, 1040)); | ||
state.terr.push(makeErrImpl(w, sval, state.path, state.dI, state.node, 1040)); | ||
} | ||
@@ -503,2 +523,8 @@ update.pass = false; | ||
exports.Optional = Optional; | ||
const Empty = function (spec) { | ||
let vs = buildize(this || spec); | ||
vs.u.empty = true; | ||
return vs; | ||
}; | ||
exports.Empty = Empty; | ||
// Optional value provides default. | ||
@@ -537,5 +563,2 @@ const Any = function (spec) { | ||
exports.One = One; | ||
// Pass if some match, but always check each one - does *not* short circuit. | ||
const Some = makeListBuilder('some'); | ||
exports.Some = Some; | ||
// Pass only if all match. Short circuits. | ||
@@ -581,3 +604,3 @@ const All = makeListBuilder('all'); | ||
update.err = | ||
makeErr('closed', val, state.path, state.dI, vs, 3010, '', { k }); | ||
makeErrImpl('closed', val, state.path, state.dI, vs, 3010, '', { k }); | ||
return false; | ||
@@ -653,16 +676,25 @@ } | ||
return Object.assign(vs, { | ||
Required, | ||
Optional, | ||
After, | ||
All, | ||
Any, | ||
Before, | ||
Closed, | ||
Before, | ||
After, | ||
Define, | ||
Empty, | ||
None, | ||
One, | ||
Optional, | ||
Refer, | ||
Rename, | ||
Required, | ||
}); | ||
} | ||
exports.buildize = buildize; | ||
function gubuError(val, state, text, why) { | ||
return makeErr(why || 'custom', val, state.path, state.dI, state.node, 4000, text); | ||
// External utility to make ErrDesc objects. | ||
function makeErr(val, state, text, why) { | ||
return makeErrImpl(why || 'custom', val, state.path, state.dI, state.node, 4000, text); | ||
} | ||
exports.gubuError = gubuError; | ||
function makeErr(why, sval, path, dI, node, mark, text, user, fname) { | ||
exports.makeErr = makeErr; | ||
// Internal utility to make ErrDesc objects. | ||
function makeErrImpl(why, sval, path, dI, node, mark, text, user, fname) { | ||
let err = { | ||
@@ -723,8 +755,9 @@ n: node, | ||
Define, | ||
Empty, | ||
None, | ||
One, | ||
Optional, | ||
Refer, | ||
Rename, | ||
Required, | ||
Some, | ||
}); | ||
@@ -734,4 +767,4 @@ Object.defineProperty(make, 'name', { value: 'gubu' }); | ||
exports.G$ = G$; | ||
const gubu = make; | ||
exports.gubu = gubu; | ||
const Gubu = make; | ||
exports.Gubu = Gubu; | ||
const GAfter = After; | ||
@@ -749,2 +782,4 @@ exports.GAfter = GAfter; | ||
exports.GDefine = GDefine; | ||
const GEmpty = Empty; | ||
exports.GEmpty = GEmpty; | ||
const GNone = None; | ||
@@ -762,4 +797,2 @@ exports.GNone = GNone; | ||
exports.GRequired = GRequired; | ||
const GSome = Some; | ||
exports.GSome = GSome; | ||
//# sourceMappingURL=gubu.js.map |
104
gubu.ts
@@ -1,2 +0,2 @@ | ||
/* Copyright (c) 2021 Richard Rodger, MIT License */ | ||
/* Copyright (c) 2021 Richard Rodger and other contributors, MIT License */ | ||
@@ -7,4 +7,7 @@ /* | ||
// TODO: custom undefined handling? | ||
// TODO: closed on array | ||
// TODO: composable? | ||
// TODO: function deref? | ||
// TODO: test Some, or drop? | ||
// TODO: BigInt spec roundtrip test | ||
@@ -235,2 +238,9 @@ // TODO: Only - builder, exact values | ||
} | ||
else if (spec.gubu === GUBU || true === spec.$?.gubu) { | ||
let gs = spec?.spec ? spec.spec() : spec | ||
t = (gs as ValSpec).t | ||
v = gs.v | ||
r = gs.r | ||
u = gs.u | ||
} | ||
else if ( | ||
@@ -466,3 +476,3 @@ (undefined === spec.prototype && Function === spec.constructor) || | ||
if ('none' === t) { | ||
terr.push(makeErr('none', sval, path, dI, vs, 1070)) | ||
terr.push(makeErrImpl('none', sval, path, dI, vs, 1070)) | ||
} | ||
@@ -474,3 +484,3 @@ else if ('object' === t) { | ||
if (vs.r && undefined === sval) { | ||
terr.push(makeErr('required', sval, path, dI, vs, 1010)) | ||
terr.push(makeErrImpl('required', sval, path, dI, vs, 1010)) | ||
} | ||
@@ -487,3 +497,3 @@ else if ( | ||
// console.log('SVAL Q') | ||
terr.push(makeErr('type', sval, path, dI, vs, 1020)) | ||
terr.push(makeErrImpl('type', sval, path, dI, vs, 1020)) | ||
} | ||
@@ -501,7 +511,7 @@ else { | ||
if (vs.r && undefined === sval) { | ||
terr.push(makeErr('required', sval, path, dI, vs, 1030)) | ||
terr.push(makeErrImpl('required', sval, path, dI, vs, 1030)) | ||
} | ||
// else if (null != sval && !Array.isArray(sval)) { | ||
else if (undefined !== sval && !Array.isArray(sval)) { | ||
terr.push(makeErr('type', sval, path, dI, vs, 1040)) | ||
terr.push(makeErrImpl('type', sval, path, dI, vs, 1040)) | ||
} | ||
@@ -535,3 +545,3 @@ else { | ||
{ | ||
terr.push(makeErr('type', sval, path, dI, vs, 1050)) | ||
terr.push(makeErrImpl('type', sval, path, dI, vs, 1050)) | ||
pass = false | ||
@@ -543,3 +553,3 @@ } | ||
if (vs.r) { | ||
terr.push(makeErr('required', sval, path, dI, vs, 1060)) | ||
terr.push(makeErrImpl('required', sval, path, dI, vs, 1060)) | ||
pass = false | ||
@@ -552,2 +562,13 @@ } | ||
} | ||
// Empty strings fail if string is required. Use Empty to allow. | ||
else if ('string' === t && '' === sval) { | ||
if (vs.r && !vs.u.empty) { | ||
terr.push(makeErrImpl('required', sval, path, dI, vs, 1080)) | ||
} | ||
// Optional empty strings take the default, unless Empty allows. | ||
else if (!vs.u.empty) { | ||
src[key] = vs.v | ||
} | ||
} | ||
} | ||
@@ -641,2 +662,5 @@ | ||
gubuShape.gubu = GUBU | ||
return gubuShape | ||
@@ -668,3 +692,3 @@ } | ||
else { | ||
state.terr.push(makeErr( | ||
state.terr.push(makeErrImpl( | ||
w, sval, state.path, state.dI, state.node, 1040)) | ||
@@ -698,3 +722,10 @@ } | ||
const Empty: Builder = function(this: ValSpec, spec?: any) { | ||
let vs = buildize(this || spec) | ||
vs.u.empty = true | ||
return vs | ||
} | ||
// Optional value provides default. | ||
@@ -739,5 +770,2 @@ const Any: Builder = function(this: ValSpec, spec?: any) { | ||
// Pass if some match, but always check each one - does *not* short circuit. | ||
const Some: Builder = makeListBuilder('some') | ||
// Pass only if all match. Short circuits. | ||
@@ -792,3 +820,3 @@ const All: Builder = makeListBuilder('all') | ||
update.err = | ||
makeErr('closed', val, state.path, state.dI, vs, 3010, '', { k }) | ||
makeErrImpl('closed', val, state.path, state.dI, vs, 3010, '', { k }) | ||
return false | ||
@@ -890,8 +918,15 @@ } | ||
return Object.assign(vs, { | ||
Required, | ||
Optional, | ||
After, | ||
All, | ||
Any, | ||
Before, | ||
Closed, | ||
Before, | ||
After, | ||
Define, | ||
Empty, | ||
None, | ||
One, | ||
Optional, | ||
Refer, | ||
Rename, | ||
Required, | ||
}) | ||
@@ -901,4 +936,5 @@ } | ||
function gubuError(val: any, state: State, text?: string, why?: string) { | ||
return makeErr( | ||
// External utility to make ErrDesc objects. | ||
function makeErr(val: any, state: State, text?: string, why?: string) { | ||
return makeErrImpl( | ||
why || 'custom', | ||
@@ -914,3 +950,5 @@ val, | ||
function makeErr( | ||
// Internal utility to make ErrDesc objects. | ||
function makeErrImpl( | ||
why: string, | ||
@@ -987,3 +1025,6 @@ sval: any, | ||
(<T>(inroot?: T, inctx?: any) => T) & | ||
{ spec: () => any } | ||
{ | ||
spec: () => any, | ||
gubu: typeof GUBU | ||
} | ||
@@ -998,8 +1039,9 @@ | ||
Define, | ||
Empty, | ||
None, | ||
One, | ||
Optional, | ||
Refer, | ||
Rename, | ||
Required, | ||
Some, | ||
}) | ||
@@ -1017,2 +1059,3 @@ | ||
Define: typeof Define | ||
Empty: typeof Empty | ||
None: typeof None | ||
@@ -1024,3 +1067,2 @@ One: typeof One | ||
Required: typeof Required | ||
Some: typeof Some | ||
} | ||
@@ -1034,3 +1076,3 @@ | ||
const gubu: Gubu = (make as Gubu) | ||
const Gubu: Gubu = (make as Gubu) | ||
@@ -1044,2 +1086,3 @@ | ||
const GDefine = Define | ||
const GEmpty = Empty | ||
const GNone = None | ||
@@ -1051,6 +1094,4 @@ const GOne = One | ||
const GRequired = Required | ||
const GSome = Some | ||
export type { | ||
@@ -1066,7 +1107,7 @@ Validate, | ||
export { | ||
gubu, | ||
Gubu, | ||
G$, | ||
norm, | ||
buildize, | ||
gubuError, | ||
makeErr, | ||
@@ -1079,2 +1120,3 @@ After, | ||
Define, | ||
Empty, | ||
None, | ||
@@ -1086,3 +1128,2 @@ One, | ||
Required, | ||
Some, | ||
@@ -1095,2 +1136,3 @@ GAfter, | ||
GDefine, | ||
GEmpty, | ||
GNone, | ||
@@ -1102,6 +1144,4 @@ GOne, | ||
GRequired, | ||
GSome, | ||
} | ||
{ | ||
"name": "gubu", | ||
"version": "0.0.2", | ||
"description": "gubu", | ||
"version": "0.0.3", | ||
"description": "An object shape validation utility.", | ||
"main": "gubu.js", | ||
@@ -38,8 +38,7 @@ "type": "commonjs", | ||
"@types/jest": "^27.0.3", | ||
"jest": "^27.4.3", | ||
"jest": "^27.4.5", | ||
"ts-jest": "^27.1.1", | ||
"typescript": "^4.5.2", | ||
"jsonic": "github:jsonicjs/jsonic#nextgen" | ||
"typescript": "^4.5.4" | ||
}, | ||
"dependencies": {} | ||
} |
231
README.md
@@ -1,2 +0,229 @@ | ||
# gubu | ||
gubu | ||
# Gubu: An object shape validation utility. | ||
NOTE: WORK IN PROGRESS | ||
This is a schema validator in the tradition of [Joi](https://joi.dev) or any JSON-Schema validator, with the key features: | ||
* Schemas are WYSIWYG - you define a schema with a template matching your object strucure; | ||
* Covers the most useful cases in a natural way - in particular, defaults are specified directly and the type is inferred from the default; | ||
* Very light and easily extensible. | ||
Why write yet another validator? I've used `Joi` for a long time, but | ||
always found its schema definition a little verbose at the syntax | ||
level. I've never liked JSON-Schema - it's just too noisy to | ||
eyeball. What I do like is [Vue.js property | ||
validation](https://vuejs.org/v2/guide/components-props.html#Prop-Validation), | ||
but that only works at the top level. | ||
I needed this validator for two cases: adding message validation to | ||
the [Seneca microservices framework](https://senecajs.org), and | ||
providing deep defaults for complex custom Vue.js components. | ||
[![npm version](https://img.shields.io/npm/v/gubu.svg)](https://npmjs.com/package/gubu) | ||
[![build](https://github.com/rjrodger/gubu/actions/workflows/build.yml/badge.svg)](https://github.com/rjrodger/gubu/actions/workflows/build.yml) | ||
[![Coverage Status](https://coveralls.io/repos/github/rjrodger/gubu/badge.svg?branch=main)](https://coveralls.io/github/rjrodger/gubu?branch=main) | ||
[![Known Vulnerabilities](https://snyk.io/test/github/rjrodger/gubu/badge.svg)](https://snyk.io/test/github/rjrodger/gubu) | ||
[![DeepScan grade](https://deepscan.io/api/teams/5016/projects/19459/branches/505694/badge/grade.svg)](https://deepscan.io/dashboard#view=project&tid=5016&pid=19459&bid=505694) | ||
[![Maintainability](https://api.codeclimate.com/v1/badges/ee603417bbb953d35ebe/maintainability)](https://codeclimate.com/github/rjrodger/gubu/maintainability) | ||
| ![Voxgig](https://www.voxgig.com/res/img/vgt01r.png) | This open source module is sponsored and supported by [Voxgig](https://www.voxgig.com). | | ||
|---|---| | ||
## Quick Example | ||
```js | ||
const { Gubu } = require('gubu') | ||
// Property a is optional, must be a Number, and defaults to 1. | ||
// Property b is required, and must be a String. | ||
const shape = Gubu({ a: 1, b: String }) | ||
// Object shape is good! Prints `{ a: 99, b: 'foo' }` | ||
console.log( shape({ a: 99, b: 'foo' }) ) | ||
// Object shape is also good. Prints `{ a: 1, b: 'foo' }` | ||
console.log( shape({ b: 'foo' }) ) | ||
// Object shape is bad. Throws an exception: | ||
// "TODO: msg" | ||
console.log( shape({ a: 'BAD' }) ) | ||
``` | ||
Use the exported `Gubu` function to create a validation function that | ||
checks the first argument for validity - does it match the schema shape? | ||
## Install | ||
```sh | ||
$ npm install gubu | ||
``` | ||
## Usage | ||
The *Gubu* module has no dependencies. A single function named `Gubu` is exported. | ||
### TypeScript | ||
*Gubu* is written in TypeScript, and can be imported naturally: | ||
``` | ||
import { Gubu } from 'gubu' | ||
``` | ||
### Browser | ||
TODO | ||
### Shape Rules | ||
The general principle is that the schema shape should match valid | ||
object as closely as possible. | ||
For scalar values you can provide a native type object to make the value required: | ||
* `Gubu(String)` matches strings: `'foo'` | ||
* `Gubu(Number)` matches numbers: `123` | ||
* `Gubu(Boolean)` matches booleans: `true` | ||
Empty strings are not considered to be valid if a string is required | ||
(this is usually what you want). To allow empty string, use | ||
`Gubu(Empty(String))` (where `Empty` is exported by the `Gubu` module). | ||
Or defaults to make the value optional: | ||
* `Gubu('bar')` matches strings: `'foo'`, and `undefined` (becoming `'bar'`), but not `null` | ||
* `Gubu(0)` matches numbers: `123`, and `undefined` (becoming `0`), but not `null` | ||
* `Gubu(false)` matches booleans: `true`, and `undefined` (becoming `false`), but not `null` | ||
The values `null` and `NaN` must match exactly. The value `undefined` | ||
is special - it literally means no value. | ||
For objects, write them as you want them: | ||
``` | ||
let shape = Gubu({ | ||
foo: { | ||
bar: { | ||
zed: String, | ||
qaz: Number, | ||
} | ||
} | ||
}) | ||
``` | ||
For arrays, the first elements is treated as the shape that all elements must match: | ||
* `Gubu([String])` matches `['a', 'b', 'c']` | ||
* `Gubu([{x:1}])` matches `[{x: 11}, {x: 22}, {x: 33}]` | ||
Elements after the first are treated a special cases, defined specific | ||
shapes for each element (offset by 1): | ||
* `Gubu([String,Number])` matches `[1, 'b', 'c']` - the first element is a `Number`, the rest `Strings`. | ||
You can specify custom validation using functions: | ||
* `Gubu({a: (v) => 10<v })`: matches `{a: 11}` as `10 < 11` | ||
And you can manipulate the value if you need to: | ||
* `Gubu({a: (v,u) => 10<v ? (u.val=2*v, true) : false })`: matches `{a: 11}` as `10 < 11` and returns `{a: 22}`. | ||
You can also compose validations together: | ||
``` | ||
const shape = Gubu({ a: Gubu({ x: Number }) }) | ||
// Matches { a: { x: 1 } } as expected | ||
shape({ a: { x: 1 } }) | ||
``` | ||
*Gubu* exports shape "builder" utility functions that let you further | ||
refine the shape (You've already seen the `Empty` builder above that | ||
allows strings to be empty). Wrap your value with the function | ||
in-place in the shape. | ||
The `Required` builder makes a value required: | ||
``` | ||
const { Gubu, Required } = require(`gubu`) | ||
const shape = Gubu({ | ||
a: Required({x: 1}) // Property `a` is required and must match `{x: 1}`. | ||
}) | ||
``` | ||
The `Closed` builder prohibits an object from having additional unspecified properties: | ||
``` | ||
const { Gubu, Closed } = require(`gubu`) | ||
// Only properties `a` and `b` are allowed. | ||
const shape = Gubu(Closed({ | ||
a: 1, | ||
b: true | ||
})) | ||
``` | ||
You can access builders as properties of the main `Gubu` function to | ||
keep them namespaced. You can also chain most builders. Thus a | ||
required, closed object can be specificied with: | ||
``` | ||
const { Gubu } = require(`gubu`) | ||
const shape = Gubu({ | ||
a: Gubu.Closed({ x: 1 }).Required(), | ||
b: Gubu.Required({ x: 1 }).Closed(), // Also works. | ||
}) | ||
``` | ||
You can also write your own builders - see the [API Builders](#builders) section. | ||
In addition to this README, the [unit tests](lib/gubu.test.ts) are | ||
comprehensive and provide many usage examples. | ||
## API | ||
### Builders | ||
## Credits | ||
## GUBU | ||
The name comes from a sort of in-joke in Irish politics. It is | ||
[grotesque, unbelievable, bizarre and | ||
unprecedented](https://en.wikipedia.org/wiki/GUBU), that anyone would | ||
write yet another validation library for JavaSCript, let alone a | ||
second one (The first one I wrote is | ||
[parambulator](https://github.com/rjrodger/parambulator)). | ||
Also I like short names. | ||
## License | ||
Copyright (c) 2021, Richard Rodger and other contributors. | ||
Licensed under [MIT][]. | ||
[MIT]: ./LICENSE | ||
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
92516
4
1810
230
0