Skip to content

Commit a18fccb

Browse files
authored
feat: add chained input and.referenceToGroup (#21)
1 parent 040c940 commit a18fccb

File tree

4 files changed

+39
-6
lines changed

4 files changed

+39
-6
lines changed

docs/content/2.getting-started/2.usage.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ All of the helpers above return an object of type `Input` that can be chained wi
5151

5252
| | |
5353
| --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
54-
| `and` | this adds a new pattern to the current input. |
54+
| `and` | this adds a new pattern to the current input, or you can use `and.referenceToGroup(groupName)` to adds a new pattern referencing to a named group. |
5555
| `or` | this provides an alternative to the current input. |
5656
| `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). |
5757
| `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_. |

src/core/internal.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@ import type { GetValue } from './types/escape'
33
import type { InputSource } from './types/sources'
44

55
export interface Input<V extends string, G extends string = never> {
6-
/** this adds a new pattern to the current input */
7-
and: <I extends InputSource<string, any>>(
8-
input: I
9-
) => Input<`${V}${GetValue<I>}`, G | (I extends Input<any, infer NewGroups> ? NewGroups : never)>
6+
and: {
7+
/** this adds a new pattern to the current input */
8+
<I extends InputSource<string, any>>(input: I): Input<
9+
`${V}${GetValue<I>}`,
10+
G | (I extends Input<any, infer NewGroups> ? NewGroups : never)
11+
>
12+
/** this adds a new pattern to the current input, with the pattern reference to a named group. */
13+
referenceToGroup: <N extends G>(groupName: N) => Input<`${V}\\k<${N}>`, G>
14+
}
1015
/** this provides an alternative to the current input */
1116
or: <I extends InputSource<string, any>>(
1217
input: I
@@ -52,7 +57,9 @@ export const createInput = <Value extends string, Groups extends string = never>
5257
): Input<Value, Groups> => {
5358
return {
5459
toString: () => s.toString(),
55-
and: input => createInput(`${s}${exactly(input)}`),
60+
and: Object.assign((input: InputSource<string, any>) => createInput(`${s}${exactly(input)}`), {
61+
referenceToGroup: (groupName: string) => createInput(`${s}\\k<${groupName}>`),
62+
}),
5663
or: input => createInput(`(${s}|${exactly(input)})`),
5764
after: input => createInput(`(?<=${exactly(input)})${s}`),
5865
before: input => createInput(`${s}(?=${exactly(input)})`),

test/index.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,24 @@ describe('inputs', () => {
101101
)
102102
)?.groups?.id
103103
})
104+
it('named backreference to capture groups', () => {
105+
const pattern = exactly('foo')
106+
.as('fooGroup')
107+
.and(exactly('bar').as('barGroup'))
108+
.and('baz')
109+
.and.referenceToGroup('barGroup')
110+
.and.referenceToGroup('fooGroup')
111+
.and.referenceToGroup('barGroup')
112+
113+
expect('foobarbazbarfoobar'.match(createRegExp(pattern))).toMatchInlineSnapshot(`
114+
[
115+
"foobarbazbarfoobar",
116+
"foo",
117+
"bar",
118+
]
119+
`)
120+
expectTypeOf(pattern.and.referenceToGroup).toBeCallableWith('barGroup')
121+
// @ts-expect-error
122+
pattern.and.referenceToGroup('bazgroup')
123+
})
104124
})

test/inputs.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@ describe('chained inputs', () => {
135135
expect(regexp).toMatchInlineSnapshot('/\\\\\\?test\\\\\\.js/')
136136
expectTypeOf(extractRegExp(val)).toMatchTypeOf<'\\?test\\.js'>()
137137
})
138+
it('and.referenceToGroup', () => {
139+
const val = input.as('namedGroup').and(exactly('any')).and.referenceToGroup('namedGroup')
140+
const regexp = new RegExp(val as any)
141+
expect(regexp).toMatchInlineSnapshot('/\\(\\?<namedGroup>\\\\\\?\\)any\\\\k<namedGroup>/')
142+
expectTypeOf(extractRegExp(val)).toMatchTypeOf<'(?<namedGroup>\\?)any\\k<namedGroup>'>()
143+
})
138144
it('or', () => {
139145
const val = input.or('test.js')
140146
const regexp = new RegExp(val as any)

0 commit comments

Comments
 (0)