295 lines
11 KiB
TypeScript
295 lines
11 KiB
TypeScript
import { useEffect, useRef } from "react";
|
||
import { DEFAULT_REGEX_LIMITS } from "../regex/execution/request-limits";
|
||
import {
|
||
DEFAULT_GENERATION_SETTINGS,
|
||
GENERATION_LIMITS,
|
||
} from "../regex/generation/generation-limits";
|
||
import { manifest } from "../toolbox/manifest";
|
||
|
||
const releaseSourceUrl = `https://git.add-ideas.de/lotobo/regex-tools/src/tag/v${manifest.version}`;
|
||
|
||
export function HelpDialog({
|
||
open,
|
||
onClose,
|
||
}: {
|
||
readonly open: boolean;
|
||
readonly onClose: () => void;
|
||
}) {
|
||
const dialog = useRef<HTMLDialogElement>(null);
|
||
useEffect(() => {
|
||
const element = dialog.current;
|
||
if (!element) return;
|
||
if (open && !element.open) element.showModal();
|
||
if (!open && element.open) element.close();
|
||
}, [open]);
|
||
return (
|
||
<dialog
|
||
ref={dialog}
|
||
className="app-dialog"
|
||
aria-labelledby="help-title"
|
||
onClose={onClose}
|
||
>
|
||
<header>
|
||
<div>
|
||
<p className="eyebrow">Regex Tools {manifest.version}</p>
|
||
<h2 id="help-title">Local regex workbench</h2>
|
||
</div>
|
||
<button
|
||
type="button"
|
||
className="icon-button"
|
||
aria-label="Close help"
|
||
onClick={onClose}
|
||
>
|
||
×
|
||
</button>
|
||
</header>
|
||
<div className="dialog-content">
|
||
<section>
|
||
<h3>What runs where</h3>
|
||
<p>
|
||
Syntax parsing and active-engine execution run in separate, killable
|
||
browser workers. JavaScript uses the browser's ECMAScript
|
||
RegExp implementation, while the standalone PCRE2 profile uses the
|
||
bundled 10.47 WebAssembly engine. The other profiles name their
|
||
selected runtime explicitly: PHP 8.5.8 preg with PCRE2 10.44, legacy
|
||
Perl 5.28.1 through WebPerl 0.09-beta, CPython 3.14, CRuby 4.0,
|
||
TeaVM java.util.regex, libc++ std::regex, Go regexp, Rust regex and
|
||
.NET System.Text.RegularExpressions. Scala is explicitly a Scala/JVM
|
||
regex-syntax compatibility profile over the same TeaVM Java runtime,
|
||
not a Scala VM. Result metadata names the runtime actually used.
|
||
</p>
|
||
<p>
|
||
Structural coverage varies by profile. Only the ECMAScript provider
|
||
currently exposes a complete grammar-backed tree; the additional
|
||
community providers retain partial lexical captures and replacement
|
||
tokens while their selected runtime compiler remains authoritative.
|
||
Patterns, subjects and projects are never uploaded. There is no
|
||
backend, account, telemetry, CDN dependency, or executable
|
||
replacement function.
|
||
</p>
|
||
<p>
|
||
TeaVM 0.15.0 is not OpenJDK. Its replacement implementation accepts
|
||
single-digit $n references, so $12 means $1 followed by literal 2.
|
||
Java SE ${"{name}"} references are reported as unavailable.
|
||
</p>
|
||
</section>
|
||
<section>
|
||
<h3>Trees and replacement mapping</h3>
|
||
<p>
|
||
The explanation tree is deterministic structure derived from the
|
||
syntax provider. The extraction tree contains actual browser-engine
|
||
matches and captures. Replacement mode adds a typed token tree and
|
||
bounded per-match contribution/range mapping over those actual
|
||
matches. These views are not internal engine traces. The separate
|
||
PCRE trace viewer shows actual bounded automatic callouts reported
|
||
by PCRE2; its adjacent-position movement labels are derived and it
|
||
is not a complete record of every internal action. Browser
|
||
ECMAScript exposes no corresponding V8, SpiderMonkey or
|
||
JavaScriptCore trace API.
|
||
</p>
|
||
</section>
|
||
<section>
|
||
<h3>Advisory analysis</h3>
|
||
<p>
|
||
Static risk findings are ECMAScript-2025-specific heuristics, and
|
||
generated-input growth observations describe only the selected
|
||
bounded samples. Neither proves safety or general complexity. Growth
|
||
and cold/warm benchmark timing run in a separate killable worker and
|
||
never include the PCRE2 trace path.
|
||
</p>
|
||
</section>
|
||
<section>
|
||
<h3>Generated cases</h3>
|
||
<p>
|
||
ECMAScript generator v1 deterministically samples supported
|
||
normalized-AST paths from an explicit seed. Every intended positive
|
||
and negative subject runs through the selected actual engine before
|
||
it can become a test; candidates with the wrong outcome are
|
||
discarded. The coverage report names unsupported constructs.
|
||
Sampling is not proof of complete language coverage. Other flavours
|
||
remain unavailable until their structural providers expose the
|
||
required AST; their syntax is never reinterpreted as ECMAScript.
|
||
</p>
|
||
</section>
|
||
<section>
|
||
<h3>Pattern formatting</h3>
|
||
<p>
|
||
The ECMAScript formatter makes only grammar-backed literal/control
|
||
escape changes; it does not insert layout whitespace or reinterpret
|
||
another flavour's syntax. Applying a preview requires
|
||
independent source and candidate reparsing, actual-engine
|
||
match/replacement comparison, every applicable exact unit test, and
|
||
an explicit confirmation. Passing bounded checks is evidence for
|
||
those snapshots, not proof for every possible subject.
|
||
</p>
|
||
</section>
|
||
<section>
|
||
<h3>Timeouts and limits</h3>
|
||
<dl className="help-limits">
|
||
<div>
|
||
<dt>Live execution</dt>
|
||
<dd>{DEFAULT_REGEX_LIMITS.liveExecutionTimeoutMs} ms</dd>
|
||
</div>
|
||
<div>
|
||
<dt>Manual execution</dt>
|
||
<dd>{DEFAULT_REGEX_LIMITS.manualExecutionTimeoutMs} ms</dd>
|
||
</div>
|
||
<div>
|
||
<dt>Maximum matches</dt>
|
||
<dd>{DEFAULT_REGEX_LIMITS.maximumMatches.toLocaleString()}</dd>
|
||
</div>
|
||
<div>
|
||
<dt>Maximum capture rows</dt>
|
||
<dd>
|
||
{DEFAULT_REGEX_LIMITS.maximumCaptureRows.toLocaleString()}
|
||
</dd>
|
||
</div>
|
||
<div>
|
||
<dt>Maximum capture groups</dt>
|
||
<dd>
|
||
{DEFAULT_REGEX_LIMITS.maximumCaptureGroups.toLocaleString()}
|
||
</dd>
|
||
</div>
|
||
<div>
|
||
<dt>Replacement template</dt>
|
||
<dd>
|
||
{DEFAULT_REGEX_LIMITS.maximumReplacementTemplateUtf16.toLocaleString()}{" "}
|
||
UTF-16 units
|
||
</dd>
|
||
</div>
|
||
<div>
|
||
<dt>List template</dt>
|
||
<dd>
|
||
{DEFAULT_REGEX_LIMITS.maximumListTemplateUtf16.toLocaleString()}{" "}
|
||
UTF-16 units
|
||
</dd>
|
||
</div>
|
||
<div>
|
||
<dt>Unit-test suite wall time</dt>
|
||
<dd>60 seconds</dd>
|
||
</div>
|
||
<div>
|
||
<dt>Corpus input</dt>
|
||
<dd>
|
||
{DEFAULT_REGEX_LIMITS.maximumCorpusDocuments.toLocaleString()}{" "}
|
||
documents · {DEFAULT_REGEX_LIMITS.corpusHardBytes / 1024 / 1024}{" "}
|
||
MiB
|
||
</dd>
|
||
</div>
|
||
<div>
|
||
<dt>Corpus wall time</dt>
|
||
<dd>
|
||
{DEFAULT_REGEX_LIMITS.maximumCorpusWallTimeMs / 60_000} minutes
|
||
</dd>
|
||
</div>
|
||
<div>
|
||
<dt>Analysis wall time</dt>
|
||
<dd>
|
||
{DEFAULT_REGEX_LIMITS.maximumBenchmarkWallTimeMs / 1_000}{" "}
|
||
seconds
|
||
</dd>
|
||
</div>
|
||
<div>
|
||
<dt>Benchmark iteration cap</dt>
|
||
<dd>
|
||
{DEFAULT_REGEX_LIMITS.maximumBenchmarkIterations.toLocaleString()}
|
||
</dd>
|
||
</div>
|
||
<div>
|
||
<dt>Growth probe steps</dt>
|
||
<dd>24</dd>
|
||
</div>
|
||
<div>
|
||
<dt>Generated cases</dt>
|
||
<dd>
|
||
{DEFAULT_REGEX_LIMITS.maximumGeneratedCases.toLocaleString()}{" "}
|
||
retained ·{" "}
|
||
{GENERATION_LIMITS.maximumCandidateAttempts.toLocaleString()}{" "}
|
||
attempts
|
||
</dd>
|
||
</div>
|
||
<div>
|
||
<dt>Generation defaults</dt>
|
||
<dd>
|
||
{DEFAULT_GENERATION_SETTINGS.perCaseTimeoutMs} ms per case ·{" "}
|
||
{DEFAULT_GENERATION_SETTINGS.maximumWallTimeMs / 1_000} seconds
|
||
aggregate
|
||
</dd>
|
||
</div>
|
||
<div>
|
||
<dt>Generated subject text</dt>
|
||
<dd>
|
||
{GENERATION_LIMITS.maximumTotalSubjectBytes / 1024 / 1024} MiB
|
||
aggregate hard cap
|
||
</dd>
|
||
</div>
|
||
<div>
|
||
<dt>Formatter validation</dt>
|
||
<dd>1,000 tests · 60 seconds aggregate</dd>
|
||
</div>
|
||
<div>
|
||
<dt>Independent corpus lines</dt>
|
||
<dd>
|
||
{DEFAULT_REGEX_LIMITS.maximumCorpusLines.toLocaleString()}
|
||
</dd>
|
||
</div>
|
||
<div>
|
||
<dt>Corpus applied output</dt>
|
||
<dd>
|
||
{DEFAULT_REGEX_LIMITS.maximumCorpusOutputBytes / 1024 / 1024}{" "}
|
||
MiB
|
||
</dd>
|
||
</div>
|
||
</dl>
|
||
<p>
|
||
A timeout terminates the worker. It means “timed out”, never “no
|
||
match”. The following run uses a fresh worker.
|
||
</p>
|
||
</section>
|
||
<section>
|
||
<h3>Persistence</h3>
|
||
<p>
|
||
Ad-hoc test text is excluded from local saves and exports by
|
||
default. Test definitions are deliberate project data. Import is
|
||
validated and paused until you review and run it. Corpus documents,
|
||
contents, outputs and results are always ephemeral and excluded from
|
||
projects and IndexedDB. Analysis settings and results are likewise
|
||
ephemeral. Generated-case settings and review results are ephemeral;
|
||
only cases explicitly added to the test suite persist, together with
|
||
their bounded seed and generator provenance. Test subjects remain
|
||
excluded unless separately opted in. Formatter previews and
|
||
validation observations are ephemeral; only an explicitly applied
|
||
pattern enters workbench/project state.
|
||
</p>
|
||
</section>
|
||
<section>
|
||
<h3>Legal notice</h3>
|
||
<p>
|
||
Copyright © 2026 Albrecht Degering. Regex Tools is free software:
|
||
you may redistribute it and/or modify it under the terms of the GNU
|
||
General Public License, version 3 or (at your option) any later
|
||
version. It comes without any warranty, to the extent permitted by
|
||
law.
|
||
</p>
|
||
<p>
|
||
Read the{" "}
|
||
<a href="./LICENSE" target="_blank" rel="noreferrer">
|
||
complete licence
|
||
</a>{" "}
|
||
or inspect and obtain the{" "}
|
||
<a href={releaseSourceUrl} target="_blank" rel="noreferrer">
|
||
corresponding source code
|
||
</a>
|
||
.
|
||
</p>
|
||
</section>
|
||
</div>
|
||
<footer>
|
||
<button type="button" className="primary-button" onClick={onClose}>
|
||
Close
|
||
</button>
|
||
</footer>
|
||
</dialog>
|
||
);
|
||
}
|