Skip to content

Commit

Permalink
Adding Schema.or().
Browse files Browse the repository at this point in the history
  • Loading branch information
seanmorris committed Sep 5, 2024
1 parent 7ad2bcf commit 3b9272c
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 10 deletions.
42 changes: 36 additions & 6 deletions Schema.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import Dict from './Dict.mjs';
const Schema = {
/**
* Map one or more values to a Tuple.
* Will append additional properties as plain values if more values are provided than appear in the schema.
* Will append additional properties as unmapped values if more values are provided than appear in the schema.
* @param {...SchemaMapper} schema A list of SchemaMappers
*/
tuple(...schema)
Expand All @@ -40,7 +40,7 @@ const Schema = {

/**
* Map one or more values to a Group.
* Will append additional properties as plain values if more values are provided than appear in the schema.
* Will append additional properties as unmapped values if more values are provided than appear in the schema.
* @param {...SchemaMapper} schema A list of SchemaMappers
*/
group(...schema)
Expand All @@ -54,6 +54,7 @@ const Schema = {

/**
* Map an object to a Record.
* Will append additional properties as unmapped values if more values are provided than appear in the schema.
* @param {Object.<string, SchemaMapper>} schema - An Object holding SchemaMappers
*/
record(schema = {})
Expand All @@ -68,6 +69,7 @@ const Schema = {

/**
* Map an object to a Record.
* Will append additional properties as unmapped values if more values are provided than appear in the schema.
* @param {Object.<string, SchemaMapper>} schema - An Object holding SchemaMappers
*/
dict(schema = {})
Expand All @@ -82,7 +84,7 @@ const Schema = {

/**
* Map n values to a Tuple.
* Will append each value in the input to the Tuple
* Will append each value in the input to the Tuple using the same mapper.
* @param {SchemaMapper} schema - A SchemaMapper
*/
nTuple(schema)
Expand All @@ -99,7 +101,7 @@ const Schema = {

/**
* Map n values to a Group.
* Will append each value in the input to the Group
* Will append each value in the input to the Group using the same mapper.
* @param {SchemaMapper} schema - A list of SchemaMappers
*/
nGroup(schema)
Expand All @@ -116,6 +118,7 @@ const Schema = {

/**
* Map n keys to a Record.
* Will append each value in the input to the Record using the same mapper.
* @param {Object.<string, SchemaMapper>} schema - An Object holding SchemaMappers
*/
nRecord(schema)
Expand All @@ -130,6 +133,7 @@ const Schema = {

/**
* Map n keys to a Dict.
* Will append each value in the input to the Dict using the same mapper.
* @param {Object.<string, SchemaMapper>} schema - An Object holding SchemaMappers
*/
nDict(schema)
Expand Down Expand Up @@ -444,7 +448,7 @@ const Schema = {
* @param {function(any):boolean} options.check Throw a TypeError if this returns false.
* @param {function(any):class} options.class Throw a TypeError if the class does not match.
* @param {function(any):any} options.map Transform the object after its been validated.
* @param {function(any):each} options.each Transform each entry in the object, after its been validated..
* @param {function(any):each} options.each Transform each entry in the object, after its been validated.
*/
object(options = {})
{
Expand Down Expand Up @@ -580,13 +584,39 @@ const Schema = {
},

/**
* Drop the value
* Drop the value (always maps to `undefined`)
*/
drop()
{
return () => undefined;
},

/**
* Map the value with the first matching SchemaMapper
* @param {...function(options):value} mappers
*/
or(...mappers)
{
return (value, path) => {
const errors = [];
for(const mapper of mappers)
{
try
{
return mapper(value, path);
}
catch(error)
{
errors.push(error);
}
}

const multi = new Error(errors.map(e => e.message).join(", "));
multi.errors = errors;
throw multi;
};
},

/**
* Repeat a SchemaMapper n times
* @param {number} n The number of times to repeat.
Expand Down
38 changes: 34 additions & 4 deletions test/schema.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,34 @@ test('dateSchema test', t => {
assert.throws(() => dateSchema(new Event('something')), 'SchemaMapper should throw errors on bad value.');
});

test('s.or test', t => {
const schema = s.or(s.boolean(), s.string());
assert.strictEqual(s.parse(schema, false), false);
assert.strictEqual(s.parse(schema, true), true);

assert.strictEqual(s.parse(schema, ""), "");
assert.strictEqual(s.parse(schema, "string"), "string");

assert.throws(() => schema(321), 'SchemaMapper should throw errors on bad value.');
assert.throws(() => schema({}), 'SchemaMapper should throw errors on bad value.');
});

test('s.or param test', t => {
const schema = s.or(
s.string({match: /\d\d \w+ \d\d\d\d \d\d:\d\d:\d\d \w+?/})
, s.object({class: Date})
);

const dateObject = new Date;
const dateString = '04 Apr 1995 00:12:00 GMT';

assert.strictEqual(s.parse(schema, dateObject), dateObject);
assert.strictEqual(s.parse(schema, dateString), dateString);

assert.throws(() => schema([]), 'SchemaMapper should throw errors on bad value.');
assert.throws(() => schema("bad string"), 'SchemaMapper should throw errors on bad value.');
});

test('usersSchema test', t => {
const usersSchema = s.sTuple(
...s.repeat(10, s.sRecord({
Expand All @@ -118,8 +146,8 @@ test('usersSchema test', t => {
city: s.string(),
zipcode: s.string({match: /\d{5}(-\d{4})?/, map: s => Tuple(...s.split('-'))}),
geo: s.sRecord({
lat: s.value({map: Number}),
lng: s.value({map: Number}),
lat: s.string({map: Number}),
lng: s.string({map: Number}),
}),
}),
phone: s.string({map: s => Tuple(...s.split(/\W+/).filter(x => x))}),
Expand All @@ -132,10 +160,12 @@ test('usersSchema test', t => {
}))
);

const usersA = usersSchema(users);
const usersB = usersSchema(users);
const usersA = usersSchema(JSON.parse(JSON.stringify(users)));
const usersB = usersSchema(JSON.parse(JSON.stringify(users)));

assert.strictEqual(usersA, usersB);
assert.strictEqual(usersA[0], usersB[0]);
assert.strictEqual(usersA[9], usersB[9]);

assert.notEqual(usersA[0], usersB[1]);
});

0 comments on commit 3b9272c

Please sign in to comment.