@ericcornelissen/lregexp 1.0.5 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Eric Cornelissen
3
+ Copyright (c) 2025-2026 Eric Cornelissen
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,21 +1,35 @@
1
+ <!-- SPDX-License-Identifier: CC0-1.0 -->
2
+
1
3
  # lRegExp
2
4
 
3
- Transparently create linear-time ([non-backtracking]) regular expressions.
5
+ Transparent linear-time ([non-backtracking]) regular expressions for libraries.
4
6
 
5
7
  [non-backtracking]: https://v8.dev/blog/non-backtracking-regexp
6
8
 
7
9
  ## Usage
8
10
 
9
- This library exports a drop-in replacement for the built-in RegExp.
11
+ This library exports a drop-in replacement for the built-in RegExp ([caveats]
12
+ apply).
10
13
 
11
- ```shell
12
- npm install @ericcornelissen/lregexp
13
- ```
14
+ 1. Install
14
15
 
15
- ```javascript
16
- import RegExp from "@ericcornelissen/lregexp";
17
- new RegExp("[linear]{6}");
18
- ```
16
+ ```shell
17
+ npm install @ericcornelissen/lregexp
18
+ ```
19
+
20
+ 2. Import
21
+
22
+ ```javascript
23
+ import RegExp from "@ericcornelissen/lregexp";
24
+ ```
25
+
26
+ 3. Use
27
+
28
+ ```javascript
29
+ new RegExp("[linear]{6}");
30
+ ```
31
+
32
+ [caveats]: #caveats
19
33
 
20
34
  ## Why
21
35
 
@@ -23,9 +37,51 @@ Backtracking regular expressions can take exponential time to evaluate, leading
23
37
  to the dreaded _ReDoS_ vulnerability. Linear-time regular expressions avoid this
24
38
  by not backtracking.
25
39
 
40
+ In Node.js, linear-time regular expressions can be created using the `l` flag
41
+ provided the `--enable-experimental-regexp-engine` CLI option is used. This
42
+ makes it difficult for library authors to tap into. Using this package, a
43
+ library can use the RegExp constructor as usual and benefit from the linear time
44
+ regular expression engine when its users enable it. If they don't, it gracefully
45
+ falls back to the default constructor.
46
+
26
47
  ## Caveats
27
48
 
28
- Not all regular expression constructs are valid in a linear-time regular
29
- expression and this library won't tell you your regular expression is
30
- incompatible unless you run it with the non-backtracking engine, in which
31
- case it throws an error.
49
+ Not all valid JavaScript regular expressions are supported when using the
50
+ `--enable-experimental-regexp-engine` CLI option. This library won't tell you if
51
+ your regular expressions are incompatible, unless you run it with that CLI
52
+ option. If a regular expression is incompatible the constructor will throw a
53
+ SyntaxError.
54
+
55
+ To support users of this package in writing compatible regular expressions we're
56
+ interested in:
57
+
58
+ - an ESLint plugin to lint regular expressions and raise warnings for the use of
59
+ regex features not supported by the non-backtracing engine; ([#4])
60
+ - a tool (CLI/web) to check a given regular expression for compatibility with
61
+ the non-backtracing engine. ([#21])
62
+
63
+ [#4]: https://github.com/ericcornelissen/lregexp/issues/4
64
+ [#21]: https://github.com/ericcornelissen/lregexp/issues/21
65
+
66
+ ## How
67
+
68
+ If `--enable-experimental-regexp-engine` is used, the RegExp constructor from
69
+ this package automatically adds the `l` flag to all regular expressions it
70
+ constructs. If not, the RegExp constructor behavior is unchanged.
71
+
72
+ ## Example
73
+
74
+ A classic example of a ReDoS-vulnerable regular expression is `(a*)*b`. Using
75
+ this with vanilla Node.js on a pathological input string takes some time, test
76
+ it for yourself with (add an `a` and the runtime doubles):
77
+
78
+ ```shell
79
+ node -e '/(a*)*b/.test("aaaaaaaaaaaaaaaaaaaaaaaaac")'
80
+ ```
81
+
82
+ When the non-backtracking regular expression engine is enabled, the expression
83
+ evaluates instantly:
84
+
85
+ ```shell
86
+ node -e '/(a*)*b/l.test("aaaaaaaaaaaaaaaaaaaaaaaaac")' --enable-experimental-regexp-engine
87
+ ```
package/SECURITY.md ADDED
@@ -0,0 +1,11 @@
1
+ <!-- SPDX-License-Identifier: CC0-1.0 -->
2
+
3
+ # Security Policy
4
+
5
+ All security issues in `@ericcornelissen/lregexp` should be reported publicly as
6
+ bugs. Private reports will be made public by the maintainers after 7 days with
7
+ best-effort attribution.
8
+
9
+ This document should be considered expired after 2026-06-01. If you are reading
10
+ this after that date you should try to find an up-to-date version in the source
11
+ repository.
package/index.cjs CHANGED
@@ -1,11 +1,27 @@
1
+ // SPDX-License-Identifier: MIT
2
+
1
3
  const isSupportedRegexpFlag = require("./is-supported-regexp-flag.cjs");
2
4
 
5
+ /**
6
+ * The `RegExp()` constructor creates {@link RegExp} objects.
7
+ *
8
+ * @param {string|RegExp} pattern The text of the regular expression. This can also be another RegExp object.
9
+ * @param {string} [flags] If specified, flags is a string that contains the flags to add. Alternatively, if a RegExp object is supplied for the pattern, the flags string will replace any of that object's flags.
10
+ * @returns {RegExp} A {@link RegExp} object constructed from `pattern` and `flags`.
11
+ * @throws {SyntaxError} Thrown in one of the following cases: `pattern` cannot be parsed as a valid regular expression, or `flags` contains repeated characters or any character outside of those allowed.
12
+ */
3
13
  let lRegExp = RegExp;
4
14
 
5
15
  if (isSupportedRegexpFlag("l")) {
6
- const RegExp_ = globalThis.RegExp;
7
- lRegExp = function(pattern, flags="") {
8
- return new RegExp_(pattern, `${flags}l`);
16
+ lRegExp = function(pattern, flags) {
17
+ if (flags === undefined) {
18
+ flags = "";
19
+ if (pattern instanceof RegExp && pattern.flags) {
20
+ flags = pattern.flags.replace(/l/g, "");
21
+ }
22
+ }
23
+
24
+ return new RegExp(pattern, `${flags}l`);
9
25
  };
10
26
  }
11
27
 
package/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export default class lRegExp {
2
- constructor(pattern: string, flags?: string);
3
- }
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ export default RegExp;
package/index.js CHANGED
@@ -1,11 +1,27 @@
1
+ // SPDX-License-Identifier: MIT
2
+
1
3
  import isSupportedRegexpFlag from "is-supported-regexp-flag";
2
4
 
5
+ /**
6
+ * The `RegExp()` constructor creates {@link RegExp} objects.
7
+ *
8
+ * @param {string|RegExp} pattern The text of the regular expression. This can also be another RegExp object.
9
+ * @param {string} [flags] If specified, flags is a string that contains the flags to add. Alternatively, if a RegExp object is supplied for the pattern, the flags string will replace any of that object's flags.
10
+ * @returns {RegExp} A {@link RegExp} object constructed from `pattern` and `flags`.
11
+ * @throws {SyntaxError} Thrown in one of the following cases: `pattern` cannot be parsed as a valid regular expression, or `flags` contains repeated characters or any character outside of those allowed.
12
+ */
3
13
  let lRegExp = RegExp;
4
14
 
5
15
  if (isSupportedRegexpFlag("l")) {
6
- const RegExp_ = globalThis.RegExp;
7
- lRegExp = function(pattern, flags="") {
8
- return new RegExp_(pattern, `${flags}l`);
16
+ lRegExp = function(pattern, flags) {
17
+ if (flags === undefined) {
18
+ flags = "";
19
+ if (pattern instanceof RegExp && pattern.flags) {
20
+ flags = pattern.flags.replace(/l/g, "");
21
+ }
22
+ }
23
+
24
+ return new RegExp(pattern, `${flags}l`);
9
25
  };
10
26
  }
11
27
 
@@ -1,3 +1,5 @@
1
+ // SPDX-License-Identifier: MIT
2
+
1
3
  /**
2
4
  * MIT License
3
5
  *
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ericcornelissen/lregexp",
3
- "description": "Transparently create linear-time regular expressions",
4
- "version": "1.0.5",
3
+ "description": "Transparent linear-time (non-backtracking) regular expressions for libraries",
4
+ "version": "1.0.7",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "exports": {