Skip to content

Commit

Permalink
Show subclass call in demo output
Browse files Browse the repository at this point in the history
  • Loading branch information
slevithan committed Nov 5, 2024
1 parent c1741e3 commit 2000cec
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 38 deletions.
6 changes: 5 additions & 1 deletion demo/demo.css
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ small {
font-size: 0.8em;
}

td {
padding-right: 40px;
}

label, .label {
margin-right: 0.4em;
}
Expand Down Expand Up @@ -115,7 +119,7 @@ pre, code, textarea {
}

#info {
font-style: italic;
font-weight: bold;
}

.hidden {
Expand Down
35 changes: 22 additions & 13 deletions demo/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const state = {
},
opts: {
allowBestEffort: getValue('option-allow-best-effort'),
allowSubclassBasedEmulation: getValue('option-subclass'),
global: getValue('option-global'),
hasIndices: getValue('option-has-indices'),
maxRecursionDepth: getValue('option-max-recursion-depth'),
Expand All @@ -31,22 +32,23 @@ function showOutput(el) {
};
let output = '';
try {
// Use `compile` but display output as if `toRegExp` was called. This avoids erroring when the
// selected `target` includes features that don't work in the user's browser
const re = OnigurumaToES.compile(input, flags, opts);
output = `/${getRegExpLiteralPattern(re.pattern)}/${re.flags}`;
if (opts.allowSubclassBasedEmulation) {
const wrappedRe = OnigurumaToES.toRegExp(input, flags, opts);
if (wrappedRe._internal) {
infoEl.classList.remove('hidden');
output = `new WrappedRegExp('${wrappedRe.source.replace(/'/g, "\\'")}', '${wrappedRe.flags}', {
strategy: '${wrappedRe._internal.strategy}',${wrappedRe._internal.subpattern ? `
subpattern: '${wrappedRe._internal.subpattern}',` : ''}
})`;
} else {
output = getFormattedCompileOutput(input, flags, opts);
}
} else {
output = getFormattedCompileOutput(input, flags, opts);
}
} catch (err) {
outputEl.classList.add('error');
output = `Error: ${err.message}`;
try {
const re2 = OnigurumaToES.toRegExp(input, flags, {
...opts,
allowSubclassBasedEmulation: true,
});
infoEl.classList.remove('hidden');
} catch (err2) {
// No-op
}
}
outputEl.innerHTML = escapeHtml(output);
}
Expand All @@ -60,6 +62,13 @@ function escapeHtml(str) {
return str.replace(/&/g, '&amp;').replace(/</g, '&lt;');
}

function getFormattedCompileOutput(input, flags, opts) {
// Use `compile` but display output as if `toRegExp` was called. This avoids erroring when the
// selected `target` includes features that don't work in the user's browser
const re = OnigurumaToES.compile(input, flags, opts);
return `/${getRegExpLiteralPattern(re.pattern)}/${re.flags}`;
}

function getRegExpLiteralPattern(str) {
return str ? str.replace(/\\?./gsu, m => m === '/' ? '\\/' : m) : '(?:)';
}
Expand Down
66 changes: 43 additions & 23 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,31 +43,51 @@ <h2>Try it</h2>
</p>
<details>
<summary>More options</summary>
<p>
<label>
<input type="checkbox" id="option-allow-best-effort" checked onchange="setOption('allowBestEffort', this.checked)">
<code>allowBestEffort</code>
</label>
<label>
<input type="checkbox" id="option-optimize" checked onchange="setOption('optimize', this.checked)">
<code>optimize</code>
</label>
<label>
<input type="number" id="option-max-recursion-depth" value="6" min="2" max="100" onchange="setOption('maxRecursionDepth', this.value)" onkeyup="setOption('maxRecursionDepth', this.value)">
<code>maxRecursionDepth</code>
</label>
<label>
<input type="checkbox" id="option-global" onchange="setOption('global', this.checked)">
<code>global</code>
</label>
<label>
<input type="checkbox" id="option-has-indices" onchange="setOption('hasIndices', this.checked)">
<code>hasIndices</code>
</label>
</p>
<table id="more-options">
<tr>
<td>
<label>
<input type="checkbox" id="option-allow-best-effort" checked onchange="setOption('allowBestEffort', this.checked)">
<code>allowBestEffort</code>
</label>
</td>
<td>
<label>
<input type="checkbox" id="option-global" onchange="setOption('global', this.checked)">
<code>global</code>
</label>
</td>
<td>
<label>
<input type="number" id="option-max-recursion-depth" value="6" min="2" max="100" onchange="setOption('maxRecursionDepth', this.value)" onkeyup="setOption('maxRecursionDepth', this.value)">
<code>maxRecursionDepth</code>
</label>
</td>
</tr>
<tr>
<td>
<label>
<input type="checkbox" id="option-subclass" onchange="setOption('allowSubclassBasedEmulation', this.checked)">
<code>allowSubclassBasedEmulation</code>
</label>
</td>
<td>
<label>
<input type="checkbox" id="option-has-indices" onchange="setOption('hasIndices', this.checked)">
<code>hasIndices</code>
</label>
</td>
<td>
<label>
<input type="checkbox" id="option-optimize" checked onchange="setOption('optimize', this.checked)">
<code>optimize</code>
</label>
</td>
</tr>
</table>
</details>
<pre id="output"></pre>
<div id="info" class="hidden"><p>✅ This regex is supported with experimental option <code>allowSubclassBasedEmulation</code>.</p></div>
<div id="info" class="hidden"><p>✅ This regex is supported with a <code>RegExp</code> subclass.</p></div>
<p>The output shows the result of calling <code>toRegExp</code>. Oniguruma-To-ES includes functions to generate additional formats: <code>compile</code>, <code>toOnigurumaAst</code>, and <code>toRegexAst</code> (for an AST based on <a href="https://github.com/slevithan/regex"><code>regex</code></a>). You can run all of these from the console on this page.</p>
<details>
<summary>More details</summary>
Expand Down
4 changes: 3 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ class WrappedRegExp extends RegExp {
// Can read private properties of the existing object since it was created by this class
this.#data = pattern.#data;
}
// TODO: Change to getters since values are for tools and won't be read internally
this._internal = this.#data;
}
/**
Called internally by all String/RegExp methods that use regexes.
Expand All @@ -82,7 +84,6 @@ class WrappedRegExp extends RegExp {
const useLastIndex = this.global || this.sticky;
const pos = this.lastIndex;
const exec = RegExp.prototype.exec;
const globalRe = useLastIndex ? this : new RegExp(this, `g${this.flags}`);

// ## Support leading `(^|\G)` and similar
if (this.#data.strategy === 'search_or_line_start' && useLastIndex && this.lastIndex) {
Expand All @@ -98,6 +99,7 @@ class WrappedRegExp extends RegExp {
}

// ## Support leading `(?!\G)` and similar
const globalRe = useLastIndex ? this : new RegExp(this, `g${this.flags}`);
if (this.#data.strategy === 'not_search_start') {
let match = exec.call(this, str);
if (match?.index === pos) {
Expand Down

0 comments on commit 2000cec

Please sign in to comment.