Skip to content

Add Regex+ engines with rr as default to close #854 - #855

Open
mathiasrw wants to merge 1 commit into
mainfrom
fix/854
Open

mathiasrw wants to merge 1 commit into
mainfrom
fix/854

Conversation

@mathiasrw

Copy link
Copy Markdown
Owner

Closes #854

Change

Regex+ by Steven Levithan is now behind the engines of -E:

Engine What it is
rr (the default, also default) Regex+ wrapped so it keeps compatibility with the native engines. Patterns are read as today, with no u or v flag unless -u, and the extended syntax of Regex+ on top: atomic groups (?>…), possessive quantifiers like a++, and subroutines \g<name> with (?(DEFINE)…). Only the transforms of Regex+ run, not its flags.
regex+v (also regex+ and V) Full Regex+: the v flag, free spacing (x), and only named groups capture (n).
regex+u (also U) The same with the u flag.
runtime The native engine of the runtime.
V8, JSC The same, and the run stops on the other runtime.
> echo aab | rexreplace '(?>a+)(b)' '[$1]'
[b]
> echo 3.12.0 | rexreplace '\b(?<v>\g<n>\.\g<n>\.\g<n>)(?(DEFINE)(?<n>0|[1-9]\d*))' 'v$<v>'
v3.12.0
  • Atomic groups and possessive quantifiers add a group of their own inside the regex. $1 in the replacement, in --js code and in --output-match still counts only the groups of the user. The status report with --verbose tells the engine and the added groups.
  • --literal gives the text as it is with every engine, also with the free spacing of regex+.
  • The RE2 placeholder is gone.

For the release note of v8

Every piece of extended syntax was an error in the native engines, except \g<name>. So a pattern that works today gives the same regex with rr. The one change: \g<name> was the text g<name>, and with rr it calls the group. -E runtime, -E V8 and -E JSC keep the old meaning.

The copy of Regex+

regex 6.1.0 and regex-utilities 2.3.0 are copied into src/libs, with their MIT licenses. The build bundles them, so there is no new runtime dependency. The bundle grows from 52 KB to 88 KB. Biome leaves the folder alone, so it stays easy to compare with upstream. The changes from upstream, listed in src/libs/README.md:

  1. The imports of regex-utilities are relative, as the build leaves bare imports out of the bundle.
  2. internals.js exports subroutines. Asked for upstream.
  3. rewrite() also gives hiddenCaptures, so the added groups can be skipped without RegExpSubclass, which makes .replace() 3 to 5 times slower.

When upstream exports subroutines, the copy goes and regex becomes a normal dependency. The README in src/libs has the steps.

Tests

test/fix/854.test.js is new, with 49 tests, and 47 fail without the change:

  • rr gives the same regex as the native engine for 24 legacy patterns, like \", a], \01, [a++] and [(?>].
  • rr reads atomic groups, possessive quantifiers, subroutines and DEFINE, and default is rr.
  • The added groups are not counted in $1, $2$1, $3 (stays text), $10, --js and --output-match.
  • JSC and runtime read \g<d> as text. regex+ and its other names have free spacing and only named groups capture. regex+u uses u and not v. regex+ stops the run on \", and --literal with regex+ finds a b #c (d) as it is.

The tests that named default as the engine of the runtime say rr now, and test/cli/run.sh shows an atomic group and -E runtime on Node and Bun. yarn test-ci passes.

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.

Add Regex+ engines, with rr as the default engine

1 participant