diff --git a/.gitignore b/.gitignore
index 918de83..378fa5a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,6 @@ _site
.jekyll-metadata
vendor
Gemfile.lock
+node_modules
+local
+grammar/jsonc-processed.abnf
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..1bfa9dd
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,4 @@
+[submodule "submodules/railroad-diagram-generator-js"]
+ path = submodules/railroad-diagram-generator-js
+ url = https://github.com/DecimalTurn/railroad-diagram-generator-js
+ branch = dev
diff --git a/assets/examples/many_comments.jsonc b/assets/examples/many_comments.jsonc
new file mode 100644
index 0000000..e72fc5e
--- /dev/null
+++ b/assets/examples/many_comments.jsonc
@@ -0,0 +1,14 @@
+//Comment
+/*Comment*/
+/*Comment*/{//Comment
+
+/*Comment*/"key1" /*Comment*/:/*Comment*/"value1"/*Comment*/,/*Comment*/
+
+"key2" //Comment
+: //Comment
+"value2" //Comment
+, //Comment
+
+"array1": [/*Comment*/"value1"/*Comment*/,/*Comment*/"value2",/*Comment*/1/*Comment*/]
+
+}
\ No newline at end of file
diff --git a/generate-railroad.js b/generate-railroad.js
new file mode 100644
index 0000000..9ba7b55
--- /dev/null
+++ b/generate-railroad.js
@@ -0,0 +1,176 @@
+#!/usr/bin/env node
+
+const fs = require("node:fs");
+const { spawnSync } = require("node:child_process");
+const path = require("node:path");
+
+// Customization section
+const DEFAULT_INPUT_ABNF = "grammar/jsonc.abnf";
+const DEFAULT_PROCESSED_ABNF = "grammar/jsonc-processed.abnf";
+const DEFAULT_OUTPUT_HTML = "grammar/railroad-diagram.html";
+
+// Rules to inline from their %x... definitions as literal ABNF strings.
+// Add more rule names here to apply the same transformation.
+const INLINE_HEX_RULES = [
+ "multi-line-comment-start",
+ "multi-line-comment-end",
+ "asterisk",
+ "escape"
+];
+
+function escapeRegExp(value) {
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
+}
+
+function decodeAbnfHexSequence(value) {
+ const trimmed = value.trim();
+ if (!/^%x[0-9A-Fa-f]+(?:\.[0-9A-Fa-f]+)*$/.test(trimmed)) {
+ throw new Error(`Unsupported ABNF hex sequence: ${value}`);
+ }
+
+ const bytes = trimmed
+ .slice(2)
+ .split(".")
+ .map((part) => parseInt(part, 16));
+
+ return String.fromCodePoint(...bytes);
+}
+
+function inlineHexRuleAsLiteral(source, ruleName) {
+ const escapedRuleName = escapeRegExp(ruleName);
+ const ruleRegex = new RegExp(
+ `^\\s*${escapedRuleName}\\s*=\\s*(%x[0-9A-Fa-f]+(?:\\.[0-9A-Fa-f]+)*)\\b.*$`,
+ "m",
+ );
+ const ruleMatch = source.match(ruleRegex);
+ if (!ruleMatch) {
+ throw new Error(`Rule ${ruleName} was not found.`);
+ }
+
+ const hexSequence = ruleMatch[1];
+ const literalChars = decodeAbnfHexSequence(hexSequence);
+
+ // For backslash or other problematic characters, keep them as hex format
+ // ABNF doesn't support backslash escaping in quoted strings
+ let replacement;
+ if (literalChars === "\\") {
+ replacement = hexSequence;
+ } else {
+ // For other characters, escape only double quotes (not backslashes)
+ const escapedLiteralChars = literalChars.replace(/"/g, '\\"');
+ replacement = `"${escapedLiteralChars}"`;
+ }
+
+ const removeRuleRegex = new RegExp(`^\\s*${escapedRuleName}\\s*=.*(?:\\r?\\n|$)`, "m");
+ const withoutRule = source.replace(removeRuleRegex, "");
+
+ const useRuleRegex = new RegExp(
+ `(? {
+ const eqIndex = line.indexOf("=");
+
+ if (eqIndex !== -1) {
+ const lhs = line.slice(0, eqIndex + 1);
+ const rhs = line.slice(eqIndex + 1).replace(useRuleRegex, replacement);
+ return `${lhs}${rhs}`;
+ }
+
+ if (/^\s/.test(line)) {
+ return line.replace(useRuleRegex, replacement);
+ }
+
+ return line;
+ })
+ .join("\n");
+}
+
+function processAbnfSource(source) {
+ let processed = source;
+
+ for (const ruleName of INLINE_HEX_RULES) {
+ processed = inlineHexRuleAsLiteral(processed, ruleName);
+ }
+
+ return processed;
+}
+
+const args = process.argv.slice(2);
+const titleIndex = args.indexOf("--title");
+
+let title;
+if (titleIndex !== -1) {
+ if (titleIndex + 1 >= args.length) {
+ console.error("Missing value for --title");
+ process.exit(1);
+ }
+ title = args[titleIndex + 1];
+ args.splice(titleIndex, 2);
+}
+
+const input = args[0] || DEFAULT_INPUT_ABNF;
+const output = args[1] || DEFAULT_OUTPUT_HTML;
+const processedAbnf = DEFAULT_PROCESSED_ABNF;
+
+const inputPath = path.resolve(__dirname, input);
+const outputPath = path.resolve(__dirname, output);
+const processedPath = path.resolve(__dirname, processedAbnf);
+
+let source;
+try {
+ source = fs.readFileSync(inputPath, "utf8");
+} catch (error) {
+ console.error(`Failed to read input ABNF: ${error.message}`);
+ process.exit(1);
+}
+
+let processed;
+try {
+ processed = processAbnfSource(source);
+} catch (error) {
+ console.error(`Failed to process ABNF source: ${error.message}`);
+ process.exit(1);
+}
+
+if (typeof processed !== "string") {
+ console.error("Failed to process ABNF source: processAbnfSource must return a string.");
+ process.exit(1);
+}
+
+try {
+ fs.mkdirSync(path.dirname(processedPath), { recursive: true });
+ fs.writeFileSync(processedPath, processed, "utf8");
+} catch (error) {
+ console.error(`Failed to write processed ABNF: ${error.message}`);
+ process.exit(1);
+}
+
+const cliPath = path.join(
+ __dirname,
+ "node_modules",
+ "railroad-diagram-generator-js",
+ "bin",
+ "cli.js",
+);
+
+const cliArgs = [cliPath, "generate", processedPath, outputPath];
+if (title) {
+ cliArgs.push("--title", title);
+}
+
+const result = spawnSync(process.execPath, cliArgs, {
+ cwd: __dirname,
+ stdio: "inherit",
+});
+
+if (result.error) {
+ console.error(`Failed to run railroad generator: ${result.error.message}`);
+ process.exit(1);
+}
+
+process.exit(result.status === null ? 1 : result.status);
\ No newline at end of file
diff --git a/grammar/README.md b/grammar/README.md
new file mode 100644
index 0000000..c852672
--- /dev/null
+++ b/grammar/README.md
@@ -0,0 +1,73 @@
+# JSONC Grammar directory
+
+This directory contains the ABNF grammar for JSONC, along with plans for generating railroad diagrams from it.
+
+## Railroad Diagram Generation Plan
+
+Generate railroad diagrams from `grammar/jsonc.abnf` using a simple one-file Node.js script.
+
+Instead of building a custom ABNF parser and converter to Tab Atkins constructor calls, use:
+
+- https://github.com/xtofs/railroad-diagram-generator.js
+
+This tool parses ABNF directly and generates static HTML with embedded SVG diagrams.
+
+### Script behavior
+
+The wrapper script should:
+
+1. Accept input ABNF path and optional output HTML path.
+2. Default to:
+ - input: `grammar/jsonc.abnf`
+ - output: `grammar/railroad-diagram.html`
+3. Optionally accept `--title` to set the HTML title.
+4. Execute the upstream CLI from our installed dependency.
+5. Exit non-zero on error and print useful diagnostics.
+
+### Command examples
+
+Initialize submodule(s):
+
+```bash
+git submodule update --init --recursive
+```
+
+Install dependencies:
+
+```bash
+npm install
+```
+
+The dependency is sourced from disk via:
+
+```json
+"railroad-diagram-generator-js": "file:./submodules/railroad-diagram-generator-js"
+```
+
+Generate with defaults:
+
+```bash
+npm run railroad
+```
+
+Generate from a specific input and output:
+
+```bash
+npm run railroad -- grammar/jsonc.abnf grammar/railroad-diagram.html
+```
+
+Generate with a custom title:
+
+```bash
+npm run railroad -- grammar/jsonc.abnf grammar/railroad-diagram.html --title "JSONC Grammar"
+```
+
+### Notes on EOF for single-line comments
+
+The grammar already allows inline comments to terminate at end-of-file because the line terminator is optional:
+
+```abnf
+single-line-comment = "//" *single-line-comment-char [ comment-terminator ]
+```
+
+So diagrams generated from this ABNF should not imply a mandatory line ending.
\ No newline at end of file
diff --git a/grammar/jsonc.abnf b/grammar/jsonc.abnf
new file mode 100644
index 0000000..d8ff0af
--- /dev/null
+++ b/grammar/jsonc.abnf
@@ -0,0 +1,108 @@
+; JSONC grammar with comments support (RFC 8259 extended with JavaScript-style comments)
+;
+; Notes:
+; - Rule names and structure follow RFC 8259 ABNF snippets.
+; - DIGIT and HEXDIG are core rules from RFC 5234.
+; - comments are an extension not in RFC 8259.
+; - Trailing commas are NOT supported in this grammar.
+
+; A JSONC-text is a serialized value surrounded by optional whitespace and comments.
+; Comments can appear anywhere insignificant whitespace is allowed in JSON.
+JSONC-text = wsc value wsc
+
+; Whitespace with Comments: zero or more whitespace characters or comments
+wsc = *(ws-char / comment)
+
+; Single whitespace character (space, tab, line feed, carriage return)
+ws-char = %x20 / %x09 / %x0A / %x0D ; space / tab / LF / CR
+
+; Comments: single-line or multi-line
+comment = single-line-comment / multi-line-comment
+
+; Source character: any Unicode code point, as per ECMAScript.
+source-character = %x00-10FFFF
+
+; Comment terminators and sequences (based on ECMAScript line terminators)
+comment-terminator = %x0A / %x0D / %x2028 / %x2029 ; LF / CR / LS / PS
+comment-terminator-sequence = %x0D.0A / %x0A / %x0D / %x2028 / %x2029
+
+; Single-line comment: starts with //, continues until line ending
+; Terminator is not part of the comment body.
+; Note that the single-line-comment-end is optional, allowing comments to end at the end of the file without a line terminator.
+single-line-comment-start = %x2F.2F ; // double solidus
+single-line-comment-end = comment-terminator-sequence
+single-line-comment = single-line-comment-start *single-line-comment-char [ single-line-comment-end ]
+single-line-comment-char = %x00-09 / %x0B-0C / %x0E-2027 / %x202A-10FFFF ; Any source character except comment terminators
+
+; Multi-line comment: /* ... */
+; Cannot be nested. The first */ closes the comment.
+; Any source character is allowed inside, including control characters,
+; except the closing delimiter sequence "*/".
+multi-line-comment-start = %x2F.2A ; /* slash-asterisk
+multi-line-comment-end = %x2A.2F ; */ asterisk-slash
+asterisk = %x2A ; * asterisk character
+multi-line-comment = multi-line-comment-start [ multi-line-comment-chars ] multi-line-comment-end
+multi-line-comment-chars = not-asterisk-char [ multi-line-comment-chars ] /
+ asterisk [ post-asterisk-comment-chars ]
+post-asterisk-comment-chars = not-forward-slash-or-asterisk-char [ multi-line-comment-chars ] /
+ asterisk [ post-asterisk-comment-chars ]
+not-asterisk-char = %x00-29 / %x2B-10FFFF
+not-forward-slash-or-asterisk-char = %x00-29 / %x2B-2E / %x30-10FFFF
+
+; Structural characters with surrounding optional whitespace and comments
+begin-array = wsc %x5B wsc ; [ left square bracket
+begin-object = wsc %x7B wsc ; { left curly bracket
+end-array = wsc %x5D wsc ; ] right square bracket
+end-object = wsc %x7D wsc ; } right curly bracket
+name-separator = wsc %x3A wsc ; : colon
+value-separator = wsc %x2C wsc ; , comma
+
+; Any JSON value
+value = false / null / true / object / array / number / string
+
+; Literal names (boolean values and null)
+false = %x66.61.6C.73.65 ; false
+true = %x74.72.75.65 ; true
+null = %x6E.75.6C.6C ; null
+
+; Objects
+object = begin-object [ member *( value-separator member ) ] end-object
+member = string name-separator value
+
+; Arrays
+array = begin-array [ value *( value-separator value ) ] end-array
+
+; Numbers
+number = [ minus ] int [ frac ] [ exp ]
+decimal-point = %x2E ; .
+digit1-9 = %x31-39 ; 1-9
+e = %x65 / %x45 ; e E
+exp = e [ minus / plus ] 1*DIGIT
+frac = decimal-point 1*DIGIT
+int = zero / ( digit1-9 *DIGIT )
+minus = %x2D ; -
+plus = %x2B ; +
+zero = %x30 ; 0
+
+; Strings
+string = quotation-mark *char quotation-mark
+
+char = unescaped /
+ escape (
+ %x22 / ; " quotation mark U+0022
+ %x5C / ; \ reverse solidus U+005C
+ %x2F / ; / solidus U+002F
+ %x62 / ; b backspace U+0008
+ %x66 / ; f form feed U+000C
+ %x6E / ; n line feed U+000A
+ %x72 / ; r carriage return U+000D
+ %x74 / ; t tab U+0009
+ %x75 4HEXDIG ; uXXXX U+XXXX
+ )
+
+escape = %x5C ; \
+quotation-mark = %x22 ; "
+
+unescaped = %x20-21 / %x23-5B / %x5D-10FFFF ; Any code point except quotation mark, reverse solidus or ASCII control chars
+
+; End of JSONC grammar (RFC 8259 extended with JavaScript-style comments).
diff --git a/grammar/railroad-diagram.css b/grammar/railroad-diagram.css
new file mode 100644
index 0000000..87adf27
--- /dev/null
+++ b/grammar/railroad-diagram.css
@@ -0,0 +1,189 @@
+
+/* Railroad diagram styling for connections */
+:root {
+ /* Default sizing configuration */
+ --grid-size: 16px;
+ --font-size: 14px;
+ --track-width: 6px;
+ --text-border: 2px;
+ /* Text box corner radius factor */
+ --text-box-corner-radius-factor: 0.8;
+ /* Rule endpoint circle radius factor */
+ --rule-endpoint-radius-factor: 0.7;
+}
+
+.track {
+ fill: none; /* Prevent filling of the path */
+ stroke: #000;
+ stroke-width: var(--track-width);
+ stroke-linecap: butt; /* End exactly at coordinates, don't extend beyond */
+}
+
+/* Endpoint styling for start/end points */
+.start-endpoint,
+.end-endpoint {
+ fill: black;
+ stroke: none;
+}
+
+/* Endpoint circle styling */
+.endpoint {
+ r: calc(var(--grid-size) * var(--rule-endpoint-radius-factor));
+ fill: black;
+ stroke: none;
+}
+
+.highlight {
+ stroke: red;
+}
+
+/* Terminal and non-terminal text box styling */
+.textbox {
+ stroke-width: var(--text-border);
+ stroke: black;
+ rx: calc(var(--grid-size) * var(--text-box-corner-radius-factor));
+ ry: calc(var(--grid-size) * var(--text-box-corner-radius-factor));
+ fill: none;
+}
+
+.textbox.terminal {
+ fill: rgb(200, 200, 200);
+}
+
+.textbox.nonterminal {
+ fill: rgb(210, 210, 210);
+}
+
+.textbox-text {
+ font-family: Arial, sans-serif;
+ font-size: var(--font-size);
+ fill: black;
+ text-anchor: "middle";
+ dominant-baseline: "middle";
+ alignment-baseline: "middle";
+}
+
+.textbox-text.nonterminal {
+ text-decoration: underline; /* Underline non-terminals */
+ cursor: pointer; /* Show it's clickable */
+ pointer-events: auto; /* Ensure text can receive click events */
+}
+
+.textbox-text.nonterminal:hover {
+ fill: #0066cc; /* Blue on hover */
+}
+
+/* CSS-based debug visualization using HTML overlays */
+.debug-overlay {
+ position: absolute !important;
+ top: 0 !important;
+ left: 0 !important;
+ width: 100% !important;
+ height: 100% !important;
+ pointer-events: none !important;
+ z-index: 10 !important;
+}
+
+.debug-box-overlay {
+ position: absolute !important;
+ border: 1px dotted hotpink !important;
+ box-sizing: border-box !important;
+ pointer-events: none !important;
+}
+
+.debug-baseline-overlay {
+ position: absolute !important;
+ border-top: 1px dashed hotpink !important;
+ pointer-events: none !important;
+}
+
+/* Ensure container has relative positioning for debug overlay */
+.diagram-container {
+ position: relative;
+ margin-top: 1rem;
+}
+
+/* Fallback: Old SVG-based debug styles (in case CSS approach doesn't work) */
+.debug-box {
+ stroke: hotpink;
+ stroke-width: 1px;
+ stroke-dasharray:6 4;
+ fill: none;
+}
+
+.debug-baseline {
+ stroke: hotpink;
+ stroke-width: 1px;
+ stroke-dasharray: 1 1;
+ fill: none;
+}
+
+/* New syntax rule layout styles */
+.syntax-rule {
+ margin: 2rem 0;
+ padding: 1rem;
+ border: 1px solid #ddd;
+ border-radius: 8px;
+ background-color: #fafafa;
+ font-family:'Courier New', Courier, monospace
+}
+
+.syntax-rule h2 {
+ margin: 0 0 1rem 0;
+ color: #333;
+ font-size: 1.2rem;
+}
+
+
+
+.error {
+ color: red;
+ font-weight: bold;
+ padding: 1rem;
+ background-color: #ffe6e6;
+ border: 1px solid red;
+ border-radius: 4px;
+}
+
+/* Grid and bounding box styles - initially hidden */
+.grid-background,
+.bounding-box {
+ display: none;
+}
+
+/* Visible state for grid and bounding boxes */
+.grid-background.visible,
+.bounding-box.visible {
+ display: block !important;
+}
+
+/* Make grid transparent to mouse clicks so elements underneath can be clicked */
+.grid-background {
+ pointer-events: none;
+}
+
+/* Ensure bounding boxes are visible when shown */
+.bounding-box {
+ stroke: limegreen !important;
+ stroke-width: 0.5 !important;
+ fill: rgba(50, 205, 50, 0.1) !important; /* 90% transparent lime green background */
+ opacity: 0.9 !important;
+}
+
+/* Make nonterminal textboxes clickable */
+.textbox.nonterminal {
+ cursor: pointer;
+}
+
+.textbox.nonterminal:hover {
+ fill: rgb(190, 190, 190);
+ stroke-width: calc(var(--text-border) * 1.5);
+}
+
+/* Footer styling */
+.generator-footer {
+ margin-top: 2rem;
+ padding: 1rem;
+ border-top: 1px solid #ccc;
+ color: #666;
+}
diff --git a/grammar/railroad-diagram.html b/grammar/railroad-diagram.html
new file mode 100644
index 0000000..27256f2
--- /dev/null
+++ b/grammar/railroad-diagram.html
@@ -0,0 +1,617 @@
+
+
+
+
+
+ jsonc-processed Grammar
+
+
+
+ jsonc-processed Grammar
+
+
+
JSONC-text
+
JSONC-text := wsc value wsc
+
+
+
+
wsc
+
wsc := *(ws-char / comment)
+
+
+
+
ws-char
+
ws-char := %x20 / %x09 / %x0A / %x0D ; space / tab / LF / CR
+
+
+
+
+
source-character
+
source-character := %x00-10FFFF
+
+
+
+
+
+
+
+
+
+
+
+
+
not-asterisk-char
+
not-asterisk-char := %x00-29 / %x2B-10FFFF
+
+
+
+
+
+
not-forward-slash-or-asterisk-char
+
not-forward-slash-or-asterisk-char := %x00-29 / %x2B-2E / %x30-10FFFF
+
+
+
+
+
+
begin-array
+
begin-array := wsc %x5B wsc ; [ left square bracket
+
+
+
+
begin-object
+
begin-object := wsc %x7B wsc ; { left curly bracket
+
+
+
+
end-array
+
end-array := wsc %x5D wsc ; ] right square bracket
+
+
+
+
end-object
+
end-object := wsc %x7D wsc ; } right curly bracket
+
+
+
+
name-separator
+
name-separator := wsc %x3A wsc ; : colon
+
+
+
+
value-separator
+
value-separator := wsc %x2C wsc ; , comma
+
+
+
+
value
+
value := false / null / true / object / array / number / string
+
+
+
+
+
+
false
+
false := %x66.61.6C.73.65 ; false
+
+
+
+
true
+
true := %x74.72.75.65 ; true
+
+
+
+
null
+
null := %x6E.75.6C.6C ; null
+
+
+
+
object
+
object := begin-object [ member *( value-separator member ) ] end-object
+
+
+
+
+
+
member
+
member := string name-separator value
+
+
+
+
+
+
array
+
array := begin-array [ value *( value-separator value ) ] end-array
+
+
+
+
+
+
number
+
number := [ minus ] int [ frac ] [ exp ]
+
+
+
+
decimal-point
+
decimal-point := %x2E ; .
+
+
+
+
digit1-9
+
digit1-9 := %x31-39 ; 1-9
+
+
+
+
e
+
e := %x65 / %x45 ; e E
+
+
+
+
exp
+
exp := e [ minus / plus ] 1*DIGIT
+
+
+
+
frac
+
frac := decimal-point 1*DIGIT
+
+
+
+
+
+
int
+
int := zero / ( digit1-9 *DIGIT )
+
+
+
+
minus
+
minus := %x2D ; -
+
+
+
+
plus
+
plus := %x2B ; +
+
+
+
+
zero
+
zero := %x30 ; 0
+
+
+
+
string
+
string := quotation-mark *char quotation-mark
+
+
+
+
+
+
char
+
char := unescaped /
+ %x5C (
+ %x22 / ; " quotation mark U+0022
+ %x5C / ; \ reverse solidus U+005C
+ %x2F / ; / solidus U+002F
+ %x62 / ; b backspace U+0008
+ %x66 / ; f form feed U+000C
+ %x6E / ; n line feed U+000A
+ %x72 / ; r carriage return U+000D
+ %x74 / ; t tab U+0009
+ %x75 4HEXDIG ; uXXXX U+XXXX
+ )
+
+
+
+
+
+
quotation-mark
+
quotation-mark := %x22 ; "
+
+
+
+
unescaped
+
unescaped := %x20-21 / %x23-5B / %x5D-10FFFF ; Any code point except quotation mark, reverse solidus or ASCII control chars
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..e73eb09
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,802 @@
+{
+ "name": "jsonc-railroad-tools",
+ "version": "0.1.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "jsonc-railroad-tools",
+ "version": "0.1.0",
+ "dependencies": {
+ "railroad-diagram-generator-js": "file:./submodules/railroad-diagram-generator-js"
+ }
+ },
+ "node_modules/@isaacs/cliui": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz",
+ "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/bl": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+ "license": "MIT",
+ "dependencies": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
+ "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "node_modules/canvas": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/canvas/-/canvas-3.2.3.tgz",
+ "integrity": "sha512-PzE5nJZPz72YUAfo8oTp0u3fqqY7IzlTubneAihqDYAUcBk7ryeCmBbdJBEdaH0bptSOe2VT2Zwcb3UaFyaSWw==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "node-addon-api": "^7.0.0",
+ "prebuild-install": "^7.1.3"
+ },
+ "engines": {
+ "node": "^18.12.0 || >= 20.9.0"
+ }
+ },
+ "node_modules/chownr": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
+ "license": "ISC"
+ },
+ "node_modules/commander": {
+ "version": "14.0.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.1.tgz",
+ "integrity": "sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/decompress-response": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+ "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "mimic-response": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/deep-extend": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/detect-libc": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/end-of-stream": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
+ "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
+ "license": "MIT",
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
+ "node_modules/expand-template": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
+ "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
+ "license": "(MIT OR WTFPL)",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/foreground-child": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
+ "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
+ "license": "ISC",
+ "dependencies": {
+ "cross-spawn": "^7.0.6",
+ "signal-exit": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/fs-constants": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+ "license": "MIT"
+ },
+ "node_modules/fs-extra": {
+ "version": "11.3.4",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz",
+ "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==",
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=14.14"
+ }
+ },
+ "node_modules/github-from-package": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
+ "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
+ "license": "MIT"
+ },
+ "node_modules/glob": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz",
+ "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==",
+ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "foreground-child": "^3.3.1",
+ "jackspeak": "^4.1.1",
+ "minimatch": "^10.1.1",
+ "minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
+ "path-scurry": "^2.0.0"
+ },
+ "bin": {
+ "glob": "dist/esm/bin.mjs"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "license": "ISC"
+ },
+ "node_modules/handlebars": {
+ "version": "4.7.9",
+ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz",
+ "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==",
+ "license": "MIT",
+ "dependencies": {
+ "minimist": "^1.2.5",
+ "neo-async": "^2.6.2",
+ "source-map": "^0.6.1",
+ "wordwrap": "^1.0.0"
+ },
+ "bin": {
+ "handlebars": "bin/handlebars"
+ },
+ "engines": {
+ "node": ">=0.4.7"
+ },
+ "optionalDependencies": {
+ "uglify-js": "^3.1.4"
+ }
+ },
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "license": "ISC"
+ },
+ "node_modules/ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+ "license": "ISC"
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "license": "ISC"
+ },
+ "node_modules/jackspeak": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.2.3.tgz",
+ "integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "@isaacs/cliui": "^9.0.0"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/jsonfile": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz",
+ "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==",
+ "license": "MIT",
+ "dependencies": {
+ "universalify": "^2.0.0"
+ },
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "11.3.5",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz",
+ "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/mimic-response": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+ "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "10.2.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+ "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.5"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/minipass": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
+ "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/mkdirp-classic": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
+ "license": "MIT"
+ },
+ "node_modules/napi-build-utils": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
+ "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==",
+ "license": "MIT"
+ },
+ "node_modules/neo-async": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
+ "license": "MIT"
+ },
+ "node_modules/node-abi": {
+ "version": "3.89.0",
+ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.89.0.tgz",
+ "integrity": "sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA==",
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.3.5"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/node-addon-api": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
+ "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
+ "license": "MIT"
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/package-json-from-dist": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
+ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
+ "license": "BlueOak-1.0.0"
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-scurry": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz",
+ "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "lru-cache": "^11.0.0",
+ "minipass": "^7.1.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/prebuild-install": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
+ "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
+ "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.",
+ "license": "MIT",
+ "dependencies": {
+ "detect-libc": "^2.0.0",
+ "expand-template": "^2.0.3",
+ "github-from-package": "0.0.0",
+ "minimist": "^1.2.3",
+ "mkdirp-classic": "^0.5.3",
+ "napi-build-utils": "^2.0.0",
+ "node-abi": "^3.3.0",
+ "pump": "^3.0.0",
+ "rc": "^1.2.7",
+ "simple-get": "^4.0.0",
+ "tar-fs": "^2.0.0",
+ "tunnel-agent": "^0.6.0"
+ },
+ "bin": {
+ "prebuild-install": "bin.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/pump": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz",
+ "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==",
+ "license": "MIT",
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "node_modules/railroad-diagram-generator-js": {
+ "resolved": "submodules/railroad-diagram-generator-js",
+ "link": true
+ },
+ "node_modules/rc": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+ "license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
+ "dependencies": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ },
+ "bin": {
+ "rc": "cli.js"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
+ "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/simple-concat": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
+ "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/simple-get": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
+ "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "decompress-response": "^6.0.0",
+ "once": "^1.3.1",
+ "simple-concat": "^1.0.0"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/tar-fs": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
+ "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "chownr": "^1.1.1",
+ "mkdirp-classic": "^0.5.2",
+ "pump": "^3.0.0",
+ "tar-stream": "^2.1.4"
+ }
+ },
+ "node_modules/tar-stream": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+ "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+ "license": "MIT",
+ "dependencies": {
+ "bl": "^4.0.3",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/uglify-js": {
+ "version": "3.19.3",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz",
+ "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==",
+ "license": "BSD-2-Clause",
+ "optional": true,
+ "bin": {
+ "uglifyjs": "bin/uglifyjs"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/universalify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+ "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "license": "MIT"
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/wordwrap": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+ "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
+ "license": "MIT"
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "license": "ISC"
+ },
+ "submodules/railroad-diagram-generator-js": {
+ "name": "abnf-to-railroad",
+ "version": "0.0.6",
+ "license": "MIT",
+ "dependencies": {
+ "canvas": "^3.2.0",
+ "commander": "14.0.1",
+ "fs-extra": "^11.0.0",
+ "glob": "11.1.0",
+ "handlebars": "^4.7.8"
+ },
+ "bin": {
+ "abnf-to-railroad": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..145893f
--- /dev/null
+++ b/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "jsonc-railroad-tools",
+ "private": true,
+ "version": "0.1.0",
+ "scripts": {
+ "railroad": "node generate-railroad.js"
+ },
+ "dependencies": {
+ "railroad-diagram-generator-js": "file:./submodules/railroad-diagram-generator-js"
+ }
+}
\ No newline at end of file
diff --git a/submodules/railroad-diagram-generator-js b/submodules/railroad-diagram-generator-js
new file mode 160000
index 0000000..e3e2166
--- /dev/null
+++ b/submodules/railroad-diagram-generator-js
@@ -0,0 +1 @@
+Subproject commit e3e21669af406cad1c94c75774d891a9f6447363