Skip to content

Commit

Permalink
feat: add StringConstraints (#20)
Browse files Browse the repository at this point in the history
* feat(iftools_287): add IsPopulatedString

* feat(iftools_287): add contraints to IsString

* feat(iftools_287): rename to IsFilledString

* feat(itools_287): make use of IsString constraints

* feat(itools_287): improve tests
  • Loading branch information
henricazottes authored May 31, 2023
1 parent 928f2d5 commit c26a50c
Show file tree
Hide file tree
Showing 6 changed files with 310 additions and 8 deletions.
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,32 @@ Asserts that the value is a number, but not NaN nor +/-Infinity.
### IsString

```ts
static IsString(value: unknown): void
static IsString(value: unknown, constraints?: StringConstraints): void
```

Asserts that the value is a string.

The optional parameter `constraints` accept an object described by the following interface.

```ts
interface StringConstraints
{
minLength?: number;
maxLength?: number;
}
```

If `minLength` is provided, it'll asserts that the value has at least this length.<br />
If `maxLength` is provided, it'll asserts that the value has at most this length.

### IsFilledString

```ts
static IsFilledString(value: unknown): void
```

Like `IsString`, but asserts that the string is never empty too.

### IsArray

```ts
Expand Down Expand Up @@ -211,6 +232,14 @@ static IsString(value: unknown): boolean

Narrow down the value to being a string.

### IsFilledString

```ts
static IsFilledString(value: unknown): void
```

Asserts that the value is a non empty string.

### IsArray

```ts
Expand Down
111 changes: 110 additions & 1 deletion __tests__/TypeAssertion.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,115 @@ describe(
}
}
);

it(
"should return when given a string with a length greater or equal to the minLength constraint",
(): void =>
{
expect(
(): void =>
{
TypeAssertion.IsString("Allan", { minLength: 1 });
}
).to.not.throw();

expect(
(): void =>
{
TypeAssertion.IsString("Allan", { minLength: 5 });
}
).to.not.throw();
}
);

it(
"should throw when given a string with a length shorter than minLength constraint",
(): void =>
{
expect(
(): void =>
{
TypeAssertion.IsString("Allan", { minLength: 6 });
}
).to.throw("value length is shorter than minimum length 6");
}
);

it(
"should return when given a string with a length shorter or equal to the maxLength constraint",
(): void =>
{
expect(
(): void =>
{
TypeAssertion.IsString("Allan", { maxLength: 10 });
}
).to.not.throw();

expect(
(): void =>
{
TypeAssertion.IsString("Allan", { maxLength: 5 });
}
).to.not.throw();
}
);

it(
"should throw when given a string with a length greater than maxLength constraint",
(): void =>
{
expect(
(): void =>
{
TypeAssertion.IsString("Allan", { maxLength: 4 });
}
).to.throw("value length is greater than maximum length 4");
}
);
}
);

describe(
"IsFilledString",
(): void =>
{
it(
"should return when given a non empty string",
(): void =>
{
const VALUES: Array<unknown> = getValues(BaseType.STRING)
.filter((value) => { return value !== ""; });

for (const ITEM of VALUES)
{
expect(
(): void =>
{
TypeAssertion.IsFilledString(ITEM);
}
).to.not.throw();
}
}
);

it(
"should throw when given anything else",
(): void =>
{
const VALUES: Array<unknown> = [...getInvertedValues(BaseType.STRING), ""];

for (const ITEM of VALUES)
{
expect(
(): void =>
{
TypeAssertion.IsFilledString(ITEM);
}
).to.throw(/^value /);
}
}
);
}
);

Expand Down Expand Up @@ -434,7 +543,7 @@ describe(
);

it(
"should throw when given a populated array",
"should return when given a populated array",
(): void =>
{
expect(
Expand Down
67 changes: 67 additions & 0 deletions __tests__/TypeGuard.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,73 @@ describe(
}
}
);

it(
"should return true when given a string with a length greater or equal to the minLength constraint",
(): void =>
{
expect(TypeGuard.IsString("Allan", { minLength: 2 })).to.be.true;
expect(TypeGuard.IsString("Allan", { minLength: 5 })).to.be.true;
}
);

it(
"should return false when given an array with a length below the minLength constraint",
(): void =>
{
expect(TypeGuard.IsString("Allan", { minLength: 6 })).to.be.false;
}
);

it(
"should return true when given a string with a length shorter or equal to the maxLength constraint",
(): void =>
{
expect(TypeGuard.IsString("Allan", { maxLength: 5 })).to.be.true;
expect(TypeGuard.IsString("Allan", { maxLength: 10 })).to.be.true;
}
);

it(
"should return false when given a string with a length above the maxLength constraint",
(): void =>
{
expect(TypeGuard.IsString("Allan", { maxLength: 2 })).to.be.false;
}
);
}
);

describe(
"IsFilledString",
(): void =>
{
it(
"should return true when given a populated string",
(): void =>
{
const VALUES: Array<unknown> = getValues(BaseType.STRING)
.filter((value) => { return value !== ""; });

for (const ITEM of VALUES)
{
expect(TypeGuard.IsFilledString(ITEM)).to.be.true;
}
}
);

it(
"should return false when given anything else",
(): void =>
{
const VALUES: Array<unknown> = [...getInvertedValues(BaseType.STRING), ""];

for (const ITEM of VALUES)
{
expect(TypeGuard.IsFilledString(ITEM)).to.be.false;
}
}
);
}
);

Expand Down
42 changes: 40 additions & 2 deletions src/TypeAssertion.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { TypeGuard } from "./TypeGuard.js";

import type { ArrayConstraints, ObjectWithNullableProperty, ObjectWithProperty, PopulatedArray } from "./Types.js";
import type { ArrayConstraints, ObjectWithNullableProperty, ObjectWithProperty, PopulatedArray, StringConstraints } from "./Types.js";

/**
* TypeAssertion
Expand Down Expand Up @@ -110,15 +110,53 @@ class TypeAssertion
* @public
* @static
* @param {unknown} value the value
* @param {object} [constraints] some additional check
* @param {number} [constraints.minLength] minimal length
* @param {number} [constraints.maxLength] maximum length
* @throws {Error} if the value is not a string
* @return {void} nothing
*/
public static IsString(value: unknown): asserts value is string
public static IsString(value: unknown, constraints?: StringConstraints): asserts value is string
{
if (!TypeGuard.IsString(value))
{
throw new Error("value is not a string");
}

if (constraints === undefined)
{
return;
}

if (constraints.minLength !== undefined && value.length < constraints.minLength)
{
throw new Error(`value length is shorter than minimum length ${constraints.minLength.toString()}`);
}

if (constraints.maxLength !== undefined && value.length > constraints.maxLength)
{
throw new Error(`value length is greater than maximum length ${constraints.maxLength.toString()}`);
}
}

/**
* IsFilledString
*
* @description Assertion that check if a value is non empty string.
* @public
* @static
* @param {unknown} value the value
* @throws {Error} if the value is not a string
* @return {void} nothing
*/
public static IsFilledString(value: unknown): asserts value is string
{
TypeAssertion.IsString(value, {
/**
*
*/
minLength: 1,
});
}

/**
Expand Down
50 changes: 47 additions & 3 deletions src/TypeGuard.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ArrayConstraints, ObjectWithNullableProperty, ObjectWithProperty, PopulatedArray } from "./Types.js";
import type { ArrayConstraints, ObjectWithNullableProperty, ObjectWithProperty, PopulatedArray, StringConstraints } from "./Types.js";

/**
* TypeGuard
Expand Down Expand Up @@ -108,11 +108,55 @@ class TypeGuard
* @public
* @static
* @param {unknown} value the value
* @param {object} [constraints] some additional check
* @param {number} [constraints.minLength] minimal length
* @param {number} [constraints.maxLength] maximum length
* @return {boolean} a boolean
*/
public static IsString(value: unknown, constraints?: StringConstraints): value is string
{
if (typeof value !== "string")
{
return false;
}

if (constraints === undefined)
{
return true;
}

if (constraints.minLength !== undefined && value.length < constraints.minLength)
{
return false;
}

if (constraints.maxLength !== undefined && value.length > constraints.maxLength)
{
return false;
}

return true;
}

/**
* IsFilledString
*
* @description Predicate that check if a value is a non empty string.
* @public
* @static
* @param {unknown} value the value
* @return {boolean} a boolean
*/
public static IsString(value: unknown): value is string
public static IsFilledString(
value: unknown,
): value is string
{
return typeof value === "string";
return TypeGuard.IsString(value, {
/**
*
*/
minLength: 1
});
}

/**
Expand Down
17 changes: 16 additions & 1 deletion src/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,19 @@ interface ArrayConstraints<Type>
itemGuard?: (item: unknown) => item is Type;
}

export type { ArrayConstraints, ObjectWithNullableProperty, ObjectWithProperty, PopulatedArray };
/**
* StringConstraints interface
*/
interface StringConstraints
{
/**
* minLength
*/
minLength?: number;
/**
* maxLength
*/
maxLength?: number;
}

export type { ArrayConstraints, ObjectWithNullableProperty, ObjectWithProperty, PopulatedArray, StringConstraints };

0 comments on commit c26a50c

Please sign in to comment.