Comparing version 0.17.3 to 0.18.0
@@ -10,23 +10,35 @@ declare module 'optimal/lib/isObject' { | ||
} | ||
export type Checker = (path: string, value: any, ...args: any[]) => void; | ||
export type CustomCallback = (value: any, options: Options) => void; | ||
export interface Options { | ||
[key: string]: any; | ||
export type CheckerCallback = (path: string, value: any, ...args: any[]) => void; | ||
export type CustomCallback = (value: any, struct: Struct) => void; | ||
export interface Struct<T = any> { | ||
[key: string]: T; | ||
} | ||
export interface OptimalOptions extends Options { | ||
export interface OptimalOptions extends Struct { | ||
name?: string; | ||
unknown?: boolean; | ||
} | ||
export type SupportedType = 'array' | 'boolean' | 'function' | 'instance' | 'number' | 'object' | 'shape' | 'string' | 'union' | 'custom'; | ||
export enum SupportedType { | ||
Array = "array", | ||
Boolean = "boolean", | ||
Custom = "custom", | ||
Function = "function", | ||
Instance = "instance", | ||
Number = "number", | ||
Object = "object", | ||
Shape = "shape", | ||
String = "string", | ||
Union = "union", | ||
Unknown = "unknown", | ||
} | ||
} | ||
declare module 'optimal/lib/Builder' { | ||
import { SupportedType, Checker, CustomCallback, Options, OptimalOptions } from 'optimal/lib/types'; | ||
import { SupportedType, CheckerCallback, CustomCallback, OptimalOptions, Struct } from 'optimal/lib/types'; | ||
export interface Check { | ||
args: any[]; | ||
callback: Checker; | ||
callback: CheckerCallback; | ||
} | ||
export default class Builder<T> { | ||
checks: Check[]; | ||
currentOptions: Options; | ||
currentStruct: Struct; | ||
defaultValue: T; | ||
@@ -37,6 +49,6 @@ deprecatedMessage: string; | ||
isRequired: boolean; | ||
optimalOptions: OptimalOptions; | ||
options: OptimalOptions; | ||
type: SupportedType; | ||
constructor(type: SupportedType, defaultValue: T); | ||
addCheck(checker: Checker, ...args: any[]): this; | ||
addCheck(checker: CheckerCallback, ...args: any[]): this; | ||
and(...keys: string[]): this; | ||
@@ -57,3 +69,3 @@ checkAnd(path: string, value: any, otherKeys: string[]): void; | ||
required(state?: boolean): this; | ||
runChecks(path: string, initialValue: any, options: Options, optimalOptions?: OptimalOptions): any; | ||
runChecks(path: string, initialValue: any, struct: Struct, options?: OptimalOptions): any; | ||
typeAlias(): string; | ||
@@ -70,5 +82,6 @@ xor(...keys: string[]): this; | ||
import Builder from 'optimal/lib/Builder'; | ||
import { SupportedType } from 'optimal/lib/types'; | ||
export default class CollectionBuilder<T, TDefault> extends Builder<TDefault | null> { | ||
contents: Builder<T> | null; | ||
constructor(type: 'array' | 'object', contents?: Builder<T> | null, defaultValue?: TDefault | null); | ||
constructor(type: SupportedType.Array | SupportedType.Object, contents?: Builder<T> | null, defaultValue?: TDefault | null); | ||
checkContents(path: string, value: any, contents: Builder<T>): void; | ||
@@ -93,4 +106,4 @@ notEmpty(): this; | ||
declare module 'optimal/lib/optimal' { | ||
import { Blueprint, Options, OptimalOptions } from 'optimal/lib/types'; | ||
export default function optimal<T extends Options>(stagedOptions: Options, blueprint: Blueprint, options?: OptimalOptions): T; | ||
import { Blueprint, OptimalOptions, Struct } from 'optimal/lib/types'; | ||
export default function optimal<T extends Struct>(struct: Struct, blueprint: Blueprint, options?: OptimalOptions): T; | ||
@@ -180,8 +193,8 @@ } | ||
import UnionBuilder, { union } from 'optimal/lib/UnionBuilder'; | ||
import { Blueprint, Checker, CustomCallback, Options, OptimalOptions, SupportedType } from 'optimal/lib/types'; | ||
import { Blueprint, CheckerCallback, CustomCallback, OptimalOptions, Struct, SupportedType } from 'optimal/lib/types'; | ||
export { array, bool, custom, date, func, instance, number, object, regex, shape, string, union }; | ||
export { Builder, CollectionBuilder, InstanceBuilder, NumberBuilder, ShapeBuilder, StringBuilder, UnionBuilder }; | ||
export { Blueprint, Checker, CustomCallback, Options, OptimalOptions, SupportedType }; | ||
export { Blueprint, CheckerCallback, CustomCallback, OptimalOptions, Struct, SupportedType }; | ||
export default optimal; | ||
} |
@@ -7,6 +7,7 @@ "use strict"; | ||
var isObject_1 = __importDefault(require("./isObject")); | ||
var types_1 = require("./types"); | ||
var Builder = (function () { | ||
function Builder(type, defaultValue) { | ||
this.checks = []; | ||
this.currentOptions = {}; | ||
this.currentStruct = {}; | ||
this.deprecatedMessage = ''; | ||
@@ -16,3 +17,3 @@ this.errorMessage = ''; | ||
this.isRequired = false; | ||
this.optimalOptions = {}; | ||
this.options = {}; | ||
if (process.env.NODE_ENV !== 'production') { | ||
@@ -44,3 +45,3 @@ this.invariant(typeof defaultValue !== 'undefined', "A default value for type \"" + type + "\" is required."); | ||
if (process.env.NODE_ENV !== 'production') { | ||
this.invariant(keys.length > 0, 'AND requires a list of option names.'); | ||
this.invariant(keys.length > 0, 'AND requires a list of field names.'); | ||
} | ||
@@ -52,8 +53,8 @@ return this.addCheck(this.checkAnd, keys); | ||
var keys = [this.key(path)].concat(otherKeys); | ||
var options_1 = this.currentOptions; | ||
var undefs = keys.filter(function (key) { return typeof options_1[key] === 'undefined' || options_1[key] === null; }); | ||
var struct_1 = this.currentStruct; | ||
var undefs = keys.filter(function (key) { return typeof struct_1[key] === 'undefined' || struct_1[key] === null; }); | ||
if (undefs.length === keys.length) { | ||
return; | ||
} | ||
this.invariant(undefs.length === 0, "All of these options must be defined: " + keys.join(', ')); | ||
this.invariant(undefs.length === 0, "All of these fields must be defined: " + keys.join(', ')); | ||
} | ||
@@ -90,3 +91,3 @@ }; | ||
try { | ||
callback(value, this.currentOptions); | ||
callback(value, this.currentStruct); | ||
} | ||
@@ -111,10 +112,10 @@ catch (error) { | ||
} | ||
var name = this.optimalOptions.name; | ||
var name = this.options.name; | ||
var prefix = ''; | ||
if (path) { | ||
if (name) { | ||
prefix += "Invalid " + name + " option \"" + path + "\". "; | ||
prefix += "Invalid " + name + " field \"" + path + "\". "; | ||
} | ||
else { | ||
prefix += "Invalid option \"" + path + "\". "; | ||
prefix += "Invalid field \"" + path + "\". "; | ||
} | ||
@@ -163,3 +164,3 @@ } | ||
if (process.env.NODE_ENV !== 'production') { | ||
this.invariant(keys.length > 0, 'OR requires a list of option names.'); | ||
this.invariant(keys.length > 0, 'OR requires a list of field names.'); | ||
} | ||
@@ -171,5 +172,5 @@ return this.addCheck(this.checkOr, keys); | ||
var keys = [this.key(path)].concat(otherKeys); | ||
var options_2 = this.currentOptions; | ||
var defs = keys.filter(function (key) { return typeof options_2[key] !== 'undefined' && options_2[key] !== null; }); | ||
this.invariant(defs.length > 0, "At least one of these options must be defined: " + keys.join(', ')); | ||
var struct_2 = this.currentStruct; | ||
var defs = keys.filter(function (key) { return typeof struct_2[key] !== 'undefined' && struct_2[key] !== null; }); | ||
this.invariant(defs.length > 0, "At least one of these fields must be defined: " + keys.join(', ')); | ||
} | ||
@@ -184,7 +185,7 @@ }; | ||
}; | ||
Builder.prototype.runChecks = function (path, initialValue, options, optimalOptions) { | ||
Builder.prototype.runChecks = function (path, initialValue, struct, options) { | ||
var _this = this; | ||
if (optimalOptions === void 0) { optimalOptions = {}; } | ||
this.currentOptions = options; | ||
this.optimalOptions = optimalOptions; | ||
if (options === void 0) { options = {}; } | ||
this.currentStruct = struct; | ||
this.options = options; | ||
var value = initialValue; | ||
@@ -201,3 +202,3 @@ if (typeof value === 'undefined') { | ||
if (process.env.NODE_ENV !== 'production') { | ||
console.info("Option \"" + path + "\" is deprecated. " + this.deprecatedMessage); | ||
console.info("Field \"" + path + "\" is deprecated. " + this.deprecatedMessage); | ||
} | ||
@@ -230,3 +231,3 @@ } | ||
if (process.env.NODE_ENV !== 'production') { | ||
this.invariant(keys.length > 0, 'XOR requires a list of option names.'); | ||
this.invariant(keys.length > 0, 'XOR requires a list of field names.'); | ||
} | ||
@@ -238,5 +239,5 @@ return this.addCheck(this.checkXor, keys); | ||
var keys = [this.key(path)].concat(otherKeys); | ||
var options_3 = this.currentOptions; | ||
var defs = keys.filter(function (key) { return typeof options_3[key] !== 'undefined' && options_3[key] !== null; }); | ||
this.invariant(defs.length === 1, "Only one of these options may be defined: " + keys.join(', ')); | ||
var struct_3 = this.currentStruct; | ||
var defs = keys.filter(function (key) { return typeof struct_3[key] !== 'undefined' && struct_3[key] !== null; }); | ||
this.invariant(defs.length === 1, "Only one of these fields may be defined: " + keys.join(', ')); | ||
} | ||
@@ -249,3 +250,3 @@ }; | ||
if (defaultValue === void 0) { defaultValue = false; } | ||
return new Builder('boolean', defaultValue); | ||
return new Builder(types_1.SupportedType.Boolean, defaultValue); | ||
} | ||
@@ -255,3 +256,3 @@ exports.bool = bool; | ||
if (defaultValue === void 0) { defaultValue = null; } | ||
return new Builder('custom', defaultValue).custom(callback); | ||
return new Builder(types_1.SupportedType.Custom, defaultValue).custom(callback); | ||
} | ||
@@ -261,4 +262,4 @@ exports.custom = custom; | ||
if (defaultValue === void 0) { defaultValue = null; } | ||
return new Builder('function', defaultValue).nullable(); | ||
return new Builder(types_1.SupportedType.Function, defaultValue).nullable(); | ||
} | ||
exports.func = func; |
@@ -17,2 +17,3 @@ "use strict"; | ||
var Builder_1 = __importDefault(require("./Builder")); | ||
var types_1 = require("./types"); | ||
var CollectionBuilder = (function (_super) { | ||
@@ -43,3 +44,3 @@ __extends(CollectionBuilder, _super); | ||
value.forEach(function (item, i) { | ||
contents.runChecks(path + "[" + i + "]", item, _this.currentOptions, _this.optimalOptions); | ||
contents.runChecks(path + "[" + i + "]", item, _this.currentStruct, _this.options); | ||
}); | ||
@@ -49,3 +50,3 @@ } | ||
Object.keys(value).forEach(function (key) { | ||
contents.runChecks(path + "." + key, value[key], _this.currentOptions, _this.optimalOptions); | ||
contents.runChecks(path + "." + key, value[key], _this.currentStruct, _this.options); | ||
}); | ||
@@ -79,3 +80,3 @@ } | ||
if (defaultValue === void 0) { defaultValue = []; } | ||
return new CollectionBuilder('array', contents, defaultValue); | ||
return new CollectionBuilder(types_1.SupportedType.Array, contents, defaultValue); | ||
} | ||
@@ -86,4 +87,4 @@ exports.array = array; | ||
if (defaultValue === void 0) { defaultValue = {}; } | ||
return new CollectionBuilder('object', contents, defaultValue); | ||
return new CollectionBuilder(types_1.SupportedType.Object, contents, defaultValue); | ||
} | ||
exports.object = object; |
@@ -33,2 +33,4 @@ "use strict"; | ||
exports.union = UnionBuilder_1.union; | ||
var types_1 = require("./types"); | ||
exports.SupportedType = types_1.SupportedType; | ||
exports.default = optimal_1.default; |
@@ -18,2 +18,3 @@ "use strict"; | ||
var isObject_1 = __importDefault(require("./isObject")); | ||
var types_1 = require("./types"); | ||
var InstanceBuilder = (function (_super) { | ||
@@ -23,3 +24,3 @@ __extends(InstanceBuilder, _super); | ||
if (refClass === void 0) { refClass = null; } | ||
var _this = _super.call(this, 'instance', null) || this; | ||
var _this = _super.call(this, types_1.SupportedType.Instance, null) || this; | ||
_this.refClass = null; | ||
@@ -26,0 +27,0 @@ _this.nullable(); |
@@ -17,2 +17,3 @@ "use strict"; | ||
var Builder_1 = __importDefault(require("./Builder")); | ||
var types_1 = require("./types"); | ||
function isNumber(value) { | ||
@@ -25,3 +26,3 @@ return typeof value === 'number'; | ||
if (defaultValue === void 0) { defaultValue = 0; } | ||
return _super.call(this, 'number', defaultValue) || this; | ||
return _super.call(this, types_1.SupportedType.Number, defaultValue) || this; | ||
} | ||
@@ -28,0 +29,0 @@ NumberBuilder.prototype.between = function (min, max, inclusive) { |
@@ -17,7 +17,7 @@ "use strict"; | ||
var typeOf_1 = __importDefault(require("./typeOf")); | ||
function buildAndCheckOptions(stagedOptions, blueprint, options, parentPath) { | ||
function buildAndCheck(struct, blueprint, options, parentPath) { | ||
if (options === void 0) { options = {}; } | ||
if (parentPath === void 0) { parentPath = ''; } | ||
var unknownOptions = __assign({}, stagedOptions); | ||
var builtOptions = {}; | ||
var unknownFields = __assign({}, struct); | ||
var builtStruct = {}; | ||
Object.keys(blueprint).forEach(function (key) { | ||
@@ -27,28 +27,28 @@ var builder = blueprint[key]; | ||
if (builder instanceof Builder_1.default) { | ||
builtOptions[key] = builder.runChecks(path, stagedOptions[key], stagedOptions, options); | ||
builtStruct[key] = builder.runChecks(path, struct[key], struct, options); | ||
} | ||
else if (isObject_1.default(builder)) { | ||
builtOptions[key] = buildAndCheckOptions(stagedOptions[key] || {}, builder, options, path); | ||
builtStruct[key] = buildAndCheck(struct[key] || {}, builder, options, path); | ||
} | ||
else if (process.env.NODE_ENV !== 'production') { | ||
throw new Error('Unknown blueprint option. Must be a builder or plain object.'); | ||
throw new Error('Unknown blueprint. Must be a builder or plain object.'); | ||
} | ||
delete unknownOptions[key]; | ||
delete unknownFields[key]; | ||
}); | ||
if (options.unknown) { | ||
Object.assign(builtOptions, unknownOptions); | ||
Object.assign(builtStruct, unknownFields); | ||
} | ||
else if (process.env.NODE_ENV !== 'production') { | ||
var unknownKeys = Object.keys(unknownOptions); | ||
var unknownKeys = Object.keys(unknownFields); | ||
if (unknownKeys.length > 0) { | ||
throw new Error("Unknown options: " + unknownKeys.join(', ') + "."); | ||
throw new Error("Unknown fields: " + unknownKeys.join(', ') + "."); | ||
} | ||
} | ||
return builtOptions; | ||
return builtStruct; | ||
} | ||
function optimal(stagedOptions, blueprint, options) { | ||
function optimal(struct, blueprint, options) { | ||
if (options === void 0) { options = {}; } | ||
if (process.env.NODE_ENV !== 'production') { | ||
if (!isObject_1.default(stagedOptions)) { | ||
throw new TypeError("Options require a plain object, found " + typeOf_1.default(stagedOptions) + "."); | ||
if (!isObject_1.default(struct)) { | ||
throw new TypeError("Optimal requires a plain object, found " + typeOf_1.default(struct) + "."); | ||
} | ||
@@ -59,7 +59,7 @@ else if (!isObject_1.default(options)) { | ||
else if (!isObject_1.default(blueprint)) { | ||
throw new TypeError('An options blueprint is required.'); | ||
throw new TypeError('A blueprint is required.'); | ||
} | ||
} | ||
return buildAndCheckOptions(stagedOptions, blueprint, options); | ||
return buildAndCheck(struct, blueprint, options); | ||
} | ||
exports.default = optimal; |
@@ -18,2 +18,3 @@ "use strict"; | ||
var isObject_1 = __importDefault(require("./isObject")); | ||
var types_1 = require("./types"); | ||
var ShapeBuilder = (function (_super) { | ||
@@ -23,3 +24,3 @@ __extends(ShapeBuilder, _super); | ||
if (defaultValue === void 0) { defaultValue = {}; } | ||
var _this = _super.call(this, 'shape', defaultValue) || this; | ||
var _this = _super.call(this, types_1.SupportedType.Shape, defaultValue) || this; | ||
if (process.env.NODE_ENV !== 'production') { | ||
@@ -40,3 +41,3 @@ _this.invariant(isObject_1.default(contents) && | ||
(builder.isRequired || typeof object[key] !== 'undefined')) { | ||
builder.runChecks(path + "." + key, object[key], object, _this.optimalOptions); | ||
builder.runChecks(path + "." + key, object[key], object, _this.options); | ||
} | ||
@@ -43,0 +44,0 @@ }); |
@@ -17,2 +17,3 @@ "use strict"; | ||
var Builder_1 = __importDefault(require("./Builder")); | ||
var types_1 = require("./types"); | ||
function isString(value) { | ||
@@ -25,3 +26,3 @@ return typeof value === 'string' && value !== ''; | ||
if (defaultValue === void 0) { defaultValue = ''; } | ||
var _this = _super.call(this, 'string', defaultValue) || this; | ||
var _this = _super.call(this, types_1.SupportedType.String, defaultValue) || this; | ||
_this.allowEmpty = false; | ||
@@ -28,0 +29,0 @@ if (process.env.NODE_ENV !== 'production') { |
@@ -7,11 +7,25 @@ "use strict"; | ||
var isObject_1 = __importDefault(require("./isObject")); | ||
var types_1 = require("./types"); | ||
function typeOf(value) { | ||
if (Array.isArray(value)) { | ||
return 'array'; | ||
return value.every(function (item) { return typeof item === typeof value[0]; }) | ||
? types_1.SupportedType.Array | ||
: types_1.SupportedType.Union; | ||
} | ||
else if (isObject_1.default(value)) { | ||
return value.constructor === Object ? 'object' : 'instance'; | ||
if (isObject_1.default(value)) { | ||
return value.constructor === Object ? types_1.SupportedType.Object : types_1.SupportedType.Instance; | ||
} | ||
return typeof value; | ||
switch (typeof value) { | ||
case 'boolean': | ||
return types_1.SupportedType.Boolean; | ||
case 'function': | ||
return types_1.SupportedType.Function; | ||
case 'number': | ||
return types_1.SupportedType.Number; | ||
case 'string': | ||
return types_1.SupportedType.String; | ||
default: | ||
return types_1.SupportedType.Unknown; | ||
} | ||
} | ||
exports.default = typeOf; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var SupportedType; | ||
(function (SupportedType) { | ||
SupportedType["Array"] = "array"; | ||
SupportedType["Boolean"] = "boolean"; | ||
SupportedType["Custom"] = "custom"; | ||
SupportedType["Function"] = "function"; | ||
SupportedType["Instance"] = "instance"; | ||
SupportedType["Number"] = "number"; | ||
SupportedType["Object"] = "object"; | ||
SupportedType["Shape"] = "shape"; | ||
SupportedType["String"] = "string"; | ||
SupportedType["Union"] = "union"; | ||
SupportedType["Unknown"] = "unknown"; | ||
})(SupportedType = exports.SupportedType || (exports.SupportedType = {})); |
@@ -18,2 +18,3 @@ "use strict"; | ||
var typeOf_1 = __importDefault(require("./typeOf")); | ||
var types_1 = require("./types"); | ||
var UnionBuilder = (function (_super) { | ||
@@ -23,3 +24,3 @@ __extends(UnionBuilder, _super); | ||
if (defaultValue === void 0) { defaultValue = null; } | ||
var _this = _super.call(this, 'union', defaultValue) || this; | ||
var _this = _super.call(this, types_1.SupportedType.Union, defaultValue) || this; | ||
_this.builders = []; | ||
@@ -62,3 +63,3 @@ if (process.env.NODE_ENV !== 'production') { | ||
checked_1 = true; | ||
builder.runChecks(path, value, _this.currentOptions, _this.optimalOptions); | ||
builder.runChecks(path, value, _this.currentStruct, _this.options); | ||
} | ||
@@ -65,0 +66,0 @@ }); |
{ | ||
"name": "optimal", | ||
"version": "0.17.3", | ||
"description": "Options object builder and validator.", | ||
"version": "0.18.0", | ||
"description": "A system for building and validating defined object structures", | ||
"main": "./lib/index.js", | ||
@@ -13,2 +13,5 @@ "module": "./esm/index.js", | ||
"coverage": "yarn run jest --coverage", | ||
"docs": "gitbook build --debug", | ||
"docs:serve": "gitbook serve", | ||
"docs:install": "gitbook install", | ||
"eslint": "beemo eslint", | ||
@@ -19,3 +22,3 @@ "jest": "beemo jest", | ||
"prerelease": "yarn run package", | ||
"release": "np --yolo", | ||
"release": "np --yolo --no-yarn", | ||
"pretest": "yarn run type", | ||
@@ -38,3 +41,4 @@ "test": "yarn run jest", | ||
"object", | ||
"params" | ||
"params", | ||
"struct" | ||
], | ||
@@ -54,3 +58,3 @@ "author": { | ||
"devDependencies": { | ||
"@milesj/build-tool-config": "^0.78.0" | ||
"@milesj/build-tool-config": "^0.79.0" | ||
}, | ||
@@ -57,0 +61,0 @@ "beemo": { |
@@ -5,3 +5,5 @@ # Optimal | ||
Optimal, a system for building and validating options and configuration objects. | ||
A system for building and validating defined object structures, like argument options, configuration | ||
files, data bags, validation fields, and more! Runs checks in development, and strips checks in | ||
production using dead code elimination. | ||
@@ -13,8 +15,21 @@ * Recursively builds and validates nested structures. | ||
* Mark fields as nullable or required. | ||
* Utilize complex operators like AND, OR, and XOR. | ||
* Handles complex operators like AND, OR, and XOR. | ||
## Requirements | ||
* Node 6.5 (server) | ||
* IE 10+ (browser) | ||
## Installation | ||
``` | ||
yarn add optimal | ||
// OR | ||
npm install optimal --save | ||
``` | ||
## Documentation | ||
* [Options](#options) | ||
* [Blueprint](#predicate-blueprint) | ||
* [Optimal](#optimal) | ||
* [Blueprint](#blueprint) | ||
* [Customization](#customization) | ||
@@ -35,2 +50,2 @@ * [Predicates](#predicates) | ||
TODO | ||
Will write eventually... |
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
353583
1071
49