Skip to content

Commit

Permalink
feat: screw that let's make it simple again
Browse files Browse the repository at this point in the history
  • Loading branch information
yamiteru committed Apr 29, 2024
1 parent da45238 commit 5a556e5
Show file tree
Hide file tree
Showing 76 changed files with 325 additions and 697 deletions.
5 changes: 3 additions & 2 deletions src/assertions/and/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { maxValue } from "@assertions/maxValue";
import { minValue } from "@assertions/minValue";
import { number } from "@assertions/number";
import { fc, test } from "@fast-check/vitest";
import { assert } from "@utils";
import { expect } from "vitest";
import { and } from "./index";

Expand All @@ -10,12 +11,12 @@ const assertion = and([number, minValue(0), maxValue(2)]);
test.prop([fc.integer({ min: 0, max: 2 })])(
"should not throw if value passes all assertions",
(value) => {
expect(() => assertion(value)).not.toThrow();
expect(() => assert(assertion, value)).not.toThrow();
},
);

test.prop([
fc.oneof(fc.integer({ max: -1 }), fc.integer({ min: 3 }), fc.string()),
])("should throw if value does not pass all assertions", (value) => {
expect(() => assertion(value)).toThrow();
expect(() => assert(assertion, value)).toThrow();
});
16 changes: 11 additions & 5 deletions src/assertions/and/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { AndSchema, Validate } from "@assertions/and/types";
import type { Assertion } from "@the-minimal/types";
import type { Intersection } from "./types";

/**
* Checks if all the assertions pass.
Expand All @@ -18,9 +19,14 @@ import type { AndSchema, Validate } from "@assertions/and/types";
* userEmail("[email protected]"); // passes
* ```
*/
export const and = <const $Schema extends AndSchema>(assertions: $Schema) =>
((v: unknown) => {
export const and =
<const $Values extends unknown[]>(
assertions: {
[$Key in keyof $Values]: Assertion<$Values[$Key]>;
},
): Assertion<Intersection<$Values>> =>
(v: unknown) => {
for (let i = 0; i < assertions.length; ++i) {
((assertions as any)[i] as any)(v);
(assertions[i] as any)(v);
}
}) as unknown as Validate.And<$Schema>;
};
47 changes: 0 additions & 47 deletions src/assertions/and/types.d.ts

This file was deleted.

9 changes: 9 additions & 0 deletions src/assertions/and/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// TODO: move into @the-minimal/types
export type Intersection<$Values extends unknown[]> = $Values extends [
infer $Head,
...infer $Tail,
]
? $Tail extends [infer _1, ...infer _2]
? $Head & Intersection<$Tail>
: $Head
: never;
24 changes: 14 additions & 10 deletions src/assertions/and2/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import type { Validate } from "@assertions/and/types";
import type { AnyBrand } from "@the-minimal/types";
import type {
Assertion,
InferAssertion,
UnknownAssertion,
} from "@the-minimal/types";

/**
* Checks that both assertions pass.
Expand All @@ -16,11 +19,12 @@ import type { AnyBrand } from "@the-minimal/types";
* userEmail("[email protected]"); // passes
* ```
*/
export const and2 = <$Brand1 extends AnyBrand, $Brand2 extends AnyBrand>(
brand1: $Brand1,
brand2: $Brand2,
) =>
((v: unknown) => {
(brand1 as any)(v);
(brand2 as any)(v);
}) as unknown as Validate.And<[$Brand1, $Brand2]>;
export const and2 =
<$Assertion1 extends UnknownAssertion, $Assertion2 extends UnknownAssertion>(
assertion1: $Assertion1,
assertion2: $Assertion2,
): Assertion<InferAssertion<$Assertion1> & InferAssertion<$Assertion2>> =>
(v: unknown) => {
assertion1(v);
assertion2(v);
};
40 changes: 24 additions & 16 deletions src/assertions/and3/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import type { Validate } from "@assertions/and/types";
import type { AnyBrand } from "@the-minimal/types";
import type {
Assertion,
InferAssertion,
UnknownAssertion,
} from "@the-minimal/types";

/**
* Checks that all three assertions pass.
Expand All @@ -18,17 +21,22 @@ import type { AnyBrand } from "@the-minimal/types";
* userEmail("[email protected]"); // passes
* ```
*/
export const and3 = <
$Brand1 extends AnyBrand,
$Brand2 extends AnyBrand,
$Brand3 extends AnyBrand,
>(
brand1: $Brand1,
brand2: $Brand2,
brand3: $Brand3,
) =>
((v: unknown) => {
(brand1 as any)(v);
(brand2 as any)(v);
(brand3 as any)(v);
}) as unknown as Validate.And<[$Brand1, $Brand2, $Brand3]>;
export const and3 =
<
$Assertion1 extends UnknownAssertion,
$Assertion2 extends UnknownAssertion,
$Assertion3 extends UnknownAssertion,
>(
assertion1: $Assertion1,
assertion2: $Assertion2,
assertion3: $Assertion3,
): Assertion<
InferAssertion<$Assertion1> &
InferAssertion<$Assertion2> &
InferAssertion<$Assertion3>
> =>
(v: unknown) => {
assertion1(v);
assertion2(v);
assertion3(v);
};
16 changes: 8 additions & 8 deletions src/assertions/array/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { isArray } from "@assertions/isArray";
import type { AnyBrand } from "@the-minimal/types";
import type { Validate } from "./types";
import type { UnknownAssertion } from "@the-minimal/types";

/**
* Checks that assertion passes for each element of the array.
*
* @param brand - Assertion to be applied to each element of the array.
* @param assertion - Assertion to be applied to each element of the array.
*
* @example
* ```ts
Expand All @@ -15,11 +14,12 @@ import type { Validate } from "./types";
* numbers([1, 2, 3]); // passes
* ```
*/
export const array = <$Brand extends AnyBrand>(brand: $Brand) =>
((v: any) => {
(isArray as any)(v);
export const array =
<$Assertion extends UnknownAssertion>(assertion: $Assertion) =>
(v: unknown) => {
isArray(v);

for (let i = 0; i < v.length; ++i) {
(brand as any)((v as any)[i]);
assertion((v as any)[i]);
}
}) as unknown as Validate.Array<$Brand>;
};
13 changes: 0 additions & 13 deletions src/assertions/array/types.d.ts

This file was deleted.

3 changes: 1 addition & 2 deletions src/assertions/boolean/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { type } from "@assertions/type";
import type { Validate } from "./types";

/**
* Checks that the value is a boolean.
Expand All @@ -10,4 +9,4 @@ import type { Validate } from "./types";
* boolean(true); // passes
* ```
*/
export const boolean = type("boolean") as Validate.Type.Boolean;
export const boolean = type<boolean>("boolean");
14 changes: 0 additions & 14 deletions src/assertions/boolean/types.d.ts

This file was deleted.

3 changes: 1 addition & 2 deletions src/assertions/email/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { regex } from "@assertions/regex";
import type { Validate } from "./types";

/**
* Checks if value matches email RegExp.
Expand All @@ -10,4 +9,4 @@ import type { Validate } from "./types";
* email("[email protected]"); // passes
* ```
*/
export const email = regex(/^\w+@.+\..+$/) as Validate.Regex.Email;
export const email = regex(/^\w+@.+\..+$/);
7 changes: 0 additions & 7 deletions src/assertions/email/types.d.ts

This file was deleted.

14 changes: 6 additions & 8 deletions src/assertions/endsWith/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { error } from "@error";
import type { Validate } from "./types";
import type { Assertion } from "@the-minimal/types";

/**
* Checks if value ends with `searchString`.
*
* @param searchString - The characters to be searched for at the end of value.
* @param input - The characters to be searched for at the end of value.
*
* @throws `endsWith` if value does not end with `searchString`.
*
Expand All @@ -16,9 +16,7 @@ import type { Validate } from "./types";
* question("really?"); // passes
* ```
*/
export const endsWith = <$SearchString extends string>(
searchString: $SearchString,
) =>
((v: any) =>
v.endsWith(searchString) ||
error(endsWith)) as unknown as Validate.String.EndsWith<$SearchString>;
export const endsWith =
<$Input extends string>(input: $Input): Assertion<unknown> =>
(v: unknown) =>
(v as any).endsWith(input) || error(endsWith);
10 changes: 0 additions & 10 deletions src/assertions/endsWith/types.d.ts

This file was deleted.

19 changes: 9 additions & 10 deletions src/assertions/expect/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import type { Message } from "@assertions/expect/types";
import { error } from "@error";
import type { AnyBrand } from "@the-minimal/types";
import type { UnknownAssertion } from "@the-minimal/types";

/**
* Wraps assertion and throws an error with message if assertion fails.
*
* @param brand - Assertion to be checked.
* @param assertion - Assertion to be checked.
* @param message - Message to be used in error.
*
* @example
Expand All @@ -16,14 +15,14 @@ import type { AnyBrand } from "@the-minimal/types";
* );
* ```
*/
export const expect = <$Brand extends AnyBrand>(
brand: $Brand,
message: Message,
export const expect = <$Assertion extends UnknownAssertion>(
assertion: $Assertion,
message: (error: any, value: unknown) => string,
) =>
((v: unknown) => {
try {
(brand as any)(v);
} catch (e: any) {
error(brand, message(e, v));
assertion(v);
} catch (e) {
error(assertion, message(e, v));
}
}) as unknown as $Brand;
}) as $Assertion;
1 change: 0 additions & 1 deletion src/assertions/expect/types.d.ts

This file was deleted.

10 changes: 5 additions & 5 deletions src/assertions/includes/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Validate } from "@assertions/includes/types";
import { error } from "@error";
import type { Assertion } from "@the-minimal/types";

/**
* Checks if value includes with another value.
Expand All @@ -14,7 +14,7 @@ import { error } from "@error";
* hello("--hello--"); // passes
* ```
*/
export const includes = <const $Input>(input: $Input) =>
((v: any) =>
v.includes(input) ||
error(includes)) as unknown as Validate.List.Includes<$Input>;
export const includes =
(input: unknown): Assertion<unknown> =>
(v: unknown) =>
(v as any).includes(input) || error(includes);
7 changes: 0 additions & 7 deletions src/assertions/includes/types.d.ts

This file was deleted.

6 changes: 3 additions & 3 deletions src/assertions/integer/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Validate } from "@assertions/integer/types";
import { error } from "@error";
import type { Assertion } from "@the-minimal/types";

/**
* Checks if value is integer.
Expand All @@ -10,5 +10,5 @@ import { error } from "@error";
* integer(1) // passes
* ```
*/
export const integer = ((v: unknown) =>
Number.isInteger(v) || error(integer)) as unknown as Validate.Number.Integer;
export const integer: Assertion<unknown> = (v: unknown) =>
Number.isInteger(v) || error(integer);
Loading

0 comments on commit 5a556e5

Please sign in to comment.