diff --git a/epub/.gitignore b/epub/.gitignore new file mode 100644 index 000000000..44774968b --- /dev/null +++ b/epub/.gitignore @@ -0,0 +1,5 @@ +dist/ +node_modules/ +*.epub +test_*.js +validation-report.json diff --git a/epub/README.md b/epub/README.md new file mode 100644 index 000000000..1be24744d --- /dev/null +++ b/epub/README.md @@ -0,0 +1,58 @@ +# Hello Algorithm EPUB Converter + +Convert [Hello Algorithm](https://github.com/krahets/hello-algo) Markdown documentation to EPUB e-books. + +## Installation + +```bash +npm install +``` + +## Usage + +### Basic Usage + +```bash +# Build Chinese version with C++ code (default) +npm run build + +# Build with specific programming language +npm run build -- -l python + +# Build Traditional Chinese version +npm run build -- -d zh-hant -l python -o hello-algo-zh-hant-python.epub + +# Build English version +npm run build -- -d en -l python -o hello-algo-en-python.epub + +# Build Japanese version +npm run build -- -d ja -l cpp -o hello-algo-ja-cpp.epub + +# Build all combinations +npm run build -- --all --release-version 1.2.0 +``` + +### Command Line Parameters + +| Parameter | Short | Description | Default | +|-----------|-------|-------------|---------| +| `--doc-language` | `-d` | Document language (zh, zh-hant, en, ja) | `zh` | +| `--output` | `-o` | Output EPUB file path | `./hello-algo.epub` | +| `--language` | `-l` | Programming language | `cpp` | +| `--all` | `-a` | Build all combinations | - | +| `--release-version` | - | Version number for output filename | `1.0.0` | +| `--validate` | - | Enable content integrity validation | `false` | +| `--help` | `-h` | Show help | - | +| `--version` | `-V` | Show version | - | + +### Supported Languages + +**Document Languages:** +- `zh` - Simplified Chinese (all programming languages) +- `zh-hant` - Traditional Chinese (all programming languages) +- `en` - English (cpp, java, python only) +- `ja` - Japanese (cpp, java, python only) + +**Programming Languages:** +- Supported by all document languages: `cpp`, `python`, `java` +- Supported by Chinese versions only: `csharp`, `go`, `swift`, `javascript`, `typescript`, `dart`, `rust`, `c`, `kotlin`, `ruby`, `zig` diff --git a/epub/covers/hello-algo-cover-en.jpg b/epub/covers/hello-algo-cover-en.jpg new file mode 100644 index 000000000..f65fad98b Binary files /dev/null and b/epub/covers/hello-algo-cover-en.jpg differ diff --git a/epub/covers/hello-algo-cover-zh-hant.jpg b/epub/covers/hello-algo-cover-zh-hant.jpg new file mode 100644 index 000000000..0ba7ca92a Binary files /dev/null and b/epub/covers/hello-algo-cover-zh-hant.jpg differ diff --git a/epub/covers/hello-algo-cover-zh.jpg b/epub/covers/hello-algo-cover-zh.jpg new file mode 100644 index 000000000..209efe63b Binary files /dev/null and b/epub/covers/hello-algo-cover-zh.jpg differ diff --git a/epub/fonts/MathJax_Main-Regular.otf b/epub/fonts/MathJax_Main-Regular.otf new file mode 100644 index 000000000..5cfdff9a9 Binary files /dev/null and b/epub/fonts/MathJax_Main-Regular.otf differ diff --git a/epub/fonts/MathJax_Math-Regular.otf b/epub/fonts/MathJax_Math-Regular.otf new file mode 100644 index 000000000..9d9c1684a Binary files /dev/null and b/epub/fonts/MathJax_Math-Regular.otf differ diff --git a/epub/package-lock.json b/epub/package-lock.json new file mode 100644 index 000000000..a3ca142fc --- /dev/null +++ b/epub/package-lock.json @@ -0,0 +1,1735 @@ +{ + "name": "hello-algo-epub", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "hello-algo-epub", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@types/commander": "^2.12.0", + "adm-zip": "^0.5.10", + "commander": "^14.0.2", + "epub-gen": "^0.1.0", + "fs-extra": "^11.2.0", + "highlight.js": "^11.11.1", + "js-yaml": "^4.1.0", + "marked": "^11.1.1", + "path": "^0.12.7" + }, + "devDependencies": { + "@types/fs-extra": "^11.0.4", + "@types/js-yaml": "^4.0.9", + "@types/node": "^20.11.0", + "ts-node": "^10.9.2", + "typescript": "^5.3.3" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/commander": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@types/commander/-/commander-2.12.0.tgz", + "integrity": "sha512-DDmRkovH7jPjnx7HcbSnqKg2JeNANyxNZeUvB0iE+qKBLN+vzN5iSIwt+J2PFSmBuYEut4mgQvI/fTX9YQH/vw==", + "license": "MIT", + "dependencies": { + "commander": "*" + } + }, + "node_modules/@types/fs-extra": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz", + "integrity": "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/jsonfile": "*", + "@types/node": "*" + } + }, + "node_modules/@types/js-yaml": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", + "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jsonfile": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.4.tgz", + "integrity": "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.19.26", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.26.tgz", + "integrity": "sha512-0l6cjgF0XnihUpndDhk+nyD3exio3iKaYROSgvh/qSevPXax3L8p5DBRFjbvalnwatGgHEQn2R88y2fA3g4irg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/adm-zip": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz", + "integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==", + "license": "MIT", + "engines": { + "node": ">=12.0" + } + }, + "node_modules/archiver": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-3.1.1.tgz", + "integrity": "sha512-5Hxxcig7gw5Jod/8Gq0OneVgLYET+oNHcxgWItq4TbhOzRLKNAFUb9edAftiMKXvXfCB0vbGrJdZDNq0dWMsxg==", + "license": "MIT", + "dependencies": { + "archiver-utils": "^2.1.0", + "async": "^2.6.3", + "buffer-crc32": "^0.2.1", + "glob": "^7.1.4", + "readable-stream": "^3.4.0", + "tar-stream": "^2.1.0", + "zip-stream": "^2.1.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "license": "MIT", + "dependencies": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/archiver-utils/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/archiver-utils/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "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/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/cheerio": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", + "integrity": "sha512-8/MzidM6G/TgRelkzDG13y3Y9LxBjCb+8yOEZ9+wwq5gVF2w2pV0wmHvjfT0RvuxGyR7UEuK36r+yYMbT4uKgA==", + "license": "MIT", + "dependencies": { + "css-select": "~1.2.0", + "dom-serializer": "~0.1.0", + "entities": "~1.1.1", + "htmlparser2": "^3.9.1", + "lodash.assignin": "^4.0.9", + "lodash.bind": "^4.1.4", + "lodash.defaults": "^4.0.1", + "lodash.filter": "^4.4.0", + "lodash.flatten": "^4.2.0", + "lodash.foreach": "^4.3.0", + "lodash.map": "^4.4.0", + "lodash.merge": "^4.4.0", + "lodash.pick": "^4.2.1", + "lodash.reduce": "^4.4.0", + "lodash.reject": "^4.4.0", + "lodash.some": "^4.4.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/compress-commons": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-2.1.1.tgz", + "integrity": "sha512-eVw6n7CnEMFzc3duyFVrQEuY1BlHR3rYsSztyG32ibGMW722i3C6IizEGMFmfMU+A+fALvBIwxN3czffTcdA+Q==", + "license": "MIT", + "dependencies": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^3.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^2.3.6" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/compress-commons/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/compress-commons/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/compress-commons/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "license": "MIT" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/crc": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "license": "MIT", + "dependencies": { + "buffer": "^5.1.0" + } + }, + "node_modules/crc32-stream": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-3.0.1.tgz", + "integrity": "sha512-mctvpXlbzsvK+6z8kJwSJ5crm7yBwrQMTybJzMw1O4lLGJqjlDCXY2Zw7KheiA6XBEcBmfLx1D88mjRGVJtY9w==", + "license": "MIT", + "dependencies": { + "crc": "^3.4.4", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 6.9.0" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha512-dUQOBoqdR7QwV90WysXPLXG5LO7nhYBgiWVfxF80DKPF8zx1t/pUd2FYy73emg3zrjtM6dzmYgbHKfV2rxiHQA==", + "license": "BSD-like", + "dependencies": { + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" + } + }, + "node_modules/css-what": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", + "license": "BSD-2-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/diacritics": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/diacritics/-/diacritics-1.3.0.tgz", + "integrity": "sha512-wlwEkqcsaxvPJML+rDh/2iS824jbREk6DUMUKkEaSlxdYHeS43cClJtsWglvw2RfeXGm6ohKDqsXteJ5sP5enA==", + "license": "MIT" + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dom-serializer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "license": "MIT", + "dependencies": { + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "node_modules/domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "1" + } + }, + "node_modules/domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==", + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ejs": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz", + "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "engines": { + "node": ">=0.10.0" + } + }, + "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/entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "license": "BSD-2-Clause" + }, + "node_modules/epub-gen": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/epub-gen/-/epub-gen-0.1.0.tgz", + "integrity": "sha512-Xt2tP4XlDkZnrJCumP+3v4nEWqIN5JXNu0V5aUywwmKkhhIUrzRQ75igKFBbE2H0mUKlWnIpv2YMmzEa+RJeiw==", + "license": "MIT", + "dependencies": { + "archiver": "^3.0.0", + "cheerio": "^0.22.0", + "diacritics": "^1.3.0", + "ejs": "^2.6.1", + "entities": "^1.1.2", + "fs-extra": "^7.0.1", + "mime": "^2.4.0", + "q": "^1.5.1", + "rimraf": "^2.6.3", + "superagent": "^3.8.3", + "underscore": "^1.9.1", + "uslug": "^1.0.4" + } + }, + "node_modules/epub-gen/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/epub-gen/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/epub-gen/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/form-data": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.5.tgz", + "integrity": "sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.35", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/formidable": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.6.tgz", + "integrity": "sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==", + "deprecated": "Please upgrade to latest, formidable@v2 or formidable@v3! Check these notes: https://bit.ly/2ZEqIau", + "license": "MIT", + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "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.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz", + "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/highlight.js": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "license": "MIT", + "dependencies": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + } + }, + "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/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "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/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.assignin": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", + "integrity": "sha512-yX/rx6d/UTVh7sSVWVSIMjfnz95evAgDFdb1ZozC35I9mSFCkmzptOzevxjgbQUsc78NR44LVHWjsoMQXy9FDg==", + "license": "MIT" + }, + "node_modules/lodash.bind": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", + "integrity": "sha512-lxdsn7xxlCymgLYo1gGvVrfHmkjDiyqVv62FAeF2i5ta72BipE1SLxw8hPEPLhD4/247Ijw07UQH7Hq/chT5LA==", + "license": "MIT" + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "license": "MIT" + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "license": "MIT" + }, + "node_modules/lodash.filter": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz", + "integrity": "sha512-pXYUy7PR8BCLwX5mgJ/aNtyOvuJTdZAo9EQFUvMIYugqmJxnrYaANvTbgndOzHSCSR0wnlBBfRXJL5SbWxo3FQ==", + "license": "MIT" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "license": "MIT" + }, + "node_modules/lodash.foreach": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", + "integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.map": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", + "integrity": "sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "license": "MIT" + }, + "node_modules/lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==", + "deprecated": "This package is deprecated. Use destructuring assignment syntax instead.", + "license": "MIT" + }, + "node_modules/lodash.reduce": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", + "integrity": "sha512-6raRe2vxCYBhpBu+B+TtNGUzah+hQjVdu3E17wfusjyrXBka2nBS8OH/gjVZ5PvHOhWmIZTYri09Z6n/QfnNMw==", + "license": "MIT" + }, + "node_modules/lodash.reject": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz", + "integrity": "sha512-qkTuvgEzYdyhiJBx42YPzPo71R1aEr0z79kAv7Ixg8wPFEjgRgJdUsGMG3Hf3OYSF/kHI79XhNlt+5Ar6OzwxQ==", + "license": "MIT" + }, + "node_modules/lodash.some": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", + "integrity": "sha512-j7MJE+TuT51q9ggt4fSgVqro163BEFjAt3u97IqU+JA2DkWl80nFTrowzLpZ/BnpN7rrl0JA/593NAdd8p/scQ==", + "license": "MIT" + }, + "node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", + "license": "MIT" + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/marked": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-11.2.0.tgz", + "integrity": "sha512-HR0m3bvu0jAPYiIvLUUQtdg1g6D247//lvcekpHO1WMvbwDlwSkZAX9Lw4F4YHE1T0HaaNve0tuAWuV1UJ6vtw==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "~1.0.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/path": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", + "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==", + "license": "MIT", + "dependencies": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", + "license": "MIT", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "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/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/superagent": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", + "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", + "deprecated": "Please upgrade to superagent v10.2.2+, see release notes at https://github.com/forwardemail/superagent/releases/tag/v10.2.2 - maintenance is supported by Forward Email @ https://forwardemail.net", + "license": "MIT", + "dependencies": { + "component-emitter": "^1.2.0", + "cookiejar": "^2.1.0", + "debug": "^3.1.0", + "extend": "^3.0.0", + "form-data": "^2.3.1", + "formidable": "^1.2.0", + "methods": "^1.1.1", + "mime": "^1.4.1", + "qs": "^6.5.1", + "readable-stream": "^2.3.5" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/superagent/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/superagent/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/superagent/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/superagent/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "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/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/underscore": { + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", + "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "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/unorm": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz", + "integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==", + "license": "MIT or GPL-2.0", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uslug": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/uslug/-/uslug-1.0.4.tgz", + "integrity": "sha512-Jrbpp/NS3TvIGNjfJT1sn3/BCeykoxR8GbNYW5lF6fUscLkbXFwj1b7m4DvIkHm8k3Qr6Co68lbTmoZTMGk/ow==", + "dependencies": { + "unorm": ">= 1.0.0" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "license": "MIT", + "dependencies": { + "inherits": "2.0.3" + } + }, + "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/util/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "license": "ISC" + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "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" + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/zip-stream": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-2.1.3.tgz", + "integrity": "sha512-EkXc2JGcKhO5N5aZ7TmuNo45budRaFGHOmz24wtJR7znbNqDPmdZtUauKX6et8KAVseAMBOyWJqEpXcHTBsh7Q==", + "license": "MIT", + "dependencies": { + "archiver-utils": "^2.1.0", + "compress-commons": "^2.1.1", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 6" + } + } + } +} diff --git a/epub/package.json b/epub/package.json new file mode 100644 index 000000000..c2cbf70fc --- /dev/null +++ b/epub/package.json @@ -0,0 +1,34 @@ +{ + "name": "hello-algo-epub", + "version": "1.0.0", + "description": "Convert Hello Algorithm docs to EPUB", + "main": "dist/index.js", + "scripts": { + "build": "ts-node src/index.ts" + }, + "keywords": [ + "epub", + "markdown", + "ebook" + ], + "author": "", + "license": "MIT", + "dependencies": { + "@types/commander": "^2.12.0", + "adm-zip": "^0.5.10", + "commander": "^14.0.2", + "epub-gen": "^0.1.0", + "fs-extra": "^11.2.0", + "highlight.js": "^11.11.1", + "js-yaml": "^4.1.0", + "marked": "^11.1.1", + "path": "^0.12.7" + }, + "devDependencies": { + "@types/fs-extra": "^11.0.4", + "@types/js-yaml": "^4.0.9", + "@types/node": "^20.11.0", + "ts-node": "^10.9.2", + "typescript": "^5.3.3" + } +} diff --git a/epub/src/epub.ts b/epub/src/epub.ts new file mode 100644 index 000000000..6d573ec7e --- /dev/null +++ b/epub/src/epub.ts @@ -0,0 +1,371 @@ +import * as fs from 'fs-extra'; +import * as path from 'path'; +import { Chapter, ImageInfo, EpubGenOptions } from './types'; +import { markdownToHtml, extractImagePaths, readImage, getCustomCSS } from './markdown'; + +const Epub = require('epub-gen'); + +export interface EpubOptions { + title: string; + author: string; + publisher?: string; + description?: string; + language?: string; + cover?: string; + codeLanguage?: string; // Programming language for code examples + docLanguage?: string; // Document language (zh, zh-hant, en, ja) + version?: string; // Version number +} + +/** + * Get table of contents title based on document language + */ +function getTocTitle(docLanguage?: string): string { + const tocTitles: { [key: string]: string } = { + 'zh': '目录', + 'zh-hant': '目錄', + 'en': 'Table of Contents', + 'ja': '目次', + }; + return tocTitles[docLanguage || 'zh'] || '目录'; +} + +/** + * Generate homepage HTML + */ +function generateTitlePage(title: string, author: string, docLanguage?: string, version?: string, codeLanguage?: string): string { + const lang = docLanguage || 'zh'; + + // Code reviewer mapping by language and document language + const codeReviewers: { [docLang: string]: { [codeLang: string]: string } } = { + 'zh': { + 'python': '靳宇栋(@krahets)', + 'cpp': '宫兰景(@Gonglja)', + 'java': '靳宇栋(@krahets)', + 'csharp': '@hpstory', + 'go': '刘代富(@Reanon)', + 'swift': '@nuomi1', + 'javascript': '谢发 (@justin-tse)', + 'typescript': '谢发 (@justin-tse)', + 'dart': '刘玉新(@gvenusleo)', + 'rust': '伍志豪(@night-cruise)、荣怡(@rongyi)', + 'c': '宫兰景(@Gonglja)', + 'ruby': '阮春科秀(@khoaxuantu)', + 'kotlin': '陈东辉(@curtishd)', + }, + 'zh-hant': { + 'python': '靳宇棟(@krahets)', + 'cpp': '宮蘭景(@Gonglja)', + 'java': '靳宇棟(@krahets)', + 'csharp': '@hpstory', + 'go': '劉代富(@Reanon)', + 'swift': '@nuomi1', + 'javascript': '謝發 (@justin-tse)', + 'typescript': '謝發 (@justin-tse)', + 'dart': '劉玉新(@gvenusleo)', + 'rust': '伍志豪(@night-cruise)、榮怡(@rongyi)', + 'c': '宮蘭景(@Gonglja)', + 'ruby': '阮春科秀(@khoaxuantu)', + 'kotlin': '陳東輝(@curtishd)', + }, + 'en': { + 'python': 'Yudong Jin (@krahets)', + 'cpp': 'Lanjing Gong (@Gonglja)', + 'java': 'Yudong Jin (@krahets)', + 'csharp': '@hpstory', + 'go': 'Daifu Liu (@Reanon)', + 'swift': '@nuomi1', + 'javascript': 'Fa Xie (@justin-tse)', + 'typescript': 'Fa Xie (@justin-tse)', + 'dart': 'Yuxin Liu (@gvenusleo)', + 'rust': 'Zhihao Wu (@night-cruise), Yi Rong (@rongyi)', + 'c': 'Lanjing Gong (@Gonglja)', + 'ruby': 'Chunke Xiu Ruan (@khoaxuantu)', + 'kotlin': 'Donghui Chen (@curtishd)', + }, + 'ja': { + 'python': '靳宇棟(@krahets)', + 'cpp': '宮蘭景(@Gonglja)', + 'java': '靳宇棟(@krahets)', + 'csharp': '@hpstory', + 'go': '劉代富(@Reanon)', + 'swift': '@nuomi1', + 'javascript': '謝発 (@justin-tse)', + 'typescript': '謝発 (@justin-tse)', + 'dart': '劉玉新(@gvenusleo)', + 'rust': '伍志豪(@night-cruise)、栄怡(@rongyi)', + 'c': '宮蘭景(@Gonglja)', + 'ruby': '阮春科秀(@khoaxuantu)', + 'kotlin': '陳東輝(@curtishd)', + }, + }; + + // Multilingual text configuration + const i18n: { [key: string]: { subtitle: string; authorPrefix: string; authorName: string; codeReviewPrefix: string; readOnline: string; codeRepo: string; versionPrefix: string } } = { + 'zh': { + subtitle: '动画图解、一键运行的数据结构与算法教程', + authorPrefix: '作者:', + authorName: '靳宇栋 (@krahets)', + codeReviewPrefix: '代码审阅:', + readOnline: '在线阅读', + codeRepo: '代码仓库', + versionPrefix: '版本', + }, + 'zh-hant': { + subtitle: '動畫圖解、一鍵運行的資料結構與演算法教程', + authorPrefix: '作者:', + authorName: '靳宇棟 (@krahets)', + codeReviewPrefix: '程式碼審閱:', + readOnline: '線上閱讀', + codeRepo: '程式碼倉庫', + versionPrefix: '版本', + }, + 'en': { + subtitle: 'Data structures and algorithms crash course with animated illustrations and off-the-shelf code', + authorPrefix: 'Author: ', + authorName: 'Yudong Jin (@krahets)', + codeReviewPrefix: 'Code Review: ', + readOnline: 'Read Online', + codeRepo: 'Code Repository', + versionPrefix: 'Version', + }, + 'ja': { + subtitle: 'アニメーション図解、ワンクリック実行のデータ構造とアルゴリズム教程', + authorPrefix: '著者:', + authorName: '靳宇棟 (@krahets)', + codeReviewPrefix: 'コードレビュー:', + readOnline: 'オンライン閲覧', + codeRepo: 'コードリポジトリ', + versionPrefix: 'バージョン', + }, + }; + + const text = i18n[lang] || i18n['zh']; + const versionText = version ? `${text.versionPrefix} ${version}` : ''; + const codeReviewer = codeLanguage && codeReviewers[lang] && codeReviewers[lang][codeLanguage] + ? codeReviewers[lang][codeLanguage] + : ''; + + return ` +
${text.subtitle}
+ +${text.authorPrefix}${text.authorName}
+ + ${codeReviewer ? `${text.codeReviewPrefix}${codeReviewer}
` : ''} + + ${versionText ? `${versionText}
` : ''} + +
+ ${text.readOnline}
+ www.hello-algo.com
+
+ ${text.codeRepo}
+ github.com/krahets/hello-algo
+
${codeWithFilename}`;
+ }
+
+ // Normal code block without filename
+ return `${highlightedCode}`;
+ };
+
+ // Custom table rendering, maintain original format
+ renderer.table = (header: string, body: string) => {
+ return `syntax, convert it to use CSS class + markdown = markdown.replace(/
/g, '
');
+
+ // Use placeholders to protect math formulas from being escaped by marked
+ // Use pure alphanumeric placeholders (avoid special characters being parsed by Markdown)
+ const mathPlaceholders = new Map syntax, converted to .text-center) */
+ .text-center {
+ text-align: center;
+ }
+ /* Reduce bold text font weight */
+ strong, b {
+ font-weight: 600;
+ }
+ h1, h2, h3, h4, h5, h6 {
+ color: #24292e;
+ margin-top: 1.2em;
+ margin-bottom: 0.6em;
+ font-weight: 600;
+ line-height: 1.25;
+ }
+ /* Chapter title (Chapter X) */
+ h1 {
+ font-size: 1.5em;
+ text-align: center;
+ }
+ /* Section title (X.Y) */
+ h2 { font-size: 1.3em; }
+ /* Main heading within Markdown document */
+ h3 { font-size: 1.15em; }
+ /* Subheading within Markdown document */
+ h4 { font-size: 1.05em; }
+ h5 { font-size: 1.0em; }
+ h6 { font-size: 1.0em; }
+ /* Inline code */
+ code {
+ background-color: #f0f0f0;
+ padding: 2px 6px;
+ border-radius: 3px;
+ border: 1px solid #d0d0d0;
+ font-family: "JetBrains Mono", "Consolas", "Monaco", "Courier New", monospace;
+ font-size: 0.82em;
+ color: #333;
+ }
+
+ /* Code blocks */
+ pre {
+ padding: 3px 3px;
+ background-color: #f5f5f5;
+ border: 1.5px solid #d0d0d0;
+ border-radius: 6px;
+ margin: 16px 0;
+ line-height: 1.65;
+ page-break-inside: auto !important;
+ break-inside: auto !important;
+ }
+
+ pre code {
+ background-color: #f5f5f5;
+ padding: 14px 16px;
+ border: none;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+ word-break: break-all;
+ overflow-wrap: break-word;
+ font-family: "JetBrains Mono", "Consolas", "Monaco", "Courier New", monospace;
+ font-size: 0.78em;
+ color: #24292e;
+ display: block;
+ }
+ img {
+ max-width: 100%;
+ height: auto;
+ display: block;
+ margin: 20px auto;
+ border-radius: 8px;
+ }
+ blockquote {
+ border-left: 4px solid #3498db;
+ margin: 0;
+ padding-left: 20px;
+ color: #666;
+ }
+ table {
+ border-collapse: collapse;
+ width: 100%;
+ margin: 20px 0;
+ border: 1px solid #ddd;
+ font-size: 0.8em;
+ }
+ th, td {
+ border: 1px solid #ddd;
+ padding: 12px;
+ text-align: left;
+ vertical-align: top;
+ }
+ th {
+ background-color: #f2f2f2;
+ font-weight: bold;
+ text-align: center;
+ }
+ tbody tr:nth-child(even) {
+ background-color: #f9f9f9;
+ }
+ table code {
+ background-color: #f4f4f4;
+ padding: 2px 4px;
+ border-radius: 3px;
+ font-size: 1em;
+ }
+ .math-inline {
+ white-space: nowrap;
+ font-family: "MathJax_Math", "MathJax_Main", "STIX Two Math", "Latin Modern Math", "Computer Modern", "Times New Roman", Times, serif;
+ font-size: 1.05em;
+ vertical-align: baseline;
+ line-height: 1.4;
+ font-weight: normal;
+ letter-spacing: 0.01em;
+ }
+ .math-inline i {
+ font-style: italic;
+ font-family: "MathJax_Math", "MathJax_Main", "STIX Two Math", "Latin Modern Math", "Computer Modern", "Times New Roman", Times, serif;
+ }
+ .math-block {
+ text-align: center;
+ margin: 20px 0;
+ padding: 10px;
+ font-family: "MathJax_Math", "MathJax_Main", "STIX Two Math", "Latin Modern Math", "Computer Modern", "Times New Roman", Times, serif;
+ font-size: 1.05em;
+ }
+ .math-block i {
+ font-style: italic;
+ font-family: "MathJax_Math", "MathJax_Main", "STIX Two Math", "Latin Modern Math", "Computer Modern", "Times New Roman", Times, serif;
+ }
+ .math-function {
+ font-style: normal;
+ font-weight: normal;
+ }
+ .math-text {
+ font-style: normal;
+ font-weight: normal;
+ }
+ .math-roman {
+ font-style: normal;
+ font-weight: normal;
+ }
+ .math-aligned {
+ margin: 10px auto;
+ border-collapse: collapse;
+ border: none;
+ width: auto;
+ display: table;
+ }
+ .math-aligned td {
+ border: none;
+ padding: 6px 12px;
+ vertical-align: middle;
+ font-family: "MathJax_Math", "MathJax_Main", "STIX Two Math", "Latin Modern Math", "Computer Modern", "Times New Roman", Times, serif;
+ font-size: 1.05em;
+ }
+ .math-aligned i {
+ font-style: italic;
+ }
+ .math-inline sup,
+ .math-block sup {
+ font-size: 0.7em;
+ vertical-align: super;
+ }
+ .math-inline sub,
+ .math-block sub {
+ font-size: 0.7em;
+ vertical-align: sub;
+ }
+ .admonition {
+ margin: 20px 0;
+ padding: 12px 16px 8px 16px;
+ border: 2px solid #6d85df;
+ border-radius: 6px;
+ background-color: #f8f9fa;
+ }
+ .admonition-title {
+ font-weight: 600;
+ margin-bottom: 8px;
+ color: #2c3e50;
+ }
+ .admonition.note {
+ border-color: #53bbb1;
+ background-color: #f6fbfb;
+ }
+ .admonition.tip {
+ border-color: #53bbb1;
+ background-color: #f6fbfb;
+ }
+ .admonition.success {
+ border-color: #82bb81;
+ background-color: #f8fcf9;
+ }
+ .admonition.warning {
+ border-color: #ffc107;
+ background-color: #fff3cd;
+ }
+ .admonition.danger {
+ border-color: #dc3545;
+ background-color: #f8d7da;
+ }
+ .admonition.info {
+ border-color: #17a2b8;
+ background-color: #d1ecf1;
+ }
+ .admonition.abstract {
+ border-color: #6d85df;
+ background-color: #f8f9fa;
+ }
+ .admonition.question {
+ border-color: #82bb81;
+ background-color: #f8fcf9;
+ }
+ .admonition.quote {
+ border-color: #898989;
+ background-color: #f9f9f9;
+ }
+ ul, ol {
+ padding-left: 30px;
+ }
+ li {
+ margin: 5px 0;
+ }
+
+ /* Syntax highlighting styles (GitHub Light theme) */
+ .hljs {
+ display: block;
+ padding: 14px 16px;
+ color: #24292e;
+ background: #f5f5f5;
+ }
+
+ .hljs-comment,
+ .hljs-quote {
+ color: #6a737d;
+ font-style: italic;
+ }
+
+ .hljs-keyword,
+ .hljs-selector-tag,
+ .hljs-subst {
+ color: #d73a49;
+ font-weight: bold;
+ }
+
+ .hljs-number,
+ .hljs-literal,
+ .hljs-variable,
+ .hljs-template-variable,
+ .hljs-tag .hljs-attr {
+ color: #005cc5;
+ }
+
+ .hljs-string,
+ .hljs-doctag {
+ color: #032f62;
+ }
+
+ .hljs-title,
+ .hljs-section,
+ .hljs-selector-id {
+ color: #6f42c1;
+ font-weight: bold;
+ }
+
+ .hljs-subst {
+ font-weight: normal;
+ }
+
+ .hljs-type,
+ .hljs-class .hljs-title {
+ color: #d73a49;
+ font-weight: bold;
+ }
+
+ .hljs-tag,
+ .hljs-name,
+ .hljs-attribute {
+ color: #22863a;
+ font-weight: normal;
+ }
+
+ .hljs-regexp,
+ .hljs-link {
+ color: #032f62;
+ }
+
+ .hljs-symbol,
+ .hljs-bullet {
+ color: #e36209;
+ }
+
+ .hljs-built_in,
+ .hljs-builtin-name {
+ color: #005cc5;
+ }
+
+ .hljs-meta {
+ color: #6a737d;
+ font-weight: bold;
+ }
+
+ .hljs-deletion {
+ background: #ffeef0;
+ }
+
+ .hljs-addition {
+ background: #f0fff4;
+ }
+
+ .hljs-emphasis {
+ font-style: italic;
+ }
+
+ .hljs-strong {
+ font-weight: bold;
+ }
+`;
+}
+
+/**
+ * Wrap HTML content (simplified version, styles provided by CSS file)
+ */
+function wrapHtmlContent(html: string): string {
+ return html;
+}
+
+/**
+ * Extract all headings from Markdown text
+ * @param markdown Markdown text
+ * @param chapterPath Chapter path (for identification)
+ * @returns Heading list
+ */
+export function extractHeadings(markdown: string, chapterPath: string): HeadingInfo[] {
+ const headings: HeadingInfo[] = [];
+ const lines = markdown.split('\n');
+ let inCodeBlock = false;
+ let inFencedBlock = false;
+
+ for (let i = 0; i < lines.length; i++) {
+ const line = lines[i];
+
+ // Check code block boundaries (three backticks or tildes)
+ if (line.match(/^\s*```/) || line.match(/^\s*~~~/)) {
+ inCodeBlock = !inCodeBlock;
+ continue;
+ }
+
+ // Check indented code blocks (4 spaces)
+ if (line.match(/^ /) && !inCodeBlock) {
+ inFencedBlock = true;
+ continue;
+ } else if (inFencedBlock && !line.match(/^ /) && line.trim()) {
+ inFencedBlock = false;
+ }
+
+ // Skip content in code blocks
+ if (inCodeBlock || inFencedBlock) {
+ continue;
+ }
+
+ // Match ATX-style headings: # ## ### etc.
+ const match = line.match(/^(#{1,6})\s+(.+)$/);
+ if (match) {
+ const level = match[1].length;
+ let text = match[2].trim();
+
+ // Remove Markdown formatting and math formulas from heading, keep plain text
+ text = text
+ .replace(/\$[^$]+\$/g, '') // Remove inline math formulas
+ .replace(/\*\*(.+?)\*\*/g, '$1') // Remove bold
+ .replace(/\*(.+?)\*/g, '$1') // Remove italic
+ .replace(/`(.+?)`/g, '$1') // Remove code
+ .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') // Remove links, keep text
+ .trim();
+
+ if (text) {
+ headings.push({
+ level,
+ text,
+ chapterPath,
+ lineNumber: i + 1
+ });
+ }
+ }
+ }
+
+ return headings;
+}
+
+/**
+ * Extract image paths from Markdown
+ */
+export function extractImagePaths(markdown: string, markdownFilePath: string): Array<{ original: string; fullPath: string }> {
+ const imageRegex = /!\[([^\]]*)\]\(([^)]+)\)/g;
+ const paths: Array<{ original: string; fullPath: string }> = [];
+ let match;
+ const markdownDir = path.dirname(markdownFilePath);
+ const docsRoot = path.resolve(markdownDir, '..');
+
+ while ((match = imageRegex.exec(markdown)) !== null) {
+ const imagePath = match[2];
+ // Handle relative paths
+ if (!imagePath.startsWith('http://') && !imagePath.startsWith('https://') && !imagePath.startsWith('data:')) {
+ // Try multiple possible paths
+ const possiblePaths = [
+ path.resolve(markdownDir, imagePath), // Relative to current markdown file
+ path.resolve(docsRoot, imagePath), // Relative to docs root directory
+ path.resolve(markdownDir, '..', imagePath), // Parent directory
+ ];
+
+ for (const fullPath of possiblePaths) {
+ if (fs.existsSync(fullPath)) {
+ paths.push({ original: imagePath, fullPath });
+ break;
+ }
+ }
+ }
+ }
+
+ return paths;
+}
+
+/**
+ * Read image file
+ */
+export function readImage(imagePath: string): ImageInfo | null {
+ try {
+ const data = fs.readFileSync(imagePath);
+ const ext = path.extname(imagePath).toLowerCase();
+ const mimeTypes: { [key: string]: string } = {
+ '.jpg': 'image/jpeg',
+ '.jpeg': 'image/jpeg',
+ '.png': 'image/png',
+ '.gif': 'image/gif',
+ '.svg': 'image/svg+xml',
+ '.webp': 'image/webp',
+ };
+ const mimeType = mimeTypes[ext] || 'image/png';
+
+ return {
+ src: path.basename(imagePath),
+ data,
+ mimeType,
+ };
+ } catch (error) {
+ console.warn(`Unable to read image: ${imagePath}`, error);
+ return null;
+ }
+}
+
+/**
+ * Convert image to base64 data URI
+ */
+export function imageToDataUri(imageInfo: ImageInfo): string {
+ const base64 = imageInfo.data.toString('base64');
+ return `data:${imageInfo.mimeType};base64,${base64}`;
+}
+
diff --git a/epub/src/parser.ts b/epub/src/parser.ts
new file mode 100644
index 000000000..4e7c0a91b
--- /dev/null
+++ b/epub/src/parser.ts
@@ -0,0 +1,168 @@
+import * as fs from 'fs-extra';
+import * as path from 'path';
+import * as yaml from 'js-yaml';
+import { NavItem, Chapter, MkDocsNavItem } from './types';
+
+/**
+ * Parse mkdocs.yml file to extract version number
+ */
+export function parseVersion(configPath: string): string {
+ const content = fs.readFileSync(configPath, 'utf-8');
+ const config = yaml.load(content) as any;
+ return config.version || '1.0.0';
+}
+
+/**
+ * Parse mkdocs.yml file to extract navigation structure
+ */
+export function parseMkdocsConfig(configPath: string): MkDocsNavItem[] {
+ const content = fs.readFileSync(configPath, 'utf-8');
+ const config = yaml.load(content) as any;
+ return config.nav || [];
+}
+
+/**
+ * Flatten navigation structure, extract all chapter paths while preserving hierarchy
+ * Based on mkdocs.yml structure:
+ * - Parent titles (e.g., "Chapter 0 Preface") contain arrays of child items
+ * - Child items can be string paths (index.md) or objects (sub-chapters)
+ */
+export function flattenNav(nav: MkDocsNavItem[], basePath: string = ''): Chapter[] {
+ const chapters: Chapter[] = [];
+ let order = 0;
+
+ function traverse(items: MkDocsNavItem[], parentTitle: string = '', parentNumber: string = '', level: number = 0) {
+ for (const item of items) {
+ if (typeof item === 'string') {
+ // Simple path string (usually index.md, as chapter homepage)
+ const filePath = path.join(basePath, item);
+ if (fs.existsSync(filePath)) {
+ // Try to extract title from file content
+ const content = fs.readFileSync(filePath, 'utf-8');
+ const titleMatch = content.match(/^#\s+(.+)$/m);
+ const title = titleMatch ? titleMatch[1].trim() : path.basename(item, '.md');
+
+ // index.md uses parent chapter's title and number
+ chapters.push({
+ title: parentTitle || title, // If parent title exists, use it; otherwise use file title
+ path: filePath,
+ content: '',
+ order: order++,
+ level: level,
+ number: parentNumber || undefined,
+ parentTitle: undefined // index.md is top-level chapter
+ });
+ }
+ } else if (typeof item === 'object' && item !== null) {
+ // Handle object format: { "title": "path" } or { "title": [...] }
+ if (Array.isArray(item)) {
+ traverse(item, parentTitle, parentNumber, level);
+ } else {
+ const keys = Object.keys(item);
+ if (keys.length === 1) {
+ const key = keys[0];
+ const value = item[key];
+
+ if (typeof value === 'string') {
+ // { "title": "path" } format - this is a sub-chapter (e.g., "0.1 About this book": "path")
+ const filePath = path.join(basePath, value);
+ if (fs.existsSync(filePath)) {
+ const fullTitle = key.replace(/ /g, ' ').trim();
+
+ // Extract chapter number, e.g., "0.1 About this book" -> "0.1"
+ const numberMatch = fullTitle.match(/^(\d+(?:\.\d+)?)\s+/);
+ let chapterNumber = numberMatch ? numberMatch[1] : undefined;
+
+ // Extract title (remove number part)
+ const title = fullTitle.replace(/^\d+(?:\.\d+)?\s+/, '').trim();
+
+ chapters.push({
+ title: title,
+ path: filePath,
+ content: '',
+ order: order++,
+ level: level + 1, // Sub-chapter level +1
+ number: chapterNumber,
+ parentTitle: parentTitle || undefined
+ });
+ }
+ } else if (Array.isArray(value)) {
+ // { "title": [...] } format - this is parent chapter title and child items (e.g., "Chapter 0 Preface": [...])
+ const chapterTitle = key.replace(/ /g, ' ').trim();
+
+ // Extract chapter number from title, e.g., "Chapter 0 Preface" -> "0"
+ let chapterNumber = '';
+ const numberMatch = chapterTitle.match(/第\s*(\d+)\s*章/);
+ if (numberMatch) {
+ chapterNumber = numberMatch[1];
+ } else {
+ // If no number found, try to infer from first sub-chapter (e.g., infer "0" from "0.1")
+ for (const subItem of value) {
+ if (typeof subItem === 'string') {
+ continue;
+ } else if (typeof subItem === 'object' && subItem !== null && !Array.isArray(subItem)) {
+ const subObj = subItem as { [key: string]: string | MkDocsNavItem[] };
+ const subKeys = Object.keys(subObj);
+ if (subKeys.length === 1) {
+ const subKey = subKeys[0];
+ const subValue = subObj[subKey];
+ if (typeof subValue === 'string') {
+ const subTitle = subKey.replace(/ /g, ' ').trim();
+ const subNumberMatch = subTitle.match(/^(\d+)\.\d+/);
+ if (subNumberMatch) {
+ chapterNumber = subNumberMatch[1];
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Recursively process child items, maintain hierarchy
+ traverse(value, chapterTitle, chapterNumber, level);
+ }
+ } else if ('path' in item && typeof item.path === 'string') {
+ // Object with path property
+ const filePath = path.join(basePath, item.path);
+ if (fs.existsSync(filePath)) {
+ chapters.push({
+ title: (typeof item.title === 'string' ? item.title : undefined) || path.basename(item.path, '.md'),
+ path: filePath,
+ content: '',
+ order: order++,
+ level: level,
+ number: parentNumber || undefined,
+ parentTitle: parentTitle || undefined
+ });
+ }
+ } else if ('title' in item && 'children' in item && Array.isArray(item.children) && typeof item.title === 'string') {
+ // Object with title and children properties
+ traverse(item.children, item.title, parentNumber, level);
+ }
+ }
+ }
+ }
+ }
+
+ traverse(nav);
+
+ // Filter out chapters related to chapter_paperbook
+ return chapters.filter(chapter => {
+ // Check if path contains chapter_paperbook
+ return !chapter.path.includes('chapter_paperbook');
+ });
+}
+
+/**
+ * Read chapter content
+ */
+export function readChapterContent(chapter: Chapter): string {
+ try {
+ return fs.readFileSync(chapter.path, 'utf-8');
+ } catch (error) {
+ console.warn(`Unable to read file: ${chapter.path}`, error);
+ return '';
+ }
+}
+
diff --git a/epub/src/types.ts b/epub/src/types.ts
new file mode 100644
index 000000000..0fa8f4d2d
--- /dev/null
+++ b/epub/src/types.ts
@@ -0,0 +1,52 @@
+
+export interface NavItem {
+ title?: string;
+ path?: string;
+ children?: NavItem[];
+}
+
+// Navigation item type in MkDocs config file
+export type MkDocsNavItem = string | { [key: string]: string | MkDocsNavItem[] } | MkDocsNavItem[];
+
+export interface Chapter {
+ title: string;
+ path: string;
+ content: string;
+ order: number;
+ level: number; // Hierarchy level: 0=top-level chapter, 1=sub-chapter
+ number?: string; // Chapter number, e.g., "0", "0.1", "1", "1.1"
+ parentTitle?: string; // Parent chapter title
+}
+
+export interface ImageInfo {
+ src: string;
+ data: Buffer;
+ mimeType: string;
+}
+
+// Heading information
+export interface HeadingInfo {
+ level: number; // Heading level (1-6)
+ text: string; // Heading text
+ chapterPath: string; // Path to the chapter
+ lineNumber?: number; // Line number (if available)
+}
+
+// Option types for epub-gen library
+export interface EpubGenOptions {
+ title: string;
+ author: string;
+ publisher?: string;
+ description?: string;
+ language?: string;
+ content: Chapter[];
+ verbose?: boolean;
+ appendChapterTitles?: boolean;
+ customNcxTocTemplatePath?: string;
+ customHtmlTocTemplatePath?: string;
+ css?: string;
+ cover?: string;
+ output?: string;
+ fonts?: string[];
+ tocTitle?: string; // Table of contents title
+}
diff --git a/epub/src/validator.ts b/epub/src/validator.ts
new file mode 100644
index 000000000..6d5e924fa
--- /dev/null
+++ b/epub/src/validator.ts
@@ -0,0 +1,137 @@
+import * as fs from 'fs-extra';
+import * as path from 'path';
+import { HeadingInfo } from './types';
+const AdmZip = require('adm-zip');
+
+/**
+ * Validate if EPUB contains all headings
+ * @param epubPath EPUB file path
+ * @param expectedHeadings Expected heading list
+ * @returns Validation result
+ */
+export async function validateEpubHeadings(
+ epubPath: string,
+ expectedHeadings: HeadingInfo[]
+): Promise<{ success: boolean; missingHeadings: HeadingInfo[]; summary: string }> {
+
+ console.log(`\nStarting EPUB content validation...`);
+ console.log(`Expected heading count: ${expectedHeadings.length}`);
+
+ try {
+ // Extract EPUB
+ const zip = new AdmZip(epubPath);
+ const zipEntries = zip.getEntries();
+
+ // Extract all XHTML content
+ let allHtmlContent = '';
+ for (const entry of zipEntries) {
+ if (entry.entryName.endsWith('.xhtml') || entry.entryName.endsWith('.html')) {
+ const content = entry.getData().toString('utf8');
+ allHtmlContent += content + '\n';
+ }
+ }
+
+ // Check if each heading exists
+ const missingHeadings: HeadingInfo[] = [];
+ const foundHeadings: HeadingInfo[] = [];
+
+ for (const heading of expectedHeadings) {
+ const found = checkHeadingInHtml(allHtmlContent, heading);
+ if (found) {
+ foundHeadings.push(heading);
+ } else {
+ missingHeadings.push(heading);
+ }
+ }
+
+ // Generate report
+ const successRate = ((foundHeadings.length / expectedHeadings.length) * 100).toFixed(2);
+
+ let summary = `\n${'='.repeat(60)}\n`;
+ summary += `EPUB Content Validation Report\n`;
+ summary += `${'='.repeat(60)}\n`;
+ summary += `Total headings: ${expectedHeadings.length}\n`;
+ summary += `Found: ${foundHeadings.length}\n`;
+ summary += `Missing: ${missingHeadings.length}\n`;
+ summary += `Completeness rate: ${successRate}%\n`;
+ summary += `${'='.repeat(60)}\n`;
+
+ if (missingHeadings.length > 0) {
+ summary += `\n⚠️ Missing headings:\n`;
+ summary += `${'='.repeat(60)}\n`;
+
+ // Group by chapter
+ const byChapter = new Map';
+ for (const line of processedLines) {
+ html += '
';
+
+ return html;
+}
+
+/**
+ * Process math formula content (LaTeX to HTML)
+ */
+function processMathContent(latex: string): string {
+ let result = latex.trim();
+
+ // First process text and roman font (before processing superscripts/subscripts to avoid nested braces issue)
+ result = result.replace(/\\text\s*\{([^}]+)\}/g, '$1');
+ result = result.replace(/\\mathrm\s*\{([^}]+)\}/g, '$1');
+
+ // Process function names
+ result = result.replace(/\\log/g, 'log');
+ result = result.replace(/\\ln/g, 'ln');
+ result = result.replace(/\\sin/g, 'sin');
+ result = result.replace(/\\cos/g, 'cos');
+ result = result.replace(/\\tan/g, 'tan');
+
+ // Process subscripts
+ result = result.replace(/_\{([^}]+)\}/g, '$1');
+ result = result.replace(/_([a-zA-Z0-9])/g, '$1');
+
+ // Process superscripts
+ result = result.replace(/\^\{([^}]+)\}/g, '$1');
+ result = result.replace(/\^([a-zA-Z0-9])/g, '$1');
+
+ // Process fractions
+ result = result.replace(/\\frac\s*\{([^}]+)\}\s*\{([^}]+)\}/g, '$1⁄$2');
+
+ // Process square root
+ result = result.replace(/\\sqrt\s*\{([^}]+)\}/g, '√$1');
+
+ // Process Greek letters
+ const greekMap: { [key: string]: string } = {
+ '\\alpha': 'α', '\\beta': 'β', '\\gamma': 'γ', '\\delta': 'δ',
+ '\\epsilon': 'ε', '\\theta': 'θ', '\\lambda': 'λ', '\\mu': 'μ',
+ '\\pi': 'π', '\\sigma': 'σ', '\\tau': 'τ', '\\phi': 'φ',
+ '\\omega': 'ω', '\\Theta': 'Θ', '\\Omega': 'Ω'
+ };
+
+ for (const [tex, unicode] of Object.entries(greekMap)) {
+ result = result.replace(new RegExp(tex.replace(/\\/g, '\\\\'), 'g'), unicode);
+ }
+
+ // Process special symbols
+ result = result.replace(/\\times/g, '×');
+ result = result.replace(/\\div/g, '÷');
+ result = result.replace(/\\cdot/g, '·');
+ result = result.replace(/\\ast/g, '∗');
+ result = result.replace(/\\pm/g, '±');
+ result = result.replace(/\\mp/g, '∓');
+ result = result.replace(/\\leq/g, '≤');
+ result = result.replace(/\\geq/g, '≥');
+ result = result.replace(/\\neq/g, '≠');
+ result = result.replace(/\\ne/g, '≠');
+ result = result.replace(/\\approx/g, '≈');
+ result = result.replace(/\\equiv/g, '≡');
+ result = result.replace(/\\sim/g, '∼');
+ result = result.replace(/\\propto/g, '∝');
+ result = result.replace(/\\infty/g, '∞');
+ result = result.replace(/\\sum/g, '∑');
+ result = result.replace(/\\prod/g, '∏');
+ result = result.replace(/\\int/g, '∫');
+ result = result.replace(/\\dots/g, '...');
+ result = result.replace(/\\ldots/g, '…');
+ result = result.replace(/\\lfloor/g, '⌊');
+ result = result.replace(/\\rfloor/g, '⌋');
+ result = result.replace(/\\lceil/g, '⌈');
+ result = result.replace(/\\rceil/g, '⌉');
+ result = result.replace(/\\in/g, '∈');
+ result = result.replace(/\\notin/g, '∉');
+ result = result.replace(/\\subset/g, '⊂');
+ result = result.replace(/\\supset/g, '⊃');
+ result = result.replace(/\\subseteq/g, '⊆');
+ result = result.replace(/\\supseteq/g, '⊇');
+ result = result.replace(/\\cup/g, '∪');
+ result = result.replace(/\\cap/g, '∩');
+ result = result.replace(/\\emptyset/g, '∅');
+ result = result.replace(/\\forall/g, '∀');
+ result = result.replace(/\\exists/g, '∃');
+ result = result.replace(/\\land/g, '∧');
+ result = result.replace(/\\lor/g, '∨');
+ result = result.replace(/\\neg/g, '¬');
+
+ // Process space commands
+ result = result.replace(/\\quad/g, ' ');
+ result = result.replace(/\\qquad/g, ' ');
+ result = result.replace(/\\,/g, ' ');
+ result = result.replace(/\\;/g, ' ');
+
+ // Process arrow symbols
+ result = result.replace(/\\rightarrow/g, '→');
+ result = result.replace(/\\leftarrow/g, '←');
+ result = result.replace(/\\Rightarrow/g, '⇒');
+ result = result.replace(/\\Leftarrow/g, '⇐');
+ result = result.replace(/\\leftrightarrow/g, '↔');
+ result = result.replace(/\\Leftrightarrow/g, '⇔');
+ result = result.replace(/\\to/g, '→');
+ result = result.replace(/\\gets/g, '←');
+
+ // Process LaTeX bracket commands (remove \left and \right directly, keep brackets themselves)
+ result = result.replace(/\\left\s*/g, '');
+ result = result.replace(/\\right\s*/g, '');
+
+ // Process escaped braces (use placeholders to protect)
+ result = result.replace(/\\\{/g, 'LEFTBRACE');
+ result = result.replace(/\\\}/g, 'RIGHTBRACE');
+
+ // Clean brackets and backslashes
+ result = result.replace(/\{|\}/g, '');
+ result = result.replace(/\\/g, '');
+
+ // Restore escaped braces
+ result = result.replace(/LEFTBRACE/g, '{');
+ result = result.replace(/RIGHTBRACE/g, '}');
+
+ // Clean consecutive extra spaces (but preserve spaces inside HTML tags)
+ result = result.replace(/(?]*)\s{2,}(?![^<]*>)/g, ' ');
+
+ // No longer convert letters to italics, keep original letters
+
+ return result;
+}
+
+
+/**
+ * Process MkDocs admonition syntax
+ * Supports two formats:
+ * 1. !!! note (use default title)
+ * 2. !!! note "Custom title" (use custom title)
+ */
+function processAdmonitions(markdown: string, docLanguage?: string): { markdown: string; placeholders: Map';
+ for (let i = 0; i < line.length; i++) {
+ const cell = line[i] || '';
+ const align = i === 0 ? 'right' : 'left';
+ html += ` ';
+ }
+ html += '${cell} `;
+ }
+ html += '