Skip to content

Commit

Permalink
feat: respect nullable() with oneOf (#1757)
Browse files Browse the repository at this point in the history
closes: #768 #104

BREAKING CHANGE: previously `oneOf` required adding `null` explicitly to allowed values when using oneOf. Folks have found this confusing and unintuitive so I am deferring and adjusting the behavior
  • Loading branch information
jquense authored Aug 22, 2022
1 parent 16b7679 commit 61ec302
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 49 deletions.
10 changes: 5 additions & 5 deletions src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -848,16 +848,16 @@ export default abstract class Schema<
next.internalTests.whiteList = createValidation({
message,
name: 'oneOf',
skipAbsent: true,
test(value) {
if (value === undefined) return true;
let valids = this.schema._whitelist;
let valids = (this.schema as Schema)._whitelist;
let resolved = valids.resolveAll(this.resolve);

return resolved.includes(value)
? true
: this.createError({
params: {
values: valids.toArray().join(', '),
values: Array.from(valids).join(', '),
resolved,
},
});
Expand All @@ -881,12 +881,12 @@ export default abstract class Schema<
message,
name: 'notOneOf',
test(value) {
let invalids = this.schema._blacklist;
let invalids = (this.schema as Schema)._blacklist;
let resolved = invalids.resolveAll(this.resolve);
if (resolved.includes(value))
return this.createError({
params: {
values: invalids.toArray().join(', '),
values: Array.from(invalids).join(', '),
resolved,
},
});
Expand Down
54 changes: 14 additions & 40 deletions src/util/ReferenceSet.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,33 @@
import type { SchemaRefDescription } from '../schema';
import Reference from '../Reference';

export default class ReferenceSet {
list: Set<unknown>;
refs: Map<string, Reference>;

constructor() {
this.list = new Set();
this.refs = new Map();
}
get size() {
return this.list.size + this.refs.size;
}

export default class ReferenceSet extends Set<unknown | Reference> {
describe() {
const description = [] as Array<unknown | SchemaRefDescription>;

for (const item of this.list) description.push(item);
for (const [, ref] of this.refs) description.push(ref.describe());

for (const item of this.values()) {
description.push(Reference.isRef(item) ? item.describe() : item);
}
return description;
}

toArray() {
return Array.from(this.list).concat(Array.from(this.refs.values()));
}

resolveAll(resolve: (v: unknown) => unknown) {
return this.toArray().reduce((acc: unknown[],e) => acc.concat(Reference.isRef(e) ? resolve(e) : e),[]);
}

add(value: unknown) {
Reference.isRef(value)
? this.refs.set(value.key, value)
: this.list.add(value);
}
delete(value: unknown) {
Reference.isRef(value)
? this.refs.delete(value.key)
: this.list.delete(value);
resolveAll(resolve: (v: unknown | Reference) => unknown) {
let result = [] as unknown[];
for (const item of this.values()) {
result.push(resolve(item));
}
return result;
}

clone() {
const next = new ReferenceSet();
next.list = new Set(this.list);
next.refs = new Map(this.refs);
return next;
return new ReferenceSet(this.values());
}

merge(newItems: ReferenceSet, removeItems: ReferenceSet) {
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));

newItems.forEach((value) => next.add(value));
removeItems.forEach((value) => next.delete(value));
return next;
}
}
4 changes: 2 additions & 2 deletions test/mixed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,11 +255,11 @@ describe('Mixed Types ', () => {
let inst = mixed().oneOf(['hello']);

validateAll(inst, {
valid: [undefined, 'hello'],
valid: [undefined, 'hello', [null, inst.nullable()]],
invalid: [
'YOLO',
[undefined, inst.required(), 'required'],
[null, inst.nullable()],
// [null, inst.nullable()],
[null, inst.nullable().required(), 'required'],
],
});
Expand Down
3 changes: 1 addition & 2 deletions test/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -964,12 +964,11 @@ Conditions: {
}

TypeAssigning: {
// $ExpectError unknown is not assignable to () => any
const _schema: ObjectSchema<{
mtime?: Date | null | undefined;
toJSON: () => any;
}> = object({
mtime: date().nullable(),
toJSON: mixed().required(),
toJSON: mixed<() => any>().required(),
});
}

0 comments on commit 61ec302

Please sign in to comment.