Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: #473 make concat compatible with (not)oneOf #492

Merged
merged 2 commits into from
May 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 27 additions & 4 deletions src/mixed.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ class RefSet {
Ref.isRef(value) ? this.refs.set(value.key, value) : this.list.add(value);
}
delete(value) {
Ref.isRef(value)
? this.refs.delete(value.key, value)
: this.list.delete(value);
Ref.isRef(value) ? this.refs.delete(value.key) : this.list.delete(value);
}
has(value, resolve) {
if (this.list.has(value)) return true;
Expand All @@ -41,6 +39,20 @@ class RefSet {

return false;
}
clone() {
const next = new RefSet();
next.list = new Set(this.list);
next.refs = new Map(this.refs);
return next;
}
merge(newItems, removeItems) {
const next = this.clone();
newItems.list.forEach(value => next.add(value));
newItems.refs.forEach(value => next.add(value));
removeItems.list.forEach(value => next.delete(value));
removeItems.refs.forEach(value => next.delete(value));
return next;
}
}

export default function SchemaType(options = {}) {
Expand Down Expand Up @@ -115,12 +127,23 @@ const proto = (SchemaType.prototype = {

var next = prependDeep(schema.clone(), this);

// new undefined default is overriden by old non-undefined one, revert
// new undefined default is overridden by old non-undefined one, revert
if (has(schema, '_default')) next._default = schema._default;

next.tests = this.tests;
next._exclusive = this._exclusive;

// manually merge the blacklist/whitelist (the other `schema` takes
// precedence in case of conflicts)
next._whitelist = this._whitelist.merge(
schema._whitelist,
schema._blacklist,
);
next._blacklist = this._blacklist.merge(
schema._blacklist,
schema._whitelist,
);

// manually add the new tests to ensure
// the deduping logic is consistent
next.withMutation(next => {
Expand Down
41 changes: 41 additions & 0 deletions test/mixed.js
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,47 @@ describe('Mixed Types ', () => {
);
});

it('concat should preserve oneOf', async function() {
let inst = string()
.oneOf(['a'])
.concat(string().default('hi'));

await inst.isValid('a').should.become(true);
});

it('gives whitelist precedence to second in concat', async function() {
let inst = string()
.oneOf(['a', 'b', 'c'])
.concat(string().notOneOf(['b']));

await inst.isValid('a').should.become(true);
await inst.isValid('b').should.become(false);
await inst.isValid('c').should.become(true);
});

it('gives blacklist precedence to second in concat', async function() {
let inst = string()
.notOneOf(['a', 'b', 'c'])
.concat(string().oneOf(['b', 'c']));

await inst.isValid('a').should.become(false);
await inst.isValid('b').should.become(true);
await inst.isValid('c').should.become(true);
});

it('concats whitelist with refs', async function() {
let inst = object({
x: string().required(),
y: string()
.oneOf([ref('$x'), 'b', 'c'])
.concat(string().notOneOf(['c', ref('$x')])),
});

await inst.isValid({ x: 'a', y: 'a' }).should.become(false);
await inst.isValid({ x: 'a', y: 'b' }).should.become(true);
await inst.isValid({ x: 'a', y: 'c' }).should.become(false);
});

it('defaults should be validated but not transformed', function() {
let inst = string()
.trim()
Expand Down