Skip to content

Commit

Permalink
Add ArrayBufferPredicate, DataViewPredicate, TypedArrayPredicate (
Browse files Browse the repository at this point in the history
  • Loading branch information
JasonHK authored Feb 22, 2020
1 parent 816e66c commit f010b90
Show file tree
Hide file tree
Showing 9 changed files with 572 additions and 29 deletions.
27 changes: 22 additions & 5 deletions source/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,29 @@ export interface Ow extends Modifiers, Predicates {
@param predicate - Predicate used in the validator function.
*/
create<T>(predicate: BasePredicate<T>): (value: T) => void;
create<T>(predicate: BasePredicate<T>): ReusableValidator<T>;

/**
Create a reusable validator.
@param label - Label which should be used in error messages.
@param predicate - Predicate used in the validator function.
*/
create<T>(label: string, predicate: BasePredicate<T>): (value: T) => void;
create<T>(label: string, predicate: BasePredicate<T>): ReusableValidator<T>;
}

/**
A reusable validator.
*/
export interface ReusableValidator<T> {
/**
Test if the value matches the predicate. Throws an `ArgumentError` if the test fails.
@param value - Value to test.
@param label - Override the label which should be used in error messages.
*/
// eslint-disable-next-line @typescript-eslint/prefer-function-type
(value: T, label?: string): void;
}

const ow = <T>(value: T, labelOrPredicate: unknown, predicate?: BasePredicate<T>) => {
Expand Down Expand Up @@ -83,16 +97,16 @@ Object.defineProperties(ow, {
}
},
create: {
value: <T>(labelOrPredicate: BasePredicate<T> | string | undefined, predicate?: BasePredicate<T>) => (value: T) => {
value: <T>(labelOrPredicate: BasePredicate<T> | string | undefined, predicate?: BasePredicate<T>) => (value: T, label?: string) => {
if (isPredicate(labelOrPredicate)) {
const stackFrames = callsites();

test(value, () => inferLabel(stackFrames), labelOrPredicate);
test(value, label ?? (() => inferLabel(stackFrames)), labelOrPredicate);

return;
}

test(value, labelOrPredicate as string, predicate as BasePredicate<T>);
test(value, label ?? (labelOrPredicate as string), predicate as BasePredicate<T>);
}
}
});
Expand All @@ -111,6 +125,9 @@ export {
WeakMapPredicate,
SetPredicate,
WeakSetPredicate,
TypedArrayPredicate,
ArrayBufferPredicate,
DataViewPredicate,
AnyPredicate,
Shape
} from './predicates';
Expand Down
62 changes: 38 additions & 24 deletions source/predicates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import {MapPredicate} from './predicates/map';
import {WeakMapPredicate} from './predicates/weak-map';
import {SetPredicate} from './predicates/set';
import {WeakSetPredicate} from './predicates/weak-set';
import {TypedArrayPredicate} from './predicates/typed-array';
import {ArrayBufferPredicate} from './predicates/array-buffer';
import {DataViewPredicate} from './predicates/data-view';
import {BasePredicate} from './predicates/base-predicate';
import {AnyPredicate} from './predicates/any';

Expand Down Expand Up @@ -118,62 +121,67 @@ export interface Predicates {
/**
Test the value to be a typed array.
*/
readonly typedArray: Predicate<TypedArray>;
readonly typedArray: TypedArrayPredicate<TypedArray>;

/**
Test the value to be a Int8Array.
*/
readonly int8Array: Predicate<Int8Array>;
readonly int8Array: TypedArrayPredicate<Int8Array>;

/**
Test the value to be a Uint8Array.
*/
readonly uint8Array: Predicate<Uint8Array>;
readonly uint8Array: TypedArrayPredicate<Uint8Array>;

/**
Test the value to be a Uint8ClampedArray.
*/
readonly uint8ClampedArray: Predicate<Uint8ClampedArray>;
readonly uint8ClampedArray: TypedArrayPredicate<Uint8ClampedArray>;

/**
Test the value to be a Int16Array.
*/
readonly int16Array: Predicate<Int16Array>;
readonly int16Array: TypedArrayPredicate<Int16Array>;

/**
Test the value to be a Uint16Array.
*/
readonly uint16Array: Predicate<Uint16Array>;
readonly uint16Array: TypedArrayPredicate<Uint16Array>;

/**
Test the value to be a Int32Array.
*/
readonly int32Array: Predicate<Int32Array>;
readonly int32Array: TypedArrayPredicate<Int32Array>;

/**
Test the value to be a Uint32Array.
*/
readonly uint32Array: Predicate<Uint32Array>;
readonly uint32Array: TypedArrayPredicate<Uint32Array>;

/**
Test the value to be a Float32Array.
*/
readonly float32Array: Predicate<Float32Array>;
readonly float32Array: TypedArrayPredicate<Float32Array>;

/**
Test the value to be a Float64Array.
*/
readonly float64Array: Predicate<Float64Array>;
readonly float64Array: TypedArrayPredicate<Float64Array>;

/**
Test the value to be a ArrayBuffer.
*/
readonly arrayBuffer: Predicate<ArrayBuffer>;
readonly arrayBuffer: ArrayBufferPredicate<ArrayBuffer>;

/**
Test the value to be a SharedArrayBuffer.
*/
readonly sharedArrayBuffer: ArrayBufferPredicate<SharedArrayBuffer>;

/**
Test the value to be a DataView.
*/
readonly dataView: Predicate<DataView>;
readonly dataView: DataViewPredicate;

/**
Test the value to be Iterable.
Expand Down Expand Up @@ -259,40 +267,43 @@ export default <T>(object: T, options?: PredicateOptions): T & Predicates => {
get: () => new Predicate('Promise', options)
},
typedArray: {
get: () => new Predicate('TypedArray', options)
get: () => new TypedArrayPredicate('TypedArray', options)
},
int8Array: {
get: () => new Predicate('Int8Array', options)
get: () => new TypedArrayPredicate('Int8Array', options)
},
uint8Array: {
get: () => new Predicate('Uint8Array', options)
get: () => new TypedArrayPredicate('Uint8Array', options)
},
uint8ClampedArray: {
get: () => new Predicate('Uint8ClampedArray', options)
get: () => new TypedArrayPredicate('Uint8ClampedArray', options)
},
int16Array: {
get: () => new Predicate('Int16Array', options)
get: () => new TypedArrayPredicate('Int16Array', options)
},
uint16Array: {
get: () => new Predicate('Uint16Array', options)
get: () => new TypedArrayPredicate('Uint16Array', options)
},
int32Array: {
get: () => new Predicate('Int32Array', options)
get: () => new TypedArrayPredicate('Int32Array', options)
},
uint32Array: {
get: () => new Predicate('Uint32Array', options)
get: () => new TypedArrayPredicate('Uint32Array', options)
},
float32Array: {
get: () => new Predicate('Float32Array', options)
get: () => new TypedArrayPredicate('Float32Array', options)
},
float64Array: {
get: () => new Predicate('Float64Array', options)
get: () => new TypedArrayPredicate('Float64Array', options)
},
arrayBuffer: {
get: () => new Predicate('ArrayBuffer', options)
get: () => new ArrayBufferPredicate('ArrayBuffer', options)
},
sharedArrayBuffer: {
get: () => new ArrayBufferPredicate('SharedArrayBuffer', options)
},
dataView: {
get: () => new Predicate('DataView', options)
get: () => new DataViewPredicate(options)
},
iterable: {
get: () => new Predicate('Iterable', options)
Expand All @@ -317,6 +328,9 @@ export {
WeakMapPredicate,
SetPredicate,
WeakSetPredicate,
TypedArrayPredicate,
ArrayBufferPredicate,
DataViewPredicate,
AnyPredicate,
Shape
};
41 changes: 41 additions & 0 deletions source/predicates/array-buffer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {Predicate} from './predicate';

export class ArrayBufferPredicate<T extends ArrayBufferLike> extends Predicate<T> {
/**
Test an array buffer to have a specific byte length.
@param byteLength - The byte length of the array buffer.
*/
byteLength(byteLength: number) {
return this.addValidator({
message: (value, label) => `Expected ${label} to have byte length of \`${byteLength}\`, got \`${value.byteLength}\``,
validator: value => value.byteLength === byteLength
});
}

/**
Test an array buffer to have a minimum byte length.
@param byteLength - The minimum byte length of the array buffer.
*/
minByteLength(byteLength: number) {
return this.addValidator({
message: (value, label) => `Expected ${label} to have a minimum byte length of \`${byteLength}\`, got \`${value.byteLength}\``,
validator: value => value.byteLength >= byteLength,
negatedMessage: (value, label) => `Expected ${label} to have a maximum byte length of \`${byteLength - 1}\`, got \`${value.byteLength}\``
});
}

/**
Test an array buffer to have a minimum byte length.
@param length - The minimum byte length of the array buffer.
*/
maxByteLength(byteLength: number) {
return this.addValidator({
message: (value, label) => `Expected ${label} to have a maximum byte length of \`${byteLength}\`, got \`${value.byteLength}\``,
validator: value => value.byteLength <= byteLength,
negatedMessage: (value, label) => `Expected ${label} to have a minimum byte length of \`${byteLength + 1}\`, got \`${value.byteLength}\``
});
}
}
48 changes: 48 additions & 0 deletions source/predicates/data-view.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {Predicate, PredicateOptions} from './predicate';

export class DataViewPredicate extends Predicate<DataView> {
/**
@hidden
*/
constructor(options?: PredicateOptions) {
super('DataView', options);
}

/**
Test a DataView to have a specific byte length.
@param byteLength - The byte length of the DataView.
*/
byteLength(byteLength: number) {
return this.addValidator({
message: (value, label) => `Expected ${label} to have byte length of \`${byteLength}\`, got \`${value.byteLength}\``,
validator: value => value.byteLength === byteLength
});
}

/**
Test a DataView to have a minimum byte length.
@param byteLength - The minimum byte length of the DataView.
*/
minByteLength(byteLength: number) {
return this.addValidator({
message: (value, label) => `Expected ${label} to have a minimum byte length of \`${byteLength}\`, got \`${value.byteLength}\``,
validator: value => value.byteLength >= byteLength,
negatedMessage: (value, label) => `Expected ${label} to have a maximum byte length of \`${byteLength - 1}\`, got \`${value.byteLength}\``
});
}

/**
Test a DataView to have a minimum byte length.
@param length - The minimum byte length of the DataView.
*/
maxByteLength(byteLength: number) {
return this.addValidator({
message: (value, label) => `Expected ${label} to have a maximum byte length of \`${byteLength}\`, got \`${value.byteLength}\``,
validator: value => value.byteLength <= byteLength,
negatedMessage: (value, label) => `Expected ${label} to have a minimum byte length of \`${byteLength + 1}\`, got \`${value.byteLength}\``
});
}
}
80 changes: 80 additions & 0 deletions source/predicates/typed-array.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import {TypedArray} from 'type-fest';
import {Predicate} from './predicate';

export class TypedArrayPredicate<T extends TypedArray> extends Predicate<T> {
/**
Test a typed array to have a specific byte length.
@param byteLength - The byte length of the typed array.
*/
byteLength(byteLength: number) {
return this.addValidator({
message: (value, label) => `Expected ${label} to have byte length of \`${byteLength}\`, got \`${value.byteLength}\``,
validator: value => value.byteLength === byteLength
});
}

/**
Test a typed array to have a minimum byte length.
@param byteLength - The minimum byte length of the typed array.
*/
minByteLength(byteLength: number) {
return this.addValidator({
message: (value, label) => `Expected ${label} to have a minimum byte length of \`${byteLength}\`, got \`${value.byteLength}\``,
validator: value => value.byteLength >= byteLength,
negatedMessage: (value, label) => `Expected ${label} to have a maximum byte length of \`${byteLength - 1}\`, got \`${value.byteLength}\``
});
}

/**
Test a typed array to have a minimum byte length.
@param length - The minimum byte length of the typed array.
*/
maxByteLength(byteLength: number) {
return this.addValidator({
message: (value, label) => `Expected ${label} to have a maximum byte length of \`${byteLength}\`, got \`${value.byteLength}\``,
validator: value => value.byteLength <= byteLength,
negatedMessage: (value, label) => `Expected ${label} to have a minimum byte length of \`${byteLength + 1}\`, got \`${value.byteLength}\``
});
}

/**
Test a typed array to have a specific length.
@param length - The length of the typed array.
*/
length(length: number) {
return this.addValidator({
message: (value, label) => `Expected ${label} to have length \`${length}\`, got \`${value.length}\``,
validator: value => value.length === length
});
}

/**
Test a typed array to have a minimum length.
@param length - The minimum length of the typed array.
*/
minLength(length: number) {
return this.addValidator({
message: (value, label) => `Expected ${label} to have a minimum length of \`${length}\`, got \`${value.length}\``,
validator: value => value.length >= length,
negatedMessage: (value, label) => `Expected ${label} to have a maximum length of \`${length - 1}\`, got \`${value.length}\``
});
}

/**
Test a typed array to have a maximum length.
@param length - The maximum length of the typed array.
*/
maxLength(length: number) {
return this.addValidator({
message: (value, label) => `Expected ${label} to have a maximum length of \`${length}\`, got \`${value.length}\``,
validator: value => value.length <= length,
negatedMessage: (value, label) => `Expected ${label} to have a minimum length of \`${length + 1}\`, got \`${value.length}\``
});
}
}
Loading

0 comments on commit f010b90

Please sign in to comment.