Skip to content

Commit

Permalink
Defer to native /s flag in ES2018 environments
Browse files Browse the repository at this point in the history
  • Loading branch information
slevithan committed Jan 17, 2021
1 parent fbd9869 commit 98abea8
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 20 deletions.
29 changes: 18 additions & 11 deletions src/xregexp.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ function hasNativeFlag(flag) {
}
return isSupported;
}
// Check for ES2018 `s` flag support
const hasNativeS = hasNativeFlag('s');
// Check for ES6 `u` flag support
const hasNativeU = hasNativeFlag('u');
// Check for ES6 `y` flag support
Expand All @@ -81,9 +83,12 @@ const registeredFlags = {
g: true,
i: true,
m: true,
s: hasNativeS,
u: hasNativeU,
y: hasNativeY
};
// Flags to remove when passing to native `RegExp` constructor
const nonnativeFlags = hasNativeS ? /[^gimsuy]+/g : /[^gimuy]+/g;

/**
* Attaches extended data and `XRegExp.prototype` properties to a regex object.
Expand Down Expand Up @@ -521,7 +526,7 @@ function setNamespacing(on) {
* - `y` - sticky (Firefox 3+, ES6)
* Additional XRegExp flags:
* - `n` - explicit capture
* - `s` - dot matches all (aka singleline)
* - `s` - dot matches all (aka singleline) - works even when not natively supported
* - `x` - free-spacing and line comments (aka extended)
* - `A` - astral (requires the Unicode Base addon)
* Flags cannot be provided when constructing one `RegExp` from another.
Expand Down Expand Up @@ -611,7 +616,7 @@ function XRegExp(pattern, flags) {
// separated. However, more than one empty group in a row is never needed.
pattern: output.replace(/(?:\(\?:\))+/g, '(?:)'),
// Strip all but native flags
flags: appliedFlags.replace(/[^gimuy]+/g, ''),
flags: appliedFlags.replace(nonnativeFlags, ''),
// `context.captureNames` has an item for each capturing group, even if unnamed
captures: context.hasNamedCapture ? context.captureNames : null
};
Expand Down Expand Up @@ -1772,16 +1777,18 @@ XRegExp.addToken(
);

/*
* Dot, in dotall mode (aka singleline mode, flag s) only.
* Dot, in dotAll mode (aka singleline mode, flag s) only.
*/
XRegExp.addToken(
/\./,
() => '[\\s\\S]',
{
flag: 's',
leadChar: '.'
}
);
if (!hasNativeS) {
XRegExp.addToken(
/\./,
() => '[\\s\\S]',
{
flag: 's',
leadChar: '.'
}
);
}

/*
* Named backreference: `\k<name>`. Backreference names can use RegExpIdentifierName characters
Expand Down
1 change: 1 addition & 0 deletions tests/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module.exports = {
"XRegExp": true,
"resetFeatures": true,
"REGEX_DATA": true,
"hasNativeS": true,
"hasNativeU": true,
"hasNativeY": true,
"hasStrictMode": true,
Expand Down
2 changes: 2 additions & 0 deletions tests/helpers/h.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ global.resetFeatures = function() {
// Property name used for extended regex instance data
global.REGEX_DATA = 'xregexp';

// Check for ES2018 `s` flag support
global.hasNativeS = XRegExp._hasNativeFlag('s');
// Check for ES6 `u` flag support
global.hasNativeU = XRegExp._hasNativeFlag('u');
// Check for ES6 `y` flag support
Expand Down
19 changes: 11 additions & 8 deletions tests/spec/s-xregexp.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,10 @@ describe('XRegExp()', function() {

// These properties are `undefined`, but future ES may define them with value `false`
it('should not set properties for nonnative flags', function() {
if (!hasNativeS) {
expect(XRegExp('', 's').dotAll).toBeFalsy();
}
expect(XRegExp('', 'n').explicitCapture).toBeFalsy();
expect(XRegExp('', 's').singleline).toBeFalsy();
expect(XRegExp('', 's').dotall).toBeFalsy();
expect(XRegExp('', 's').dotAll).toBeFalsy();
expect(XRegExp('', 'x').extended).toBeFalsy();
// Flag A is added by Unicode Base
//expect(XRegExp('', 'A').astral).toBeFalsy();
Expand Down Expand Up @@ -293,10 +293,10 @@ describe('XRegExp()', function() {

// These properties are `undefined`, but future ES may define them with value `false`
it('should not set properties for nonnative flags', function() {
if (!hasNativeS) {
expect(XRegExp('(?s)').dotAll).toBeFalsy();
}
expect(XRegExp('(?n)').explicitCapture).toBeFalsy();
expect(XRegExp('(?s)').singleline).toBeFalsy();
expect(XRegExp('(?s)').dotall).toBeFalsy();
expect(XRegExp('(?s)').dotAll).toBeFalsy();
expect(XRegExp('(?x)').extended).toBeFalsy();
// Flag A is added by Unicode Base
//expect(XRegExp('(?A)').astral).toBeFalsy();
Expand Down Expand Up @@ -332,8 +332,11 @@ describe('XRegExp()', function() {
expect(regex.ignoreCase).toBe(true);
expect(regex.global).toBe(true);
expect(regex.multiline).toBe(true);
// Test nonnative flag s
expect(regex.test('\n')).toBe(true);
if (hasNativeS) {
expect(regex.dotAll).toBe(true);
} else {
expect(regex.test('\n')).toBe(true);
}
});

it('should throw an exception if unknown flags are used', function() {
Expand Down
2 changes: 1 addition & 1 deletion types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export = XRegExp;
*
* Additional XRegExp flags:
* - `n` - explicit capture
* - `s` - dot matches all (aka singleline)
* - `s` - dot matches all (aka singleline) - works even when not natively supported
* - `x` - free-spacing and line comments (aka extended)
* - `A` - astral (requires the Unicode Base addon)
*
Expand Down

0 comments on commit 98abea8

Please sign in to comment.