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

Fix case-insensitive set operations #104

Merged
merged 18 commits into from
Nov 21, 2024
Merged

Conversation

JLHwung
Copy link
Collaborator

@JLHwung JLHwung commented Oct 15, 2024

Fixes #103.

In this PR we applied scf() on the class set operand before doing any set operations.

We also maintain the config.modifiersData even when we are not transforming modifiers, as more and more features will depend on this context data.

In this PR we add unicode case equivalents before we are computing the intersection / substraction. The spec applies MaybeSimpleCaseFolding to every character (loosely like toLowerCase) while we are actually adding unicode case equivalents to every character. I think there is an equivalence relationship between the canonical form (e.g. k) and the set of its case equivalents (e.g. {k, K, \u212A}), so the regex behaviour should not be changed.

The cons is that we are generating longer than necessary output when the matcher set contains both uppercase / lowercase letters within the i modifier.

@nicolo-ribaudo
Copy link
Collaborator

The cons is that we are generating longer than necessary output when the matcher set contains both uppercase / lowercase letters within the i modifier.

Can we do some sort of minification? i.e. if there is the i modifier on the regexp, we deduplicate characters that have the same canonical form.

@JLHwung
Copy link
Collaborator Author

JLHwung commented Oct 30, 2024

Can we do some sort of minification?

To do the minification for all unicode codepoints we will need the oneWayMappings defined here:

const commonMappings = require('@unicode/unicode-16.0.0/Case_Folding/C/code-points.js');
const simpleMappings = require('@unicode/unicode-16.0.0/Case_Folding/S/code-points.js');
// We want the `C` mappings in both directions (i.e. `A` should fold to `a`
// and `a` to `A`), and the `S` mappings in both directions (i.e. `ẞ` should
// fold to `ß` and `ß` to `ẞ`). Let’s start with the simple case folding (in
// one direction) first, then filter the set, and then deal with the inverse.
const oneWayMappings = new Map();
for (const [from, to] of commonMappings) {
oneWayMappings.set(from, to);
}
for (const [from, to] of simpleMappings) {
oneWayMappings.set(from, to);
}

which matches uppercase to lowercase (loosely speaking). This mapping is not yet exposed as data. Currently we only have map from character to its unicode case-insensitive equivalents: we don't know which one is "lowercase" and thus should be minified to.

If we expose this mapping, then I can just implement the MaybeSimpleCaseFolding and hopefully the generated regex will be always minimal so we can get rid of the extra minification pass, but that of course will increase the code size of this package as we will have two different mapping data derived from the same unicode data source. What do you think about this approach?

@JLHwung
Copy link
Collaborator Author

JLHwung commented Oct 31, 2024

This PR is ready for preview. I plan to cut a new minor release (because of #98) after this PR gets merged.


ESCAPE_CHARS_UNICODESET_IGNORE_CASE[upper] = {
toCode() {
return 'UNICODE_IV_SET.clone().remove(' + ESCAPE_CHARS_UNICODESET_IGNORE_CASE[lower].toCode() + ')';
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we override the toCode prototype method for a much smaller output.

@mathiasbynens
Copy link
Owner

Thanks!

@JLHwung JLHwung merged commit 924446a into mathiasbynens:main Nov 21, 2024
4 checks passed
@JLHwung JLHwung deleted the fix-103 branch November 21, 2024 20:12
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.

Internal error when transforming set intersection in ignoreCase mode
3 participants