Skip to content

Prevent invalid-regular expression syntax error in Safari < 16.4#202

Closed
tf wants to merge 1 commit into
flackr:masterfrom
tf:safari-invalid-group
Closed

Prevent invalid-regular expression syntax error in Safari < 16.4#202
tf wants to merge 1 commit into
flackr:masterfrom
tf:safari-invalid-group

Conversation

@tf

@tf tf commented Jan 8, 2024

Copy link
Copy Markdown

PR #177 added regular expressions to parse CSSNumericValue objects using lookbehind. Safari only supports lookbehind starting from version 16.4 [1]. In earlier versions loading the polyfill causes an error of the form:

SyntaxError: Invalid regular expression: invalid group specifier name

Compile RegExp on demand to ensure the polyfill can be loaded without errors. Since the relevant functions are only called initially when parsing options, the performance overhead appears limited.

[1] https://caniuse.com/js-regexp-lookbehind

@tf

tf commented Jan 8, 2024

Copy link
Copy Markdown
Author

Happy to consider caching the regexps if I'm missing use cases where the performance overhead of recompiling each time might become relevant. Shortly considered alternative ways to formulate the expressions without lookbehind, but couldn't think of anything that wouldn't make the code much more complex.

@bramus

bramus commented Jan 8, 2024

Copy link
Copy Markdown
Collaborator

Shortly considered alternative ways to formulate the expressions without lookbehind, but couldn't think of anything that wouldn't make the code much more complex.

I think this would be better to do, as it actually solves the underlying problem.

@tf tf marked this pull request as draft January 8, 2024 11:06
PR flackr#177 added regular expressions to parse CSSNumericValue objects
using lookbehind. Safari only supports lookbehind starting from
version 16.4 [1]. In earlier versions loading the polyfill causes an
error of the form:

```
SyntaxError: Invalid regular expression: invalid group specifier name
```

Compile RegExp on demand to ensure the polyfill can be loaded without
errors. Since the relevant functions are only called initially when
parsing options, the performance overhead appears limited.

[1] https://caniuse.com/js-regexp-lookbehind
@tf tf force-pushed the safari-invalid-group branch from 79c488f to 153ed40 Compare January 8, 2024 11:46
@tf

tf commented Jan 8, 2024

Copy link
Copy Markdown
Author

I agree that this would be the nicer solution, but the absence of unit tests makes the parsing logic rather scary to change. I played a bit with the current implementation and am still unsure which cases it is supposed to handle and if it does so correctly.

@johannesodland

Copy link
Copy Markdown
Contributor

I'm sorry for adding lookbehind without properly checking support.

I needed an implementation of CSSNumericValue.parse() that could parse simple math functions such as calc((1px + 2px) * 3), and some of the scroll-timelines subtests require CSSNumericValue.parse() to run. The lookbehind regex is used to split expressions such as (1px + 2px) * 3 into 1px + 2px and 3.

I agree that it would be better to add a proper implementation of CSSNumericValue.parse(). There are web platform tests, such as parse.tentative.html that can be used to test the method.

(Note that these tests fail if the the build is run with terser so it's necessary to build with the --no-compress flag, see #200)

Until we have a proper implementation, we could detect lookbehind-support and throw an error if a math-function is provided in parseCSSNumericValue:

function parseCSSNumericValue(value) {
value = value.trim();
if (value.match(/^[a-z(]/i)) {
return parseMathFunction(value);
} else {
return parseCSSUnitValue(value);
}
}

@tf

tf commented Jan 17, 2024

Copy link
Copy Markdown
Author

we could detect lookbehind-support

The problem is that using lookbehind in a literal is a syntax error that cannot be caught in JS. This is why I proposed the workaround to use dynamically compiled expressions.

@johannesodland

Copy link
Copy Markdown
Contributor

I implemented tokenization and parsing for CSSNumericValue.parse() in #206 if we want to go that route. Looking forward to having parse() in all browsers so we don't have to reimplement it when polyfilling 😅.

This will still leave one regexp in parseInset() where we need to consume a list of component values.

@johannesodland

Copy link
Copy Markdown
Contributor

I added a PR for a utility function splitIntoComponentValues() in #209 that would remove the need for the final lookahead regex in parseInset().

@johannesodland

Copy link
Copy Markdown
Contributor

All lookahead regexes have been replaced by proper parsing now. Is it ok to close this?

@bramus

bramus commented Feb 5, 2024

Copy link
Copy Markdown
Collaborator

When it comes to CSS, doing actual parsing indeed beats regexes. I think it’s fine to close this one indeed :)

@bramus bramus closed this Feb 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants