Skip to content

Commit

Permalink
Rename env support vars
Browse files Browse the repository at this point in the history
  • Loading branch information
slevithan committed Nov 17, 2024
1 parent 79758bd commit e2ba7d4
Show file tree
Hide file tree
Showing 13 changed files with 60 additions and 64 deletions.
2 changes: 1 addition & 1 deletion spec/atomic.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ describe('possessive quantifiers', () => {
expect('aa1').toMatch(regex`^[a-z]++1$`);
expect('abb').not.toMatch(regex`^[a][\x62]++.$`);
expect('ab1').toMatch(regex`^[a][\x62]++1$`);
if (flagVSupported) {
if (envSupportsFlagV) {
expect('aaa').not.toMatch(regex`^[[a-z]--y]++.$`);
expect('aa1').toMatch(regex`^[[a-z]--y]++1$`);
}
Expand Down
2 changes: 1 addition & 1 deletion spec/backcompat.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ describe('backcompat', () => {
expect(regex({disable: {v: true}})``.flags).toContain('u');
expect(regex({disable: {v: true}})``.unicode).toBeTrue();
expect(regex({disable: {v: true}, flags: 'g'})``.unicode).toBeTrue();
if (!flagVSupported) {
if (!envSupportsFlagV) {
expect(regex``.flags).toContain('u');
expect(regex``.unicode).toBeTrue();
expect(regex('g')``.unicode).toBeTrue();
Expand Down
10 changes: 5 additions & 5 deletions spec/flag-x.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ describe('flag x', () => {
'[\\0 -- b]',
];
valid.forEach(v => {
if (flagVSupported) {
if (envSupportsFlagV) {
expect(() => regex()({raw: [v]})).withContext(v).not.toThrow();
}
// Invalid set operator error from built-in `unicodeSetsPlugin`
Expand All @@ -297,7 +297,7 @@ describe('flag x', () => {
});

it('should allow set operators to be offset by whitespace', () => {
if (flagVSupported) {
if (envSupportsFlagV) {
expect('a').toMatch(regex`[\w -- _]`);
expect('a').toMatch(regex`[\w-- _]`);
expect('a').toMatch(regex`[\w --_]`);
Expand All @@ -322,7 +322,7 @@ describe('flag x', () => {
it('should allow escaping whitespace to make it significant', () => {
expect(' ').toMatch(regex`^[ \ ]$`);
expect('t ').toMatch(regex`^[\ t]{2}$`);
if (flagVSupported) {
if (envSupportsFlagV) {
expect(' ').toMatch(regex`^[\q{ \ }]$`);
} else {
expect(() => regex`^[\q{ \ }]$`).toThrow();
Expand All @@ -336,7 +336,7 @@ describe('flag x', () => {
});

it('should treat whitespace in [\\q{}] as insignificant', () => {
if (flagVSupported) {
if (envSupportsFlagV) {
expect('ab').toMatch(regex`^[\q{ a b | c }]$`);
} else {
expect(() => regex`^[\q{ a b | c }]$`).toThrow();
Expand All @@ -346,7 +346,7 @@ describe('flag x', () => {
it('should handle empty character classes with insignificant whitespace', () => {
expect(/[]/.test('a')).toBe(regex`[ ]`.test('a'));
expect(/[^]/.test('a')).toBe(regex`[^ ]`.test('a'));
if (flagVSupported) {
if (envSupportsFlagV) {
expect(new RegExp('[\\q{}]', 'v').test('a')).toBe(regex`[ \q{ } ]`.test('a'));
} else {
expect(() => regex`[ \q{ } ]`).toThrow();
Expand Down
24 changes: 12 additions & 12 deletions spec/helpers/features.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
globalThis.patternModsSupported = (() => {
globalThis.envSupportsDuplicateNames = (() => {
try {
new RegExp('(?i:)');
} catch (e) {
new RegExp('(?<n>)|(?<n>)');
} catch {
return false;
}
return true;
})();

globalThis.duplicateCaptureNamesSupported = (() => {
globalThis.envSupportsFlagGroups = (() => {
try {
new RegExp('(?<n>)|(?<n>)');
} catch (e) {
new RegExp('(?i:)');
} catch {
return false;
}
return true;
})();

globalThis.flagVSupported = (() => {
globalThis.envSupportsFlagD = (() => {
try {
new RegExp('', 'v');
} catch (e) {
new RegExp('', 'd');
} catch {
return false;
}
return true;
})();

globalThis.flagDSupported = (() => {
globalThis.envSupportsFlagV = (() => {
try {
new RegExp('', 'd');
} catch (e) {
new RegExp('', 'v');
} catch {
return false;
}
return true;
Expand Down
2 changes: 1 addition & 1 deletion spec/interpolate-number.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe('interpolation: numbers', () => {
describe('in character class context', () => {
it('should coerce to string', () => {
expect('5').toMatch(regex`^[1-${9}]$`);
if (flagVSupported) {
if (envSupportsFlagV) {
expect('99').toMatch(regex`^[\q{${99}}]$`);
}
});
Expand Down
10 changes: 5 additions & 5 deletions spec/interpolate-pattern.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ describe('interpolation: patterns', () => {
expect(() => regex`[a${pattern`]`}b]`).toThrow();
expect(']').toMatch(regex`[${pattern(String.raw`\]`)}]`);
expect(() => regex`[a${pattern(String.raw`\\]`)}b]`).toThrow();
if (flagVSupported) {
if (envSupportsFlagV) {
expect(']').toMatch(regex`[${pattern(String.raw`\\\]`)}]`);
} else {
expect(() => regex`[${pattern(String.raw`\\\]`)}]`).toThrow();
Expand All @@ -180,7 +180,7 @@ describe('interpolation: patterns', () => {
expect(() => regex`[a${pattern`[`}b]`).toThrow();
expect('[').toMatch(regex`[${pattern(String.raw`\[`)}]`);
expect(() => regex`[a${pattern(String.raw`\\[`)}b]`).toThrow();
if (flagVSupported) {
if (envSupportsFlagV) {
expect('[').toMatch(regex`[${pattern(String.raw`\\\[`)}]`);
} else {
expect(() => regex`[${pattern(String.raw`\\\[`)}]`).toThrow();
Expand All @@ -203,7 +203,7 @@ describe('interpolation: patterns', () => {
expect(() => regex`[\q{${pattern`a}`}]`).toThrow();
expect(() => regex`[\q{${pattern`a}`}}]`).toThrow();
expect(() => regex`[\q{${pattern`a\\}`}}]`).toThrow();
if (flagVSupported) {
if (envSupportsFlagV) {
expect('a}').toMatch(regex`[\q{${pattern`a\}`}}]`);
} else {
expect(() => regex`[\q{${pattern`a\}`}}]`).toThrow();
Expand Down Expand Up @@ -266,7 +266,7 @@ describe('interpolation: patterns', () => {
});

it('should allow a self-contained set operation', () => {
if (flagVSupported) {
if (envSupportsFlagV) {
expect('a').toMatch(regex`[${pattern`\w--_`}]`);
expect('a').toMatch(regex`[${pattern`\w&&a`}]`);
expect('a').toMatch(regex`[${pattern`\w&&[a-z]`}]`);
Expand Down Expand Up @@ -316,7 +316,7 @@ describe('interpolation: patterns', () => {
});

it('should not throw if a lone double-punctuator character in an implicit union is bordered by itself', () => {
if (flagVSupported) {
if (envSupportsFlagV) {
expect('&').toMatch(regex`[${pattern`a&`}&]`);
expect('!').toMatch(regex`[${pattern`a!`}!]`);
expect('#').toMatch(regex`[${pattern`a#`}#]`);
Expand Down
12 changes: 5 additions & 7 deletions spec/interpolate-regexp.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe('interpolation: regexes', () => {
});

it('should preserve local flag i or its absense, or throw if support is unavailable', () => {
if (patternModsSupported) {
if (envSupportsFlagGroups) {
expect('foo-BAR'). toMatch(regex `foo-${/bar/i}`);
expect('FOO-BAR').not.toMatch(regex `foo-${/bar/i}`);
expect('FOO-bar'). toMatch(regex('i')`foo-${/bar/}`);
Expand All @@ -35,12 +35,11 @@ describe('interpolation: regexes', () => {
});

it('should preserve multiple flag differences on outer/inner regex', () => {
if (patternModsSupported) {
if (envSupportsFlagGroups) {
expect('AAa\n'). toMatch(regex('i')`a.${/a./s}`);
expect('AAA\n'). not.toMatch(regex('i')`a.${/a./s}`);
expect('A\na\n').not.toMatch(regex('i')`a.${/a./s}`);
}

expect('\nxa\n'). toMatch(regex('m')`^.${/a.$/s}`);
expect('\n\na\n'). not.toMatch(regex('m')`^.${/a.$/s}`);
expect('\nxa\n\n').not.toMatch(regex('m')`^.${/a.$/s}`);
Expand All @@ -64,11 +63,10 @@ describe('interpolation: regexes', () => {
});

it('should treat pattern modifiers as noncapturing when adjusting backreferences', () => {
if (patternModsSupported) {
expect('abb').toMatch(regex`^(?i:a)${/(b)\1/}$`);
} else {
// Will throw a SyntaxError either way in environments that don't support pattern modifiers
if (!envSupportsFlagGroups) {
pending('requires support for flag groups (Node 23)');
}
expect('abb').toMatch(regex`^(?i:a)${/(b)\1/}$`);
});
});

Expand Down
2 changes: 1 addition & 1 deletion spec/interpolate-string.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ describe('interpolation: escaped strings', () => {

describe('in character class context', () => {
it('should coerce non-string/number/regex/pattern values', () => {
if (flagVSupported) {
if (envSupportsFlagV) {
expect('u').toMatch(regex`^[${undefined}]$`);
expect('a').toMatch(regex`^[[a-z]--${null}]$`);
expect('n').not.toMatch(regex`^[[a-z]--${null}]$`);
Expand Down
25 changes: 11 additions & 14 deletions spec/regex-tag.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe('regex', () => {
expect(regex('m')``.multiline).toBeTrue();
expect(regex('s')``.dotAll).toBeTrue();
expect(regex('y')``.sticky).toBeTrue();
if (flagDSupported) {
if (envSupportsFlagD) {
expect(regex('d')``.hasIndices).toBeTrue();
}
});
Expand All @@ -31,7 +31,7 @@ describe('regex', () => {

it('should implicitly add flag v or u', () => {
// See also `backcompat-spec.js`
if (flagVSupported) {
if (envSupportsFlagV) {
expect(regex``.flags).toContain('v');
expect(regex``.unicodeSets).toBeTrue();
expect(regex('g')``.unicodeSets).toBeTrue();
Expand Down Expand Up @@ -87,7 +87,7 @@ describe('regex', () => {
it('should allow swapping the built-in unicodeSetsPlugin', () => {
const plugin = str => str.replace(/v/g, 'u');
expect('u').toMatch(regex({unicodeSetsPlugin: plugin, disable: {v: true}})`^v$`);
if (!flagVSupported) {
if (!envSupportsFlagV) {
expect('u').toMatch(regex({unicodeSetsPlugin: plugin})`^v$`);
}
});
Expand All @@ -102,7 +102,7 @@ describe('regex', () => {

it('should not use the unicodeSetsPlugin when flag v is used', () => {
const plugin = str => str.replace(/v/g, 'u');
if (flagVSupported) {
if (envSupportsFlagV) {
expect('v').toMatch(regex({unicodeSetsPlugin: plugin})`^v$`);
} else {
expect(() => regex({unicodeSetsPlugin: plugin, force: {v: true}})`^v$`).toThrow();
Expand All @@ -111,15 +111,15 @@ describe('regex', () => {

it('should allow controlling implicit flag v via disable.v', () => {
expect(regex({disable: {v: true}})``.unicodeSets).not.toBeTrue();
if (flagVSupported) {
if (envSupportsFlagV) {
expect(regex({disable: {v: false}})``.unicodeSets).toBeTrue();
} else {
expect(regex({disable: {v: false}})``.unicodeSets).not.toBeTrue();
}
});

it('should allow controlling implicit flag v via force.v', () => {
if (flagVSupported) {
if (envSupportsFlagV) {
expect(regex({force: {v: true}, disable: {v: true}})``.unicodeSets).toBeTrue();
} else {
expect(() => regex({force: {v: true}})``).toThrow();
Expand All @@ -140,8 +140,7 @@ describe('regex', () => {
expect('ab'.replace(regex({subclass: true})`(?>(?<a>.))(?<b>.)`, '$2$1')).toBe('ba');
// String#replace: replacement function
expect('ab'.replace(regex({subclass: true})`(?>(?<a>.))(?<b>.)`, (_, $1, $2) => $2 + $1)).toBe('ba');

// Documenting behavior when the option is not used
// ## Documenting behavior when subclass is not used
expect(regex({subclass: false})`(?>(?<a>.))(?<b>.)`.exec('ab')[2]).not.toBe('b');
expect('ab'.replace(regex({subclass: false})`(?>(?<a>.))(?<b>.)`, '$2$1')).not.toBe('ba');
expect('ab'.replace(regex({subclass: false})`(?>(?<a>.))(?<b>.)`, (_, $1, $2) => $2 + $1)).not.toBe('ba');
Expand All @@ -152,19 +151,17 @@ describe('regex', () => {
expect([...'ab'.matchAll(regex({flags: 'g', subclass: true})`(?>(?<a>.))(?<b>.)`)][0][2]).toBe('b');
// String#split
expect('ab'.split(regex({subclass: true})`(?>(?<a>.))(?<b>.)`)).toEqual(['', 'a', 'b', '']);

// Documenting behavior when the option is not used
// ## Documenting behavior when subclass is not used
expect([...'ab'.matchAll(regex({flags: 'g', subclass: false})`(?>(?<a>.))(?<b>.)`)][0][2]).not.toBe('b');
expect('ab'.split(regex({subclass: false})`(?>(?<a>.))(?<b>.)`)).not.toEqual(['', 'a', 'b', '']);
});

it('should adjust indices with flag d for emulation groups', () => {
if (!flagDSupported) {
pending();
if (!envSupportsFlagD) {
pending('requires support for flag d (Node 16)');
}
expect(regex({flags: 'd', subclass: true})`(?>.)`.exec('a').indices).toHaveSize(1);

// Documenting behavior when the option is not used
// ## Documenting behavior when subclass is not used
expect(regex({flags: 'd', subclass: false})`(?>.)`.exec('a').indices).toHaveSize(2);
});
});
Expand Down
2 changes: 1 addition & 1 deletion spec/rewrite.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe('rewrite', () => {

describe('implicit flags', () => {
it('should implicitly add flag v or u', () => {
expect(rewrite('').flags).toContain(flagVSupported ? 'v' : 'u');
expect(rewrite('').flags).toContain(envSupportsFlagV ? 'v' : 'u');
expect(rewrite('', {disable: {v: true}}).flags).toContain('u');
});

Expand Down
13 changes: 7 additions & 6 deletions spec/subroutines.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,13 +129,14 @@ describe('subroutines', () => {
});

it('should refer to the first group with name when duplicate capture names exist', () => {
if (duplicateCaptureNamesSupported) {
expect('aa ba bb'.match(regex('g')`(?<n>a)|(?<n>b)\g<n>`)).toEqual(['a', 'a', 'ba']);
expect('aa ba bb'.match(regex('g')`(?<n>a)\g<n>|(?<n>b)`)).toEqual(['aa', 'b', 'b', 'b']);
expect('aa ba bb'.match(regex('g')`(?<n>a)\g<n>|(?<n>b)\g<n>`)).toEqual(['aa', 'ba']);
expect('b1 ab2ab1 ab2ab2'.match(regex('g')`(?<b>b1)|(?<n>a(?<b>b2))\g<n>`)).toEqual(['b1', 'b1', 'ab2ab2']);
expect('b1 ab2b2ab2b2 ab2b1ab2b1'.match(regex('g')`(?<b>b1)|(?<n>a(?<b>b2)\g<b>)\g<n>`)).toEqual(['b1', 'ab2b1ab2b1']);
if (!envSupportsDuplicateNames) {
pending('requires support for duplicate names (Node 23)');
}
expect('aa ba bb'.match(regex('g')`(?<n>a)|(?<n>b)\g<n>`)).toEqual(['a', 'a', 'ba']);
expect('aa ba bb'.match(regex('g')`(?<n>a)\g<n>|(?<n>b)`)).toEqual(['aa', 'b', 'b', 'b']);
expect('aa ba bb'.match(regex('g')`(?<n>a)\g<n>|(?<n>b)\g<n>`)).toEqual(['aa', 'ba']);
expect('b1 ab2ab1 ab2ab2'.match(regex('g')`(?<b>b1)|(?<n>a(?<b>b2))\g<n>`)).toEqual(['b1', 'b1', 'ab2ab2']);
expect('b1 ab2b2ab2b2 ab2b1ab2b1'.match(regex('g')`(?<b>b1)|(?<n>a(?<b>b2)\g<b>)\g<n>`)).toEqual(['b1', 'ab2b1ab2b1']);
});

it('should support specifying the group to match via interpolation', () => {
Expand Down
12 changes: 6 additions & 6 deletions src/regex.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {clean, flagXPreprocessor} from './flag-x.js';
import {Pattern, pattern} from './pattern.js';
import {RegExpSubclass} from './subclass.js';
import {subroutines} from './subroutines.js';
import {adjustNumberedBackrefs, CharClassContext, containsCharClassUnion, countCaptures, enclosedTokenCharClassContexts, enclosedTokenRegexContexts, escapeV, flagVSupported, getBreakoutChar, getEndContextForIncompleteExpression, patternModsSupported, preprocess, RegexContext, sandboxLoneCharClassCaret, sandboxLoneDoublePunctuatorChar, sandboxUnsafeNulls} from './utils.js';
import {adjustNumberedBackrefs, CharClassContext, containsCharClassUnion, countCaptures, enclosedTokenCharClassContexts, enclosedTokenRegexContexts, envSupportsFlagGroups, envSupportsFlagV, escapeV, getBreakoutChar, getEndContextForIncompleteExpression, preprocess, RegexContext, sandboxLoneCharClassCaret, sandboxLoneDoublePunctuatorChar, sandboxUnsafeNulls} from './utils.js';
import {Context, hasUnescaped, replaceUnescaped} from 'regex-utilities';

/**
Expand Down Expand Up @@ -159,7 +159,7 @@ function getOptions(options) {
if (/[nuvx]/.test(opts.flags)) {
throw new Error('Implicit flags v/u/x/n cannot be explicitly added');
}
const useFlagV = opts.force.v || (opts.disable.v ? false : flagVSupported);
const useFlagV = opts.force.v || (opts.disable.v ? false : envSupportsFlagV);
opts.flags += useFlagV ? 'v' : 'u';
if (useFlagV) {
opts.unicodeSetsPlugin = null;
Expand Down Expand Up @@ -307,28 +307,28 @@ function transformForLocalFlags(re, outerFlags) {
const newlines = '\\n\\r\\u2028\\u2029';
let value = re.source;
if (re.ignoreCase !== outerFlags.includes('i')) {
if (patternModsSupported) {
if (envSupportsFlagGroups) {
modFlagsObj.i = re.ignoreCase;
} else {
throw new Error('Pattern modifiers not supported, so flag i on the outer and interpolated regex must match');
}
}
if (re.dotAll !== outerFlags.includes('s')) {
if (patternModsSupported) {
if (envSupportsFlagGroups) {
modFlagsObj.s = re.dotAll;
} else {
value = replaceUnescaped(value, '\\.', (re.dotAll ? '[^]' : `[^${newlines}]`), Context.DEFAULT);
}
}
if (re.multiline !== outerFlags.includes('m')) {
if (patternModsSupported) {
if (envSupportsFlagGroups) {
modFlagsObj.m = re.multiline;
} else {
value = replaceUnescaped(value, '\\^', (re.multiline ? `(?<=^|[${newlines}])` : '(?<![^])'), Context.DEFAULT);
value = replaceUnescaped(value, '\\$', (re.multiline ? `(?=$|[${newlines}])` : '(?![^])'), Context.DEFAULT);
}
}
if (patternModsSupported) {
if (envSupportsFlagGroups) {
const keys = Object.keys(modFlagsObj);
let modifier = keys.filter(k => modFlagsObj[k] === true).join('');
const modOff = keys.filter(k => modFlagsObj[k] === false).join('');
Expand Down
Loading

0 comments on commit e2ba7d4

Please sign in to comment.