Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
wants to merge 1 commit into from

Conversation

tf
Copy link

@tf tf commented Jan 8, 2024

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
Copy link
Author

tf commented Jan 8, 2024

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
Copy link
Collaborator

bramus commented Jan 8, 2024

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
Copy link
Author

tf commented Jan 8, 2024

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
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
Copy link
Author

tf commented Jan 17, 2024

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
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
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
Contributor

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

@bramus
Copy link
Collaborator

bramus commented Feb 5, 2024

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