Skip to content

Commit 48b7b1f

Browse files
committed
fix(parser): ] only needs escape after [
1 parent bf0e4f4 commit 48b7b1f

File tree

2 files changed

+13
-17
lines changed

2 files changed

+13
-17
lines changed

src/code-point-range.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,11 @@ export function difference(rangeA: CodePointRange, rangeB: CodePointRange): [] |
112112
/**
113113
* Returns true iff the given char must always be escaped to occur literally
114114
* in a regular expression. Some special chars like `$` don't need to be
115-
* escaped when inside brackets (e.g. `/[$]/`). But `\` and `]` must
116-
* even be escaped when inside brackets.
115+
* escaped when inside brackets (e.g. `/[$]/`). But `\` must even be
116+
* escaped when inside brackets. And `]` must only be escaped inside brackets.
117117
*/
118-
export function mustAlwaysBeEscaped(char: string) {
119-
return '\\\]/'.includes(char)
118+
export function mustBeEscapedInsideBrackets(char: string) {
119+
return char === '\\' || char === ']'
120120
}
121121

122122
/**
@@ -125,18 +125,14 @@ export function mustAlwaysBeEscaped(char: string) {
125125
* for special chars like `$`. Outside brackets we have to write `\$`.
126126
* Inside brackets `[$]` is allowed.
127127
*/
128-
export function mustBeEscapedOrInBrackets(char: string) {
129-
return '.^$*+?()[|/'.includes(char)
130-
}
131-
132-
export function neverMustBeEscaped(char: string) {
133-
return !mustAlwaysBeEscaped(char) && !mustBeEscapedOrInBrackets(char)
128+
export function mustBeEscapedOutsideBrackets(char: string) {
129+
return '.^$*+?()[|/\\'.includes(char)
134130
}
135131

136132
function codePointToString(codePoint: number): string {
137133
const char = String.fromCharCode(codePoint)
138134

139-
if (mustAlwaysBeEscaped(char) || mustBeEscapedOrInBrackets(char))
135+
if (mustBeEscapedInsideBrackets(char) || mustBeEscapedOutsideBrackets(char))
140136
// e.g. \$ \+ \.
141137
return '\\' + char
142138
else if (codePoint > 126)

src/regex-parser.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,12 @@ const wildcard = P.string('.').map(
3737
() => RE.literal(CharSet.wildcard({ dotAll: false }))
3838
)
3939

40-
const unescapedChar = P.satisfy(Range.neverMustBeEscaped)
41-
4240
const alphaNumChar = P.satisfy(char => /^[a-zA-Z0-9]$/.test(char))
4341

44-
const unescapedCharInsideBrackets = P.satisfy(Range.mustBeEscapedOrInBrackets)
42+
const unescapedCharInsideBrackets = P.satisfy(char => !Range.mustBeEscapedInsideBrackets(char))
43+
.map(CharSet.singleton)
44+
45+
const unescapedCharOutsideBrackets = P.satisfy(char => !Range.mustBeEscapedOutsideBrackets(char))
4546
.map(CharSet.singleton)
4647

4748
export class UnsupportedSyntaxError extends Error {}
@@ -96,15 +97,14 @@ const alphaNumRange: P.Parser<CharSet.CharSet> = alphaNumChar.andThen(start =>
9697

9798
const charSet = P.choice([
9899
P.between(
99-
// QUESTION: can brackets be nested?
100+
// square brackets cant't be nested
100101
P.string('['),
101102
P.string(']'),
102103
P.optional(P.string('^')).andThen(negated =>
103104
P.many(P.choice([
104105
escapeSequence, // e.g. "\$", "\]"
105106
alphaNumRange, // e.g. "a-z", "0-9" (will also match just "a", "3")
106107
unescapedCharInsideBrackets, // e.g. "$", "."
107-
unescapedChar.map(CharSet.singleton), // e.g. "#", "%"
108108
])).map(
109109
sets => {
110110
if (negated === undefined)
@@ -115,7 +115,7 @@ const charSet = P.choice([
115115
)
116116
)
117117
),
118-
unescapedChar.map(CharSet.singleton),
118+
unescapedCharOutsideBrackets,
119119
])
120120

121121
const group = P.between(

0 commit comments

Comments
 (0)