-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Adds regexRuleConstructor to close #1978
- Loading branch information
Showing
5 changed files
with
124 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# regexRuleConstructor | ||
|
||
[Back to root readme.md](../../../readme.md) | ||
|
||
This function can be used to construct rules that ensure an input matches some given regex as shown in the example below. The function also generates an error class and a guard function. The rule should only throw errors with the generated error class. | ||
|
||
```ts | ||
import * as rulr from 'rulr' | ||
|
||
const abcSymbol = Symbol() | ||
const [abc, AbcError, abcGuard] = regexRuleConstructor(/^[abc]$/, abcSymbol) | ||
|
||
const constrainToExample = rulr.object({ | ||
required: { | ||
example: abc, | ||
}, | ||
}) | ||
|
||
type Example = rulr.Static<typeof constrainToExample> | ||
// { | ||
// example: rulr.Constrained<typeof abcSymbol, string> | ||
// } | ||
|
||
// Valid | ||
const example1: Example = constrainToExample({ | ||
example: 'a', | ||
}) | ||
|
||
// Valid | ||
const example2: Example = constrainToExample({ | ||
example: 1, | ||
}) | ||
|
||
// Invalid | ||
const example3: Example = constrainToExample({ | ||
example: '1', | ||
}) | ||
``` |
42 changes: 42 additions & 0 deletions
42
src/ruleConstructors/regexRuleConstructor/regexRuleConstructor.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import * as assert from 'assert' | ||
import { regexRuleConstructor, Constrained } from '../../rulr' | ||
|
||
const ruleSymbol = Symbol() | ||
const [rule, InvalidValueError, guard] = regexRuleConstructor(/^[abc]$/, ruleSymbol) | ||
|
||
test('regexRuleConstructor rule should allow a matching string', () => { | ||
const input = 'a' | ||
const output: Constrained<typeof ruleSymbol, string> = rule(input) | ||
assert.equal(guard(input), true) | ||
assert.strictEqual(output, input) | ||
assert.ok(InvalidValueError) | ||
}) | ||
|
||
test('regexRuleConstructor rule should not allow a non-string value', () => { | ||
const input = 1 | ||
assert.equal(guard(input), false) | ||
assert.throws(() => rule(input), InvalidValueError) | ||
}) | ||
|
||
test('regexRuleConstructor rule should not allow a non-matching value', () => { | ||
const input = '1' | ||
assert.equal(guard(input), false) | ||
assert.throws(() => rule(input), InvalidValueError) | ||
}) | ||
|
||
test('regexRuleConstructor rule should not allow a non-matching value', () => { | ||
const ruleSymbol = Symbol() | ||
const ruleName = 'test value' | ||
const [rule, InvalidValueError] = regexRuleConstructor(/^[abc]$/, ruleSymbol, ruleName) | ||
const input = '1' | ||
try { | ||
rule(input) | ||
assert.fail() | ||
} catch (err) { | ||
if (err instanceof InvalidValueError) { | ||
assert.equal(err.message, `expected ${ruleName}`) | ||
} else { | ||
assert.fail() | ||
} | ||
} | ||
}) |
32 changes: 32 additions & 0 deletions
32
src/ruleConstructors/regexRuleConstructor/regexRuleConstructor.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { BaseError } from 'make-error'; | ||
import { Constrained, Rule } from '../../core' | ||
import { isString } from '../../valueRules/string/string' | ||
|
||
type Result<T extends symbol> = [ | ||
Rule<Constrained<T, string>>, | ||
typeof BaseError, | ||
(input: unknown) => input is Constrained<T, string> | ||
] | ||
|
||
export function regexRuleConstructor<T extends symbol>(regex: RegExp, symbol: T, ruleName = 'valid value'): Result<T> { | ||
type RegexString = Constrained<typeof symbol, string> | ||
|
||
function guard(input: unknown): input is RegexString { | ||
return isString(input) && regex.test(input) | ||
} | ||
|
||
class InvalidValueError extends BaseError { | ||
constructor() { | ||
super(`expected ${ruleName}`) | ||
} | ||
} | ||
|
||
function rule(input: unknown): RegexString { | ||
if (guard(input)) { | ||
return input | ||
} | ||
throw new InvalidValueError() | ||
} | ||
|
||
return [rule, InvalidValueError, guard] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters