diff --git a/README.md b/README.md index 74e4bd3..8d1535b 100644 --- a/README.md +++ b/README.md @@ -77,9 +77,9 @@ type OnigurumaToEsOptions = { global?: boolean; hasIndices?: boolean; maxRecursionDepth?: number | null; - overrides?: { - allowAllSearchStartAnchors?: boolean; + rules?: { allowOrphanBackrefs?: boolean; + allowUnhandledGAnchors?: boolean; asciiWordBoundaries?: boolean; }; target?: 'auto' | 'ES2025' | 'ES2024' | 'ES2018'; @@ -203,13 +203,13 @@ Since recursion isn't infinite-depth like in Oniguruma, use of recursion also re Using a high limit has a small impact on performance. Generally, this is only a problem if the regex has an existing issue with runaway backtracking that recursion exacerbates. Higher limits have no effect on regexes that don't use recursion, so you should feel free to increase this if helpful. -### `overrides` +### `rules` -Advanced options that take precedence over standard error checking and flags when enabled. +Advanced pattern options that override standard error checking and flags when enabled. -- `allowAllSearchStartAnchors`: Silences errors for unsupported uses of the search-start anchor `\G`. - - Oniguruma-To-ES uses a variety of strategies to accurately emulate many common uses of `\G`. When using this option, if a `\G` is found that doesn't have a known emulation strategy, the `\G` is simply removed and JavaScript's `y` (`sticky`) flag is added. This might lead to some false positives and negatives, but is useful for non-critical matching (like syntax highlighting) when having some mismatches is better than not working. - `allowOrphanBackrefs`: Useful with TextMate grammars that merge backreferences across patterns. +- `allowUnhandledGAnchors`: Applies flag `y` for unsupported uses of `\G`, rather than erroring. + - Oniguruma-To-ES uses a variety of strategies to accurately emulate many common uses of `\G`. When using this option, if a `\G` is found that doesn't have a known emulation strategy, the `\G` is simply removed and JavaScript's `y` (`sticky`) flag is added. This might lead to some false positives and negatives, but is useful for non-critical matching (like syntax highlighting) when having some mismatches is better than not working. - `asciiWordBoundaries`: ASCII-based `\b` and `\B`. ### `target` diff --git a/demo/demo.js b/demo/demo.js index a6269bc..eea024a 100644 --- a/demo/demo.js +++ b/demo/demo.js @@ -20,9 +20,9 @@ const state = { global: getValue('option-global'), hasIndices: getValue('option-hasIndices'), maxRecursionDepth: getValue('option-maxRecursionDepth'), - overrides: { - allowAllSearchStartAnchors: getValue('option-allowAllSearchStartAnchors'), + rules: { allowOrphanBackrefs: getValue('option-allowOrphanBackrefs'), + allowUnhandledGAnchors: getValue('option-allowUnhandledGAnchors'), asciiWordBoundaries: getValue('option-asciiWordBoundaries'), }, target: getValue('option-target'), @@ -224,7 +224,7 @@ function setOption(option, value) { showTranspiled(); } -function setOverride(option, value) { - state.opts.overrides[option] = value; +function setRule(rule, value) { + state.opts.rules[rule] = value; showTranspiled(); } diff --git a/demo/index.html b/demo/index.html index 3a23a59..09b6a76 100644 --- a/demo/index.html +++ b/demo/index.html @@ -110,23 +110,23 @@
diff --git a/spec/match-search-start.spec.js b/spec/match-search-start.spec.js index 4e23216..a11a646 100644 --- a/spec/match-search-start.spec.js +++ b/spec/match-search-start.spec.js @@ -135,7 +135,7 @@ describe('Assertion: Search start', () => { ]; patterns.forEach(pattern => { expect(() => toDetails(pattern)).toThrow(); - expect(toRegExp(pattern, {overrides: {allowAllSearchStartAnchors: true}}).sticky).toBe(true); + expect(toRegExp(pattern, {rules: {allowUnhandledGAnchors: true}}).sticky).toBe(true); }); }); }); diff --git a/src/index.js b/src/index.js index e9845d5..0be7a98 100644 --- a/src/index.js +++ b/src/index.js @@ -28,9 +28,9 @@ import {recursion} from 'regex-recursion'; global?: boolean; hasIndices?: boolean; maxRecursionDepth?: number | null; - overrides?: { - allowAllSearchStartAnchors?: boolean; + rules?: { allowOrphanBackrefs?: boolean; + allowUnhandledGAnchors?: boolean; asciiWordBoundaries?: boolean; }; target?: keyof Target; @@ -52,13 +52,13 @@ function toDetails(pattern, options) { const opts = getOptions(options); const tokenized = tokenize(pattern, opts.flags); const onigurumaAst = parse(tokenized, { - skipBackrefValidation: opts.overrides.allowOrphanBackrefs, + skipBackrefValidation: opts.rules.allowOrphanBackrefs, verbose: opts.verbose, }); const regexAst = transform(onigurumaAst, { accuracy: opts.accuracy, - allowAllSearchStartAnchors: opts.overrides.allowAllSearchStartAnchors, - asciiWordBoundaries: opts.overrides.asciiWordBoundaries, + allowUnhandledGAnchors: opts.rules.allowUnhandledGAnchors, + asciiWordBoundaries: opts.rules.asciiWordBoundaries, avoidSubclass: opts.avoidSubclass, bestEffortTarget: opts.target, }); diff --git a/src/options.js b/src/options.js index c262ba1..1ce4ce6 100644 --- a/src/options.js +++ b/src/options.js @@ -51,15 +51,15 @@ function getOptions(options) { // Disables optimizations that simplify the pattern when it doesn't change the meaning. verbose: false, ...options, - // Advanced options that take precedence over standard error checking and flags when enabled. - overrides: { - // Silences errors for unsupported uses of the search-start anchor `\G`. - allowAllSearchStartAnchors: false, + // Advanced pattern options that override standard error checking and flags when enabled. + rules: { // Useful with TextMate grammars that merge backreferences across patterns. allowOrphanBackrefs: false, + // Applies flag `y` for unsupported uses of `\G`, rather than erroring. + allowUnhandledGAnchors: false, // ASCII-based `\b` and `\B`. asciiWordBoundaries: false, - ...(options?.overrides), + ...(options?.rules), }, }; if (opts.target === 'auto') { diff --git a/src/transform.js b/src/transform.js index b1afb33..8735387 100644 --- a/src/transform.js +++ b/src/transform.js @@ -30,7 +30,7 @@ AST represents what's needed to precisely reproduce Oniguruma behavior using Reg @param {import('./parse.js').OnigurumaAst} ast @param {{ accuracy?: keyof Accuracy; - allowAllSearchStartAnchors?: boolean; + allowUnhandledGAnchors?: boolean; asciiWordBoundaries?: boolean; avoidSubclass?: boolean; bestEffortTarget?: keyof Target; @@ -46,7 +46,7 @@ function transform(ast, options) { // representations would be hard to change to ASCII-based after the fact in the generator // based on `target`/`accuracy`, so produce the appropriate structure here. accuracy: 'default', - allowAllSearchStartAnchors: false, + allowUnhandledGAnchors: false, asciiWordBoundaries: false, avoidSubclass: false, bestEffortTarget: 'ES2025', @@ -56,7 +56,7 @@ function transform(ast, options) { const strategy = opts.avoidSubclass ? null : applySubclassStrategies(ast); const firstPassState = { accuracy: opts.accuracy, - allowAllSearchStartAnchors: opts.allowAllSearchStartAnchors, + allowUnhandledGAnchors: opts.allowUnhandledGAnchors, asciiWordBoundaries: opts.asciiWordBoundaries, flagDirectivesByAlt: new Map(), minTargetEs2024: isMinTarget(opts.bestEffortTarget, 'ES2024'), @@ -130,7 +130,7 @@ const FirstPassVisitor = { }, }, - Assertion({node, ast, remove, replaceWith}, {allowAllSearchStartAnchors, asciiWordBoundaries, supportedGNodes, wordIsAscii}) { + Assertion({node, ast, remove, replaceWith}, {allowUnhandledGAnchors, asciiWordBoundaries, supportedGNodes, wordIsAscii}) { const {kind, negate} = node; if (kind === AstAssertionKinds.line_end) { // Onig's only line break char is line feed, unlike JS @@ -139,7 +139,7 @@ const FirstPassVisitor = { // Onig's only line break char is line feed, unlike JS replaceWith(parseFragment(r`(?<=\A|\n)`)); } else if (kind === AstAssertionKinds.search_start) { - if (!supportedGNodes.has(node) && !allowAllSearchStartAnchors) { + if (!supportedGNodes.has(node) && !allowUnhandledGAnchors) { throw new Error(r`Uses "\G" in a way that's unsupported`); } ast.flags.sticky = true; @@ -300,7 +300,7 @@ const FirstPassVisitor = { !node.flags.enable && !node.flags.disable && delete node.flags; }, - Pattern({node}, {allowAllSearchStartAnchors, supportedGNodes}) { + Pattern({node}, {allowUnhandledGAnchors, supportedGNodes}) { // For `\G` to be accurately emulatable using JS flag y, it must be at (and only at) the start // of every top-level alternative (with complex rules for what determines being at the start). // Additional `\G` error checking in `Assertion` visitor @@ -318,7 +318,7 @@ const FirstPassVisitor = { hasAltWithoutLeadG = true; } } - if (hasAltWithLeadG && hasAltWithoutLeadG && !allowAllSearchStartAnchors) { + if (hasAltWithLeadG && hasAltWithoutLeadG && !allowUnhandledGAnchors) { throw new Error(r`Uses "\G" in a way that's unsupported`); } // Supported `\G` nodes will be removed when traversed; others will error