Skip to content

Commit

Permalink
Include the generated source in invalid regex err msgs in all envs (#25)
Browse files Browse the repository at this point in the history
  • Loading branch information
slevithan committed Oct 1, 2024
1 parent 01dc837 commit 3cccaff
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 3 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## Unreleased changes

### 🚀 Features

- When an invalid regex throws, include the generated source in the error message (some browsers automatically include the source, but Firefox and Safari don't).

### 🐞 Fixes

- Convert numbers interpolated in enclosed `\u{…}` to hexadecimal. In other words, although `` regex`\u{${'160'}}` `` (string interpolated) returns `/\u{160}/`, `` regex`\u{${160}}` `` (number interpolated) now returns `/\u{A0}/`. (#24, @graphemecluster)
Expand Down
1 change: 1 addition & 0 deletions spec/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<script src="./regex-tag.spec.js"></script>
<script src="./rewrite.spec.js"></script>
<script src="./pattern.spec.js"></script>
<script src="./interpolate-number.spec.js"></script>
<script src="./interpolate-pattern.spec.js"></script>
<script src="./interpolate-regexp.spec.js"></script>
<script src="./interpolate-string.spec.js"></script>
Expand Down
11 changes: 11 additions & 0 deletions spec/regex-tag.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,17 @@ describe('regex', () => {
expect(() => regex({}, {raw: ['']})).toThrow();
});

it('should include the generated regex in the error if the RegExp constructor throws', () => {
const values = [
['\\u', '\\u'],
['(?<a>.)\\g<a>|*', '(?<a>.)(?:.)|*'],
];
values.forEach(([input, output]) => {
expect(() => regex({raw: [input]})).toThrowMatching(err => err.message.includes(`/${output}/`));
expect(() => regex({subclass: true})({raw: [input]})).toThrowMatching(err => err.message.includes(`/${output}/`));
});
});

describe('options', () => {
it('should allow setting flags via an option', () => {
expect(regex({flags: ''})``.global).toBeFalse();
Expand Down
16 changes: 13 additions & 3 deletions src/regex.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,21 @@ const regexFromTemplate = (options, template, ...substitutions) => {
});

expression = handlePlugins(expression, opts);
let captureMap;
if (opts.subclass) {
const unmarked = unmarkEmulationGroups(expression);
return new WrappedRegExp(unmarked.expression, opts.flags, {captureMap: unmarked.captureMap});
({expression, captureMap} = unmarkEmulationGroups(expression));
}
try {
return opts.subclass ?
new WrappedRegExp(expression, opts.flags, {captureMap}) :
new RegExp(expression, opts.flags);
} catch (err) {
// Improve DX by always including the generated source in the error message. Some browsers
// include it automatically, but not Firefox or Safari
const stripped = err.message.replace(/ \/.+\/[a-z]*:/, '');
err.message = `${stripped}: /${expression}/${opts.flags}`;
throw err;
}
return new RegExp(expression, opts.flags);
}

/**
Expand Down

0 comments on commit 3cccaff

Please sign in to comment.