schemaglobin
Advanced tools
Comparing version 3.3.0 to 3.3.1
@@ -44,2 +44,3 @@ import { Schema, SchemaWithSchemas, SchemaOptions, SchemaType, NullIfOptional } from "../types"; | ||
* | ||
* - Recursive! Nested ObjectSchema instances are also partially validated. | ||
* - Props that don't appear in `options.props` are silently removed. | ||
@@ -50,3 +51,3 @@ * | ||
partialValidate(unsafeValue: unknown): Readonly<Partial<{ | ||
[K in keyof S]: SchemaType<S[K]>; | ||
[K in keyof S]: Partial<SchemaType<S[K]>>; | ||
}>> | NullIfOptional<R> | Invalid; | ||
@@ -53,0 +54,0 @@ schema<K extends keyof S & string>(key: K): S[K]; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const Invalid_1 = require("../Invalid"); | ||
// Whether we're in 'partial' mode or not. | ||
let partial = false; | ||
/** | ||
@@ -45,56 +47,28 @@ * Schema that defines a valid object. | ||
const invalids = {}; | ||
const entries = Object.entries(this.props); | ||
entries.forEach(([key, schema]) => { | ||
const unsafeProp = unsafeObj[key]; | ||
const safeProp = schema.validate(unsafeProp); | ||
if (safeProp instanceof Invalid_1.Invalid) { | ||
invalid = true; | ||
invalids[key] = safeProp.message; | ||
} | ||
else { | ||
if (safeProp !== unsafeProp) | ||
if (partial) { | ||
Object.entries(unsafeObj).forEach(([key, unsafeProp]) => { | ||
if (key in this.props) { | ||
// Known props: validate against schema. | ||
const schema = this.props[key]; | ||
const safeProp = schema.validate(unsafeProp); | ||
if (safeProp instanceof Invalid_1.Invalid) { | ||
invalid = true; | ||
invalids[key] = safeProp.message; | ||
} | ||
else { | ||
if (safeProp !== unsafeProp) | ||
changed = true; | ||
safeObj[key] = safeProp; | ||
} | ||
} | ||
else { | ||
// Unknown prop: needs to be stripped from the return. | ||
changed = true; | ||
safeObj[key] = safeProp; | ||
} | ||
}); | ||
// If input has keys that aren't in props, then these keys are _excess_ and we need to return output. | ||
if (Object.keys(unsafeObj).length > entries.length) | ||
changed = true; | ||
// If any Schema threw Invalid, return an Invalids. | ||
if (invalid) | ||
return new Invalid_1.Invalid("Invalid format", invalids); | ||
// Return immuatably (return output if changes were made, or exact input otherwise). | ||
return (changed ? safeObj : unsafeObj); | ||
} | ||
/** | ||
* Like `validate()` method but works on a Partial value. | ||
* e.g. Missing properties in the object don't cause Invalid to be thrown. | ||
* | ||
* - Props that don't appear in `options.props` are silently removed. | ||
* | ||
* @returns The valid partial value, or an Invalid summarising the issues. | ||
*/ | ||
partialValidate(unsafeValue) { | ||
// Coorce. | ||
const unsafeObj = this.coerce(unsafeValue); | ||
if (unsafeObj instanceof Invalid_1.Invalid) | ||
return unsafeObj; | ||
// Null means 'no object' | ||
if (unsafeObj === null) { | ||
// Check requiredness. | ||
if (this.required) | ||
return new Invalid_1.Invalid("Required"); | ||
// Return. | ||
// We know this type assertion is sound because `null` can never be returned if `this.required == true`. | ||
return null; | ||
} | ||
}); | ||
} | ||
// Check (partial) value against against `this.props` | ||
let changed = false; | ||
let invalid = false; | ||
const safeObj = {}; | ||
const invalids = {}; | ||
Object.entries(unsafeObj).forEach(([key, unsafeProp]) => { | ||
if (key in this.props) { | ||
// Known props: validate against schema. | ||
const schema = this.props[key]; | ||
else { | ||
const entries = Object.entries(this.props); | ||
entries.forEach(([key, schema]) => { | ||
const unsafeProp = unsafeObj[key]; | ||
const safeProp = schema.validate(unsafeProp); | ||
@@ -110,8 +84,7 @@ if (safeProp instanceof Invalid_1.Invalid) { | ||
} | ||
} | ||
else { | ||
// Unknown prop: needs to be stripped from the return. | ||
}); | ||
// If input has keys that aren't in props, then these keys are _excess_ and we need to return output. | ||
if (Object.keys(unsafeObj).length > entries.length) | ||
changed = true; | ||
} | ||
}); | ||
} | ||
// If any Schema threw Invalid, return an Invalids. | ||
@@ -123,2 +96,23 @@ if (invalid) | ||
} | ||
/** | ||
* Like `validate()` method but works on a Partial value. | ||
* e.g. Missing properties in the object don't cause Invalid to be thrown. | ||
* | ||
* - Recursive! Nested ObjectSchema instances are also partially validated. | ||
* - Props that don't appear in `options.props` are silently removed. | ||
* | ||
* @returns The valid partial value, or an Invalid summarising the issues. | ||
*/ | ||
partialValidate(unsafeValue) { | ||
try { | ||
partial = true; | ||
const value = this.validate(unsafeValue); | ||
partial = false; | ||
return value; | ||
} | ||
catch (err) { | ||
partial = false; | ||
throw err; | ||
} | ||
} | ||
// Implement SchemasSchema | ||
@@ -125,0 +119,0 @@ schema(key) { |
{ | ||
"name": "schemaglobin", | ||
"description": "Validate user-entered data.", | ||
"version": "3.3.0", | ||
"version": "3.3.1", | ||
"repository": "https://github.com/dhoulb/schemaglobin", | ||
@@ -6,0 +6,0 @@ "author": "Dave Houlbrooke <dave@shax.com>", |
@@ -14,2 +14,5 @@ import { Schema, SchemaWithSchemas, SchemaOptions, SchemaType, NullIfOptional } from "../types"; | ||
// Whether we're in 'partial' mode or not. | ||
let partial = false; | ||
/** | ||
@@ -79,17 +82,37 @@ * Schema that defines a valid object. | ||
const invalids: { [key: string]: string } = {}; | ||
const entries = Object.entries(this.props); | ||
entries.forEach(([key, schema]) => { | ||
const unsafeProp = unsafeObj[key]; | ||
const safeProp = schema.validate(unsafeProp); | ||
if (safeProp instanceof Invalid) { | ||
invalid = true; | ||
invalids[key] = safeProp.message; | ||
} else { | ||
if (safeProp !== unsafeProp) changed = true; | ||
safeObj[key] = safeProp; | ||
} | ||
}); | ||
if (partial) { | ||
Object.entries(unsafeObj).forEach(([key, unsafeProp]) => { | ||
if (key in this.props) { | ||
// Known props: validate against schema. | ||
const schema = this.props[key]; | ||
const safeProp = schema.validate(unsafeProp); | ||
if (safeProp instanceof Invalid) { | ||
invalid = true; | ||
invalids[key] = safeProp.message; | ||
} else { | ||
if (safeProp !== unsafeProp) changed = true; | ||
safeObj[key] = safeProp; | ||
} | ||
} else { | ||
// Unknown prop: needs to be stripped from the return. | ||
changed = true; | ||
} | ||
}); | ||
} else { | ||
const entries = Object.entries(this.props); | ||
entries.forEach(([key, schema]) => { | ||
const unsafeProp = unsafeObj[key]; | ||
const safeProp = schema.validate(unsafeProp); | ||
if (safeProp instanceof Invalid) { | ||
invalid = true; | ||
invalids[key] = safeProp.message; | ||
} else { | ||
if (safeProp !== unsafeProp) changed = true; | ||
safeObj[key] = safeProp; | ||
} | ||
}); | ||
// If input has keys that aren't in props, then these keys are _excess_ and we need to return output. | ||
if (Object.keys(unsafeObj).length > entries.length) changed = true; | ||
// If input has keys that aren't in props, then these keys are _excess_ and we need to return output. | ||
if (Object.keys(unsafeObj).length > entries.length) changed = true; | ||
} | ||
@@ -107,2 +130,3 @@ // If any Schema threw Invalid, return an Invalids. | ||
* | ||
* - Recursive! Nested ObjectSchema instances are also partially validated. | ||
* - Props that don't appear in `options.props` are silently removed. | ||
@@ -114,45 +138,12 @@ * | ||
unsafeValue: unknown, | ||
): Readonly<Partial<{ [K in keyof S]: SchemaType<S[K]> }>> | NullIfOptional<R> | Invalid { | ||
// Coorce. | ||
const unsafeObj = this.coerce(unsafeValue); | ||
if (unsafeObj instanceof Invalid) return unsafeObj; | ||
// Null means 'no object' | ||
if (unsafeObj === null) { | ||
// Check requiredness. | ||
if (this.required) return new Invalid("Required"); | ||
// Return. | ||
// We know this type assertion is sound because `null` can never be returned if `this.required == true`. | ||
return null as NullIfOptional<R>; | ||
): Readonly<Partial<{ [K in keyof S]: Partial<SchemaType<S[K]>> }>> | NullIfOptional<R> | Invalid { | ||
try { | ||
partial = true; | ||
const value = this.validate(unsafeValue); | ||
partial = false; | ||
return value; | ||
} catch (err) { | ||
partial = false; | ||
throw err; | ||
} | ||
// Check (partial) value against against `this.props` | ||
let changed = false; | ||
let invalid = false; | ||
const safeObj: { [key: string]: unknown } = {}; | ||
const invalids: { [key: string]: string } = {}; | ||
Object.entries(unsafeObj).forEach(([key, unsafeProp]) => { | ||
if (key in this.props) { | ||
// Known props: validate against schema. | ||
const schema = this.props[key]; | ||
const safeProp = schema.validate(unsafeProp); | ||
if (safeProp instanceof Invalid) { | ||
invalid = true; | ||
invalids[key] = safeProp.message; | ||
} else { | ||
if (safeProp !== unsafeProp) changed = true; | ||
safeObj[key] = safeProp; | ||
} | ||
} else { | ||
// Unknown prop: needs to be stripped from the return. | ||
changed = true; | ||
} | ||
}); | ||
// If any Schema threw Invalid, return an Invalids. | ||
if (invalid) return new Invalid("Invalid format", invalids); | ||
// Return immuatably (return output if changes were made, or exact input otherwise). | ||
return (changed ? safeObj : unsafeObj) as { [K in keyof S]: SchemaType<S[K]> }; | ||
} | ||
@@ -159,0 +150,0 @@ |
@@ -254,4 +254,43 @@ import { | ||
}), | ||
).toEqual({ num: 123, str: "abcdef" }); // Excess is removed. | ||
).toEqual({ | ||
num: 123, | ||
str: "abcdef", | ||
// excess is removed. | ||
}); | ||
}); | ||
test("Deeply nested objects are also partially validated", () => { | ||
const schema = object({ | ||
props: { | ||
num: new NumberSchema(), | ||
str: new StringSchema({ value: "abcdef" }), | ||
bool: new BooleanSchema(), | ||
obj: new ObjectSchema({ | ||
props: { | ||
num: new NumberSchema(), | ||
str: new StringSchema({ value: "abcdef" }), | ||
bool: new BooleanSchema(), | ||
}, | ||
}), | ||
}, | ||
}); | ||
expect( | ||
schema.partialValidate({ | ||
num: 123, | ||
str: "abcdef", | ||
obj: { | ||
num: 123, | ||
str: "abcdef", | ||
}, | ||
}), | ||
).toEqual({ | ||
num: 123, | ||
str: "abcdef", | ||
// bool is allowed to be missing. | ||
obj: { | ||
num: 123, | ||
str: "abcdef", | ||
// bool is allowed to be missing. | ||
}, | ||
}); | ||
}); | ||
test("Objects with unfixable errors in subschemas returns Invalids", () => { | ||
@@ -258,0 +297,0 @@ const schema = object({ |
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
4688
218004