Skip to content

Commit 5264256

Browse files
authored
fix: sanitize createRegExp return type (#180)
1 parent 0b61f78 commit 5264256

File tree

3 files changed

+35
-15
lines changed

3 files changed

+35
-15
lines changed

src/core/types/escape.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export type EscapeChar<T extends string> = Escape<T, '\\' | '^' | '-' | ']'>
2020
export type StripEscapes<T extends string> = T extends `${infer A}\\${infer B}` ? `${A}${B}` : T
2121

2222
// prettier-ignore
23-
type ExactEscapeChar = '.' | '*' | '+' | '?' | '^' | '$' | '{' | '}' | '(' | ')' | '|' | '[' | ']' | '/'
23+
export type ExactEscapeChar = '.' | '*' | '+' | '?' | '^' | '$' | '{' | '}' | '(' | ')' | '|' | '[' | ']' | '/'
2424

2525
export type GetValue<T extends InputSource> = T extends string
2626
? Escape<T, ExactEscapeChar>

src/index.ts

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,31 @@ import { Input, exactly } from './core/inputs'
33
import type { Join } from './core/types/join'
44
import type { MagicRegExp, MagicRegExpMatchArray } from './core/types/magic-regexp'
55

6-
export const createRegExp = <
7-
Value extends string,
8-
NamedGroups extends string = never,
9-
CapturedGroupsArr extends (string | undefined)[] = [],
10-
Flags extends Flag[] = never[]
11-
>(
12-
raw: Input<Value, NamedGroups, CapturedGroupsArr> | Value,
13-
flags?: [...Flags] | string | Set<Flag>
14-
) =>
15-
new RegExp(exactly(raw).toString(), [...(flags || '')].join('')) as MagicRegExp<
16-
`/${Value}/${Join<Flags, '', ''>}`,
17-
NamedGroups,
18-
CapturedGroupsArr,
6+
import type { Escape, ExactEscapeChar } from './core/types/escape'
7+
8+
export const createRegExp: {
9+
/** Create Magic RegExp from Input helper */
10+
<
11+
Value extends string,
12+
NamedGroups extends string = never,
13+
CapturedGroupsArr extends (string | undefined)[] = [],
14+
Flags extends Flag[] = never[]
15+
>(
16+
raw: Input<Value, NamedGroups, CapturedGroupsArr>,
17+
flags?: [...Flags] | string | Set<Flag>
18+
): MagicRegExp<`/${Value}/${Join<Flags, '', ''>}`, NamedGroups, CapturedGroupsArr, Flags[number]>
19+
/** Create Magic RegExp from string, string will be sanitized */
20+
<Value extends string, Flags extends Flag[] = never[]>(
21+
raw: Value,
22+
flags?: [...Flags] | string | Set<Flag>
23+
): MagicRegExp<
24+
`/${Escape<Value, ExactEscapeChar>}/${Join<Flags, '', ''>}`,
25+
never,
26+
[],
1927
Flags[number]
2028
>
29+
} = (raw: any, flags?: any) =>
30+
new RegExp(exactly(raw).toString(), [...(flags || '')].join('')) as any
2131

2232
export * from './core/flags'
2333
export * from './core/inputs'

test/index.test.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,17 @@ describe('magic-regexp', () => {
2626
})
2727
it('collects flag type', () => {
2828
const re = createRegExp('.', [global, multiline])
29-
expectTypeOf(re).toEqualTypeOf<MagicRegExp<'/./gm', never, [], 'g' | 'm'>>()
29+
expectTypeOf(re).toEqualTypeOf<MagicRegExp<'/\\./gm', never, [], 'g' | 'm'>>()
30+
})
31+
it('sanitize string input', () => {
32+
const escapeChars = '.*+?^${}()[]/'
33+
const re = createRegExp(escapeChars)
34+
expect(String(re)).toMatchInlineSnapshot(
35+
'"/\\\\.\\\\*\\\\+\\\\?\\\\^\\\\$\\\\{\\\\}\\\\(\\\\)\\\\[\\\\]\\\\//"'
36+
)
37+
expectTypeOf(re).toEqualTypeOf<
38+
MagicRegExp<'/\\.\\*\\+\\?\\^\\$\\{\\}\\(\\)\\[\\]\\//', never, []>
39+
>()
3040
})
3141
})
3242

0 commit comments

Comments
 (0)