Skip to content

Commit

Permalink
feat: add times.atMost function (#227)
Browse files Browse the repository at this point in the history
  • Loading branch information
xRSquared committed Feb 28, 2023
1 parent 6e3bcc7 commit b4e2aa2
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 2 deletions.
2 changes: 1 addition & 1 deletion docs/content/2.getting-started/2.usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ All of the helpers above return an object of type `Input` that can be chained wi
| `and` | this adds a new pattern to the current input, or you can use `and.referenceTo(groupName)` to adds a new pattern referencing to a named group. |
| `or` | this provides an alternative to the current input. |
| `after`, `before`, `notAfter` and `notBefore` | these activate positive/negative lookahead/lookbehinds. Make sure to check [browser support](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#browser_compatibility) as not all browsers support lookbehinds (notably Safari). |
| `times` | this is a function you can call directly to repeat the previous pattern an exact number of times, or you can use `times.between(min, max)` to specify a range, `times.atLeast(num)` to indicate it must repeat x times or `times.any()` to indicate it can repeat any number of times, _including none_. |
| `times` | this is a function you can call directly to repeat the previous pattern an exact number of times, or you can use `times.between(min, max)` to specify a range, `times.atLeast(x)` to indicate it must repeat at least x times, `times.atMost(x)` to indicate it must repeat at most x times or `times.any()` to indicate it can repeat any number of times, _including none_. |
| `optionally` | this is a function you can call to mark the current input as optional. |
| `as` | alias for `groupedAs` |
| `groupedAs` | this defines the entire input so far as a named capture group. You will get type safety when using the resulting RegExp with `String.match()`. |
Expand Down
7 changes: 6 additions & 1 deletion src/core/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,14 @@ export interface Input<
<N extends number>(number: N): Input<IfUnwrapped<V, `(?:${V}){${N}}`, `${V}{${N}}`>, G, C>
/** specify that the expression can repeat any number of times, _including none_ */
any: () => Input<IfUnwrapped<V, `(?:${V})*`, `${V}*`>, G, C>
/** specify that the expression must occur at least x times */
/** specify that the expression must occur at least `N` times */
atLeast: <N extends number>(
number: N
) => Input<IfUnwrapped<V, `(?:${V}){${N},}`, `${V}{${N},}`>, G, C>
/** specify that the expression must occur at most `N` times */
atMost: <N extends number>(
number: N
) => Input<IfUnwrapped<V, `(?:${V}){0,${N}}`, `${V}{0,${N}}`>, G, C>
/** specify a range of times to repeat the previous pattern */
between: <Min extends number, Max extends number>(
min: Min,
Expand Down Expand Up @@ -115,6 +119,7 @@ export const createInput = <
times: Object.assign((number: number) => createInput(`${wrap(s)}{${number}}`) as any, {
any: () => createInput(`${wrap(s)}*`) as any,
atLeast: (min: number) => createInput(`${wrap(s)}{${min},}`) as any,
atMost: (max: number) => createInput(`${wrap(s)}{0,${max}}`) as any,
between: (min: number, max: number) => createInput(`${wrap(s)}{${min},${max}}`) as any,
}),
optionally: () => createInput(`${wrap(s)}?`) as any,
Expand Down
2 changes: 2 additions & 0 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ describe('inputs', () => {
})
it('times', () => {
expect(exactly('test').times.between(1, 3).toString()).toMatchInlineSnapshot('"(?:test){1,3}"')
expect(exactly('test').times.atLeast(3).toString()).toMatchInlineSnapshot('"(?:test){3,}"')
expect(exactly('test').times.atMost(3).toString()).toMatchInlineSnapshot('"(?:test){0,3}"')
expect(exactly('test').times(4).or('foo').toString()).toMatchInlineSnapshot(
'"(?:(?:test){4}|foo)"'
)
Expand Down
12 changes: 12 additions & 0 deletions test/inputs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,18 @@ describe('chained inputs', () => {
expect(regexp2).toMatchInlineSnapshot('/\\(\\?:ab\\)\\{2,\\}/')
expectTypeOf(extractRegExp(val2)).toEqualTypeOf<'(?:ab){2,}'>()
})
it('times.atMost', () => {
const val = input.times.atMost(2)
const regexp = new RegExp(val as any)
expect(regexp).toMatchInlineSnapshot('/\\\\\\?\\{0,2\\}/')
expectTypeOf(extractRegExp(val)).toEqualTypeOf<'\\?{0,2}'>()

const val2 = multichar.times.atMost(2)
const regexp2 = new RegExp(val2 as any)
expect(regexp2).toMatchInlineSnapshot('/\\(\\?:ab\\)\\{0,2\\}/')
expectTypeOf(extractRegExp(val2)).toEqualTypeOf<'(?:ab){0,2}'>()
})

it('times.between', () => {
const val = input.times.between(3, 5)
const regexp = new RegExp(val as any)
Expand Down

1 comment on commit b4e2aa2

@vercel
Copy link

@vercel vercel bot commented on b4e2aa2 Feb 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.