Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 7d03ece

Browse files
Tests: Added test for zero-width lookbehinds (PrismJS#2220)
1 parent 8d2c5a3 commit 7d03ece

File tree

1 file changed

+53
-34
lines changed

1 file changed

+53
-34
lines changed

‎tests/pattern-tests.js‎

Lines changed: 53 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,31 @@ function testPatterns(Prism) {
147147
});
148148
}
149149

150+
/**
151+
* Returns whether the given element will always have zero width meaning that it doesn't consume characters.
152+
*
153+
* @param {Element} element
154+
* @returns {boolean}
155+
*/
156+
function isAlwaysZeroWidth(element) {
157+
switch (element.type) {
158+
case 'Assertion':
159+
// assertions == ^, ,ドル \b, lookarounds
160+
return true;
161+
case 'Quantifier':
162+
return element.max === 0 || isAlwaysZeroWidth(element.element);
163+
case 'CapturingGroup':
164+
case 'Group':
165+
// every element in every alternative has to be of zero length
166+
return element.alternatives.every(alt => alt.elements.every(isAlwaysZeroWidth));
167+
case 'Backreference':
168+
// on if the group referred to is of zero length
169+
return isAlwaysZeroWidth(element.resolved);
170+
default:
171+
return false; // what's left are characters
172+
}
173+
}
174+
150175

151176
it('- should not match the empty string', function () {
152177
forEachPattern(({ pattern, tokenPath }) => {
@@ -168,32 +193,7 @@ function testPatterns(Prism) {
168193
});
169194
});
170195

171-
it('- should not have lookbehind groups which can be preceded by other some characters', function () {
172-
/**
173-
* Returns whether the given element will have zero length meaning that it doesn't extend the matched string.
174-
*
175-
* @param {Element} element
176-
* @returns {boolean}
177-
*/
178-
function isZeroLength(element) {
179-
switch (element.type) {
180-
case 'Assertion':
181-
// assertions == ^, ,ドル \b, lookarounds
182-
return true;
183-
case 'Quantifier':
184-
return element.max === 0 || isZeroLength(element.element);
185-
case 'CapturingGroup':
186-
case 'Group':
187-
// every element in every alternative has to be of zero length
188-
return element.alternatives.every(alt => alt.elements.every(isZeroLength));
189-
case 'Backreference':
190-
// on if the group referred to is of zero length
191-
return isZeroLength(element.resolved);
192-
default:
193-
return false; // what's left are characters
194-
}
195-
}
196-
196+
it('- should not have lookbehind groups that can be preceded by other some characters', function () {
197197
/**
198198
* Returns whether the given element will always match the start of the string.
199199
*
@@ -205,7 +205,7 @@ function testPatterns(Prism) {
205205
switch (parent.type) {
206206
case 'Alternative':
207207
// all elements before this element have to of zero length
208-
if (!parent.elements.slice(0, parent.elements.indexOf(element)).every(isZeroLength)) {
208+
if (!parent.elements.slice(0, parent.elements.indexOf(element)).every(isAlwaysZeroWidth)) {
209209
return false;
210210
}
211211
const grandParent = parent.parent;
@@ -216,7 +216,7 @@ function testPatterns(Prism) {
216216
}
217217

218218
case 'Quantifier':
219-
if (parent.max ===null/* null == open ended */||parent.max>= 2) {
219+
if (parent.max >= 2) {
220220
return false;
221221
} else {
222222
return isFirstMatch(parent);
@@ -228,13 +228,32 @@ function testPatterns(Prism) {
228228
}
229229

230230
forEachPattern(({ ast, tokenPath, lookbehind }) => {
231-
if (lookbehind) {
232-
forEachCapturingGroup(ast.pattern, ({ group, number }) => {
233-
if (number === 1 && !isFirstMatch(group)) {
234-
assert.fail(`Token ${tokenPath}: The lookbehind group (if matched at all) always has to be at index 0 relative to the whole match.`);
235-
}
236-
});
231+
if (!lookbehind) {
232+
return;
237233
}
234+
forEachCapturingGroup(ast.pattern, ({ group, number }) => {
235+
if (number === 1 && !isFirstMatch(group)) {
236+
assert.fail(`Token ${tokenPath}: `
237+
+ `The lookbehind group (if matched) always has to be at index 0 relative to the whole match.`);
238+
}
239+
});
240+
});
241+
});
242+
243+
it('- should not have lookbehind groups that only have zero-width alternatives', function () {
244+
forEachPattern(({ ast, tokenPath, lookbehind, reportError }) => {
245+
if (!lookbehind) {
246+
return;
247+
}
248+
forEachCapturingGroup(ast.pattern, ({ group, number }) => {
249+
if (number === 1 && isAlwaysZeroWidth(group)) {
250+
const groupContent = group.raw.substr(1, group.raw.length - 2);
251+
const replacement = group.alternatives.length === 1 ? groupContent : `(?:${groupContent})`;
252+
reportError(`Token ${tokenPath}: The lookbehind group ${group.raw} does not consume characters. `
253+
+ `Therefor it is not necessary to use a lookbehind group. `
254+
+ `Replacing the lookbehind group with: ${replacement}`);
255+
}
256+
});
238257
});
239258
});
240259

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /