Skip to content

Commit

Permalink
#16, WIP #17, v 4.0.7
Browse files Browse the repository at this point in the history
  • Loading branch information
SimoneGianni committed Aug 20, 2022
1 parent 3c9a3a4 commit b7a4b2e
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 28 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,7 @@ npm publish
Release notes
=============
* 4.0.7 : Fixed #16 and partial work on #17 and other minor fixes and clode cleanups
* 4.0.6 : Support for dates, better array matching, less object matching generic mess, full exception on is.throwing, dependency bump (tickets #8 #9 #10 #11 #12 #13)
* 4.0.5 : Retry, minor bug on reporting assertion message
* 4.0.4 : Array eachItem mathcer
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tsmatchers",
"version": "4.0.6",
"version": "4.0.7",
"devDependencies": {
"@babel/core": "^7.18.10",
"@babel/preset-env": "^7.18.10",
Expand Down
6 changes: 6 additions & 0 deletions src/main/__tests__/objectMatchingTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ describe("Object >", ()=>{

check(getSomething(), is.object.matching({a:1}));
});
it("Should work with functions", ()=>{
let obj :{[index:string] :(i:number)=>string} = {
a: (i:number) => "ciao"
};
check(obj, is.object.matching({a:is.function()}));
});
/*
it.skip('All the cases that should give compile error', () => {
let obj = {a:1};
Expand Down
4 changes: 2 additions & 2 deletions src/main/__utils__/testUtils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { assert, check, is, Matcher, MatcherFactory } from "../tsMatchers";
import { assert, check, is, SomethingMatches } from "../tsMatchers";

export function checkMessage<T>(obj :T, matcher :T|Matcher<T>|MatcherFactory<T>, msg :RegExp) :any {
export function checkMessage<T>(obj :T, matcher :SomethingMatches<T>, msg :RegExp) :any {
return assert("Checking message", () => check(obj, matcher), is.throwing(msg));
}
4 changes: 2 additions & 2 deletions src/main/not.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Appendable, BaseMatcher, isContainer, IsInterface, Matcher, MatcherFactory, matcherOrEquals, Value } from './tsMatchers';
import { Appendable, BaseMatcher, isContainer, IsInterface, Matcher, matcherOrEquals, SomethingMatches, Value } from './tsMatchers';

export class Not<T> extends BaseMatcher<T> implements Matcher<T> {
constructor(private sub: Matcher<T>) { super(); }
Expand All @@ -14,8 +14,8 @@ export class Not<T> extends BaseMatcher<T> implements Matcher<T> {
}
}

export function not<T>(sub: Matcher<T>|MatcherFactory<T>): Matcher<T>;
export function not<T>(val: Value<T>): Matcher<T>;
export function not<T>(sub: SomethingMatches<T>): Matcher<T>;
export function not<T>(x: any): Matcher<T> {
return new Not<T>(matcherOrEquals(x));
}
Expand Down
1 change: 1 addition & 0 deletions src/main/object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type ObjMatch<T> = {
export type OrigObj<T> = {
[P in keyof T]:
T[P] extends Matcher<infer U> ? U :
T[P] extends Function ? (...args: any[]) => any :
T[P] extends MatcherFactory<infer U> ? U :
T[P] extends object ? OrigObj<T[P]> : T[P];
}; // & { [index :string]: any};
Expand Down
53 changes: 34 additions & 19 deletions src/main/tsMatchers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,30 @@
export interface Matcher<T> {
matches(obj :T):boolean|Promise<boolean>;
describe(obj :any, msg :Appendable) :void;
or :IsInterface & ((m :Matcher<T>) => Matcher<T>);
and :IsInterface & ((m :Matcher<T>) => Matcher<T>);
or :IsInterface;
and :IsInterface;
}

export interface AsyncMatcher<T> extends Matcher<T> {
__isAsync: boolean;
__matcherImplementation: boolean;
}

type RecursivePartial<T> = {
type RecursivePartial<T> =
T extends number ? number :
T extends string ? string :
T extends boolean ? boolean :
T extends Array<infer U> ? Array<RecursivePartial<U>> :
T extends Date ? Date :
T extends RegExp ? RegExp :
T extends Function ? Function :
T extends Object ? {
[P in keyof T]?:
T[P] extends (infer U)[] ? RecursivePartial<U>[] :
T[P] extends object ? RecursivePartial<T[P]> :
T[P];
};
} : T;

export class ToMatch<T,R extends T|Promise<T>> {
private obj:T

Expand All @@ -73,7 +82,7 @@

is(matcher :AsyncMatcher<R>) :R
is(matcher :AsyncMatcher<T>) :Promise<T>
is(matcher :Matcher<T>|Matcher<RecursivePartial<T>>) :R
is(matcher :Matcher<RecursivePartial<T>>) :R
is(val:Value<T>) :R
is(fn :MatcherFactory<T>) :R

Expand Down Expand Up @@ -180,12 +189,12 @@
return either.innerAnd(m);
}

get or() {
return isContainer.createWrapper((m :Matcher<any>) => this.asEitherOr(m), false);
get or() :IsInterface {
return isContainer.createWrapper((m :Matcher<any>) => this.asEitherOr(m), false) as unknown as IsInterface;
}

get and() {
return isContainer.createWrapper((m :Matcher<any>) => this.asEitherAnd(m), false);
get and() :IsInterface {
return isContainer.createWrapper((m :Matcher<any>) => this.asEitherAnd(m), false) as unknown as IsInterface;
}
}

Expand All @@ -197,14 +206,20 @@
[index: number]: any;
});

type TestValue = null | (any & NotAMatcher);
export type Value<T> = null | (T & NotAMatcher);
export type NotAPromise = {
then?: never;
};

type TestValue = null | (any & NotAMatcher & NotAPromise);
export type Value<T> = null | (T & NotAMatcher & NotAPromise);

export type SomethingMatches<T> = T|Matcher<T>|MatcherFactory<T>|Matcher<RecursivePartial<T>>|MatcherFactory<RecursivePartial<T>>;

export function assert<T extends TestValue>(msg :string):ToMatch<any,any>
export function assert<T extends TestValue>(msg :string, obj :T, matcher :AsyncMatcher<T>):Promise<T>
export function assert<T extends TestValue>(msg :string, obj :PromiseLike<T>, matcher :T|Matcher<T>|MatcherFactory<T>):Promise<T>
export function assert<T extends TestValue>(msg :string, obj :T, matcher :T|Matcher<T>|MatcherFactory<T>):T
export function assert<T extends TestValue>(msg :string, obj? :T, matcher? :T|Matcher<T>|MatcherFactory<T>):T|ToMatch<any,any> {
export function assert<T extends TestValue>(msg :string, obj :T, matcher :AsyncMatcher<T>|AsyncMatcher<RecursivePartial<T>>):Promise<T>
export function assert<T extends TestValue>(msg :string, obj :PromiseLike<T>, matcher :SomethingMatches<T>):Promise<T>
export function assert<T extends TestValue>(msg :string, obj :T, matcher :SomethingMatches<T>):T
export function assert<T extends TestValue>(msg :string, obj? :T, matcher? :SomethingMatches<T>):T|ToMatch<any,any> {
if (arguments.length == 1) {
return new ToMatch<any,any>(msg);
} else {
Expand All @@ -214,10 +229,10 @@

export function check<T extends TestValue>(obj :T):ToMatch<T,T>
export function check<T extends TestValue>(obj :PromiseLike<T>):ToMatch<T,Promise<T>>
export function check<T extends TestValue>(obj :T, matcher :AsyncMatcher<T>):Promise<T>
export function check<T extends TestValue>(obj :PromiseLike<T>, matcher :T|Matcher<T>|MatcherFactory<T>):Promise<T>
export function check<T extends TestValue>(obj :T, matcher :T|Matcher<T>|MatcherFactory<T>):T
export function check<T extends TestValue>(obj :T, matcher? :T|Matcher<T>|MatcherFactory<T>):T|ToMatch<T,any> {
export function check<T extends TestValue>(obj :PromiseLike<T>, matcher :SomethingMatches<T>):Promise<T>
export function check<T extends TestValue>(obj :T, matcher :AsyncMatcher<T>|AsyncMatcher<RecursivePartial<T>>):Promise<T>
export function check<T extends TestValue>(obj :T, matcher :SomethingMatches<T>):T
export function check<T extends TestValue>(obj :T, matcher? :SomethingMatches<T>):T|ToMatch<T,any> {
if (arguments.length == 1) {
return new ToMatch<T, any>(null).check(<T>obj);
} else {
Expand Down
8 changes: 4 additions & 4 deletions src/main/typing.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { not } from './not';
import { Appendable, BaseMatcher, exactly, isContainer, Matcher } from './tsMatchers';

export class OfType<T> extends BaseMatcher<T> implements Matcher<T> {
export class OfType<T = any> extends BaseMatcher<T> implements Matcher<T> {
constructor(private type: string) { super(); }

matches(obj: any) {
Expand Down Expand Up @@ -39,7 +39,7 @@ export class Truthy extends BaseMatcher<any> implements Matcher<any> {
}
}

export function ofType<N>(type: string): OfType<N> {
export function ofType<N = any>(type: string): OfType<N> {
return new OfType(type);
}

Expand All @@ -54,7 +54,7 @@ export var undefinedValue = ofType('undefined');
export var aNumber = ofType<number>('number');
export var aBoolean = ofType<boolean>('boolean');
export var anObject = ofType<object>('object');
export var aFunction = ofType<Function>('function');
export var aFunction = ofType<(... a:any[]) => any>('function');

export var anArray = instanceOf(Array);

Expand Down Expand Up @@ -87,7 +87,7 @@ declare module './tsMatchers' {

number: () => Matcher<number>;
boolean: () => Matcher<boolean>;
function: () => Matcher<Function>;
function: () => Matcher<(... a:any[]) => any>;

truthy: () => typeof aTruthy;
falsey: () => typeof aFalsey;
Expand Down

0 comments on commit b7a4b2e

Please sign in to comment.