From 69010394f392ca16904070e54d5a464ebeb1daf7 Mon Sep 17 00:00:00 2001 From: "Tommy D. Rossi" Date: Wed, 18 Jun 2025 12:04:00 +0200 Subject: [PATCH 01/61] feat(napi): add napi bindings and test --- Cargo.toml | 2 +- napi_binding/.gitignore | 3 + napi_binding/Cargo.toml | 15 ++ napi_binding/__tests__/parse.test.ts | 61 ++++++ napi_binding/index.d.ts | 6 + napi_binding/index.js | 315 +++++++++++++++++++++++++++ napi_binding/package.json | 12 + napi_binding/src/lib.rs | 12 + 8 files changed, 425 insertions(+), 1 deletion(-) create mode 100644 napi_binding/.gitignore create mode 100644 napi_binding/Cargo.toml create mode 100644 napi_binding/__tests__/parse.test.ts create mode 100644 napi_binding/index.d.ts create mode 100644 napi_binding/index.js create mode 100644 napi_binding/package.json create mode 100644 napi_binding/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 5462ac32..d6278d91 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ rust-version = "1.56" version = "1.0.0" [workspace] -members = ["generate", "mdast_util_to_markdown"] +members = ["generate", "mdast_util_to_markdown", "napi_binding"] [workspace.dependencies] pretty_assertions = "1" diff --git a/napi_binding/.gitignore b/napi_binding/.gitignore new file mode 100644 index 00000000..51b72278 --- /dev/null +++ b/napi_binding/.gitignore @@ -0,0 +1,3 @@ +node_modules +index.*.node +package-lock.json diff --git a/napi_binding/Cargo.toml b/napi_binding/Cargo.toml new file mode 100644 index 00000000..5660c7b3 --- /dev/null +++ b/napi_binding/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "markdown-napi" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +crate-type = ["cdylib"] + +[dependencies] +napi = { version = "2", features = ["napi4", "serde-json"] } +napi-derive = "2" +markdown = { path = "..", package = "markdown", version = "1.0.0", features = ["serde"] } +serde = { version = "1", features = ["derive"] } +serde_json = "1" diff --git a/napi_binding/__tests__/parse.test.ts b/napi_binding/__tests__/parse.test.ts new file mode 100644 index 00000000..bc6af170 --- /dev/null +++ b/napi_binding/__tests__/parse.test.ts @@ -0,0 +1,61 @@ +import { describe, it, expect } from 'vitest' +import { parse } from '../index' + +describe('parse', () => { + it('returns mdast', () => { + const ast = parse('# Hello') + expect(ast).toMatchInlineSnapshot(` + { + "children": [ + { + "children": [ + { + "position": { + "end": { + "column": 8, + "line": 1, + "offset": 7, + }, + "start": { + "column": 3, + "line": 1, + "offset": 2, + }, + }, + "type": "text", + "value": "Hello", + }, + ], + "depth": 1, + "position": { + "end": { + "column": 8, + "line": 1, + "offset": 7, + }, + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "heading", + }, + ], + "position": { + "end": { + "column": 8, + "line": 1, + "offset": 7, + }, + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "root", + } + `) + }) +}) diff --git a/napi_binding/index.d.ts b/napi_binding/index.d.ts new file mode 100644 index 00000000..3842ae8d --- /dev/null +++ b/napi_binding/index.d.ts @@ -0,0 +1,6 @@ +/* tslint:disable */ +/* eslint-disable */ + +/* auto-generated by NAPI-RS */ + +export declare function parse(input: string): any diff --git a/napi_binding/index.js b/napi_binding/index.js new file mode 100644 index 00000000..337b8d4d --- /dev/null +++ b/napi_binding/index.js @@ -0,0 +1,315 @@ +/* tslint:disable */ +/* eslint-disable */ +/* prettier-ignore */ + +/* auto-generated by NAPI-RS */ + +const { existsSync, readFileSync } = require('fs') +const { join } = require('path') + +const { platform, arch } = process + +let nativeBinding = null +let localFileExisted = false +let loadError = null + +function isMusl() { + // For Node 10 + if (!process.report || typeof process.report.getReport !== 'function') { + try { + const lddPath = require('child_process').execSync('which ldd').toString().trim() + return readFileSync(lddPath, 'utf8').includes('musl') + } catch (e) { + return true + } + } else { + const { glibcVersionRuntime } = process.report.getReport().header + return !glibcVersionRuntime + } +} + +switch (platform) { + case 'android': + switch (arch) { + case 'arm64': + localFileExisted = existsSync(join(__dirname, 'index.android-arm64.node')) + try { + if (localFileExisted) { + nativeBinding = require('./index.android-arm64.node') + } else { + nativeBinding = require('markdown-napi-android-arm64') + } + } catch (e) { + loadError = e + } + break + case 'arm': + localFileExisted = existsSync(join(__dirname, 'index.android-arm-eabi.node')) + try { + if (localFileExisted) { + nativeBinding = require('./index.android-arm-eabi.node') + } else { + nativeBinding = require('markdown-napi-android-arm-eabi') + } + } catch (e) { + loadError = e + } + break + default: + throw new Error(`Unsupported architecture on Android ${arch}`) + } + break + case 'win32': + switch (arch) { + case 'x64': + localFileExisted = existsSync( + join(__dirname, 'index.win32-x64-msvc.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./index.win32-x64-msvc.node') + } else { + nativeBinding = require('markdown-napi-win32-x64-msvc') + } + } catch (e) { + loadError = e + } + break + case 'ia32': + localFileExisted = existsSync( + join(__dirname, 'index.win32-ia32-msvc.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./index.win32-ia32-msvc.node') + } else { + nativeBinding = require('markdown-napi-win32-ia32-msvc') + } + } catch (e) { + loadError = e + } + break + case 'arm64': + localFileExisted = existsSync( + join(__dirname, 'index.win32-arm64-msvc.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./index.win32-arm64-msvc.node') + } else { + nativeBinding = require('markdown-napi-win32-arm64-msvc') + } + } catch (e) { + loadError = e + } + break + default: + throw new Error(`Unsupported architecture on Windows: ${arch}`) + } + break + case 'darwin': + localFileExisted = existsSync(join(__dirname, 'index.darwin-universal.node')) + try { + if (localFileExisted) { + nativeBinding = require('./index.darwin-universal.node') + } else { + nativeBinding = require('markdown-napi-darwin-universal') + } + break + } catch {} + switch (arch) { + case 'x64': + localFileExisted = existsSync(join(__dirname, 'index.darwin-x64.node')) + try { + if (localFileExisted) { + nativeBinding = require('./index.darwin-x64.node') + } else { + nativeBinding = require('markdown-napi-darwin-x64') + } + } catch (e) { + loadError = e + } + break + case 'arm64': + localFileExisted = existsSync( + join(__dirname, 'index.darwin-arm64.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./index.darwin-arm64.node') + } else { + nativeBinding = require('markdown-napi-darwin-arm64') + } + } catch (e) { + loadError = e + } + break + default: + throw new Error(`Unsupported architecture on macOS: ${arch}`) + } + break + case 'freebsd': + if (arch !== 'x64') { + throw new Error(`Unsupported architecture on FreeBSD: ${arch}`) + } + localFileExisted = existsSync(join(__dirname, 'index.freebsd-x64.node')) + try { + if (localFileExisted) { + nativeBinding = require('./index.freebsd-x64.node') + } else { + nativeBinding = require('markdown-napi-freebsd-x64') + } + } catch (e) { + loadError = e + } + break + case 'linux': + switch (arch) { + case 'x64': + if (isMusl()) { + localFileExisted = existsSync( + join(__dirname, 'index.linux-x64-musl.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./index.linux-x64-musl.node') + } else { + nativeBinding = require('markdown-napi-linux-x64-musl') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync( + join(__dirname, 'index.linux-x64-gnu.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./index.linux-x64-gnu.node') + } else { + nativeBinding = require('markdown-napi-linux-x64-gnu') + } + } catch (e) { + loadError = e + } + } + break + case 'arm64': + if (isMusl()) { + localFileExisted = existsSync( + join(__dirname, 'index.linux-arm64-musl.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./index.linux-arm64-musl.node') + } else { + nativeBinding = require('markdown-napi-linux-arm64-musl') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync( + join(__dirname, 'index.linux-arm64-gnu.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./index.linux-arm64-gnu.node') + } else { + nativeBinding = require('markdown-napi-linux-arm64-gnu') + } + } catch (e) { + loadError = e + } + } + break + case 'arm': + if (isMusl()) { + localFileExisted = existsSync( + join(__dirname, 'index.linux-arm-musleabihf.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./index.linux-arm-musleabihf.node') + } else { + nativeBinding = require('markdown-napi-linux-arm-musleabihf') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync( + join(__dirname, 'index.linux-arm-gnueabihf.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./index.linux-arm-gnueabihf.node') + } else { + nativeBinding = require('markdown-napi-linux-arm-gnueabihf') + } + } catch (e) { + loadError = e + } + } + break + case 'riscv64': + if (isMusl()) { + localFileExisted = existsSync( + join(__dirname, 'index.linux-riscv64-musl.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./index.linux-riscv64-musl.node') + } else { + nativeBinding = require('markdown-napi-linux-riscv64-musl') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync( + join(__dirname, 'index.linux-riscv64-gnu.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./index.linux-riscv64-gnu.node') + } else { + nativeBinding = require('markdown-napi-linux-riscv64-gnu') + } + } catch (e) { + loadError = e + } + } + break + case 's390x': + localFileExisted = existsSync( + join(__dirname, 'index.linux-s390x-gnu.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./index.linux-s390x-gnu.node') + } else { + nativeBinding = require('markdown-napi-linux-s390x-gnu') + } + } catch (e) { + loadError = e + } + break + default: + throw new Error(`Unsupported architecture on Linux: ${arch}`) + } + break + default: + throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`) +} + +if (!nativeBinding) { + if (loadError) { + throw loadError + } + throw new Error(`Failed to load native binding`) +} + +const { parse } = nativeBinding + +module.exports.parse = parse diff --git a/napi_binding/package.json b/napi_binding/package.json new file mode 100644 index 00000000..3764da03 --- /dev/null +++ b/napi_binding/package.json @@ -0,0 +1,12 @@ +{ + "name": "markdown-napi", + "version": "0.1.0", + "scripts": { + "build": "napi build --platform", + "test": "vitest run" + }, + "devDependencies": { + "@napi-rs/cli": "^2.16.1", + "vitest": "^1.5.0" + } +} diff --git a/napi_binding/src/lib.rs b/napi_binding/src/lib.rs new file mode 100644 index 00000000..b0de513f --- /dev/null +++ b/napi_binding/src/lib.rs @@ -0,0 +1,12 @@ +use markdown::{to_mdast, ParseOptions}; +use napi::{bindgen_prelude::*, Error}; +use napi_derive::napi; +use serde_json::Value; + +#[napi] +pub fn parse(input: String) -> Result { + let tree = to_mdast(&input, &ParseOptions::default()) + .map_err(|e| Error::from_reason(format!("{:?}", e)))?; + serde_json::to_value(&tree) + .map_err(|e| Error::from_reason(e.to_string())) +} From 9974eab73bfc43bac78224f2ee2ac14be73ad791 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 12:58:01 +0200 Subject: [PATCH 02/61] works on mac --- .gitignore | 1 + napi_binding/.cargo/config.toml | 5 + napi_binding/package.json | 4 +- napi_binding/pnpm-lock.yaml | 1059 +++++++++++++++++++++++++++++++ 4 files changed, 1068 insertions(+), 1 deletion(-) create mode 100644 napi_binding/.cargo/config.toml create mode 100644 napi_binding/pnpm-lock.yaml diff --git a/.gitignore b/.gitignore index 151575c5..925c098c 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ fuzz/corpus fuzz/artifacts fuzz/hfuzz_target fuzz/hfuzz_workspace +*.node diff --git a/napi_binding/.cargo/config.toml b/napi_binding/.cargo/config.toml new file mode 100644 index 00000000..9d0e3976 --- /dev/null +++ b/napi_binding/.cargo/config.toml @@ -0,0 +1,5 @@ +[target.x86_64-apple-darwin] +rustflags = ["-C", "link-args=-Wl,-undefined,dynamic_lookup"] + +[target.aarch64-apple-darwin] +rustflags = ["-C", "link-args=-Wl,-undefined,dynamic_lookup"] diff --git a/napi_binding/package.json b/napi_binding/package.json index 3764da03..ad046be3 100644 --- a/napi_binding/package.json +++ b/napi_binding/package.json @@ -2,7 +2,9 @@ "name": "markdown-napi", "version": "0.1.0", "scripts": { - "build": "napi build --platform", + "build": "pnpm run build:platform && pnpm run build:wasm", + "build:wasm": "napi build --release --target wasm32-wasip1-threads --no-const-enum", + "build:platform": "napi build --platform --release --no-const-enum", "test": "vitest run" }, "devDependencies": { diff --git a/napi_binding/pnpm-lock.yaml b/napi_binding/pnpm-lock.yaml new file mode 100644 index 00000000..dea6b6cf --- /dev/null +++ b/napi_binding/pnpm-lock.yaml @@ -0,0 +1,1059 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@napi-rs/cli': + specifier: ^2.16.1 + version: 2.18.4 + vitest: + specifier: ^1.5.0 + version: 1.6.1 + +packages: + + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@napi-rs/cli@2.18.4': + resolution: {integrity: sha512-SgJeA4df9DE2iAEpr3M2H0OKl/yjtg1BnRI5/JyowS71tUWhrfSu2LT0V3vlHET+g1hBVlrO60PmEXwUEKp8Mg==} + engines: {node: '>= 10'} + hasBin: true + + '@rollup/rollup-android-arm-eabi@4.43.0': + resolution: {integrity: sha512-Krjy9awJl6rKbruhQDgivNbD1WuLb8xAclM4IR4cN5pHGAs2oIMMQJEiC3IC/9TZJ+QZkmZhlMO/6MBGxPidpw==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.43.0': + resolution: {integrity: sha512-ss4YJwRt5I63454Rpj+mXCXicakdFmKnUNxr1dLK+5rv5FJgAxnN7s31a5VchRYxCFWdmnDWKd0wbAdTr0J5EA==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.43.0': + resolution: {integrity: sha512-eKoL8ykZ7zz8MjgBenEF2OoTNFAPFz1/lyJ5UmmFSz5jW+7XbH1+MAgCVHy72aG59rbuQLcJeiMrP8qP5d/N0A==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.43.0': + resolution: {integrity: sha512-SYwXJgaBYW33Wi/q4ubN+ldWC4DzQY62S4Ll2dgfr/dbPoF50dlQwEaEHSKrQdSjC6oIe1WgzosoaNoHCdNuMg==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.43.0': + resolution: {integrity: sha512-SV+U5sSo0yujrjzBF7/YidieK2iF6E7MdF6EbYxNz94lA+R0wKl3SiixGyG/9Klab6uNBIqsN7j4Y/Fya7wAjQ==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.43.0': + resolution: {integrity: sha512-J7uCsiV13L/VOeHJBo5SjasKiGxJ0g+nQTrBkAsmQBIdil3KhPnSE9GnRon4ejX1XDdsmK/l30IYLiAaQEO0Cg==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.43.0': + resolution: {integrity: sha512-gTJ/JnnjCMc15uwB10TTATBEhK9meBIY+gXP4s0sHD1zHOaIh4Dmy1X9wup18IiY9tTNk5gJc4yx9ctj/fjrIw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.43.0': + resolution: {integrity: sha512-ZJ3gZynL1LDSIvRfz0qXtTNs56n5DI2Mq+WACWZ7yGHFUEirHBRt7fyIk0NsCKhmRhn7WAcjgSkSVVxKlPNFFw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.43.0': + resolution: {integrity: sha512-8FnkipasmOOSSlfucGYEu58U8cxEdhziKjPD2FIa0ONVMxvl/hmONtX/7y4vGjdUhjcTHlKlDhw3H9t98fPvyA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.43.0': + resolution: {integrity: sha512-KPPyAdlcIZ6S9C3S2cndXDkV0Bb1OSMsX0Eelr2Bay4EsF9yi9u9uzc9RniK3mcUGCLhWY9oLr6er80P5DE6XA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loongarch64-gnu@4.43.0': + resolution: {integrity: sha512-HPGDIH0/ZzAZjvtlXj6g+KDQ9ZMHfSP553za7o2Odegb/BEfwJcR0Sw0RLNpQ9nC6Gy8s+3mSS9xjZ0n3rhcYg==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.43.0': + resolution: {integrity: sha512-gEmwbOws4U4GLAJDhhtSPWPXUzDfMRedT3hFMyRAvM9Mrnj+dJIFIeL7otsv2WF3D7GrV0GIewW0y28dOYWkmw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.43.0': + resolution: {integrity: sha512-XXKvo2e+wFtXZF/9xoWohHg+MuRnvO29TI5Hqe9xwN5uN8NKUYy7tXUG3EZAlfchufNCTHNGjEx7uN78KsBo0g==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.43.0': + resolution: {integrity: sha512-ruf3hPWhjw6uDFsOAzmbNIvlXFXlBQ4nk57Sec8E8rUxs/AI4HD6xmiiasOOx/3QxS2f5eQMKTAwk7KHwpzr/Q==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.43.0': + resolution: {integrity: sha512-QmNIAqDiEMEvFV15rsSnjoSmO0+eJLoKRD9EAa9rrYNwO/XRCtOGM3A5A0X+wmG+XRrw9Fxdsw+LnyYiZWWcVw==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.43.0': + resolution: {integrity: sha512-jAHr/S0iiBtFyzjhOkAics/2SrXE092qyqEg96e90L3t9Op8OTzS6+IX0Fy5wCt2+KqeHAkti+eitV0wvblEoQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.43.0': + resolution: {integrity: sha512-3yATWgdeXyuHtBhrLt98w+5fKurdqvs8B53LaoKD7P7H7FKOONLsBVMNl9ghPQZQuYcceV5CDyPfyfGpMWD9mQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.43.0': + resolution: {integrity: sha512-wVzXp2qDSCOpcBCT5WRWLmpJRIzv23valvcTwMHEobkjippNf+C3ys/+wf07poPkeNix0paTNemB2XrHr2TnGw==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.43.0': + resolution: {integrity: sha512-fYCTEyzf8d+7diCw8b+asvWDCLMjsCEA8alvtAutqJOJp/wL5hs1rWSqJ1vkjgW0L2NB4bsYJrpKkiIPRR9dvw==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.43.0': + resolution: {integrity: sha512-SnGhLiE5rlK0ofq8kzuDkM0g7FN1s5VYY+YSMTibP7CqShxCQvqtNxTARS4xX4PFJfHjG0ZQYX9iGzI3FQh5Aw==} + cpu: [x64] + os: [win32] + + '@sinclair/typebox@0.27.8': + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + + '@types/estree@1.0.7': + resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@vitest/expect@1.6.1': + resolution: {integrity: sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==} + + '@vitest/runner@1.6.1': + resolution: {integrity: sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==} + + '@vitest/snapshot@1.6.1': + resolution: {integrity: sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ==} + + '@vitest/spy@1.6.1': + resolution: {integrity: sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw==} + + '@vitest/utils@1.6.1': + resolution: {integrity: sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==} + + acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + engines: {node: '>=0.4.0'} + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + assertion-error@1.1.0: + resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + chai@4.5.0: + resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} + engines: {node: '>=4'} + + check-error@1.0.3: + resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-eql@4.1.4: + resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} + engines: {node: '>=6'} + + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + get-func-name@2.0.2: + resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} + + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + + local-pkg@0.5.1: + resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==} + engines: {node: '>=14'} + + loupe@2.3.7: + resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} + + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + + mlly@1.7.4: + resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + + p-limit@5.0.0: + resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} + engines: {node: '>=18'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pathval@1.1.1: + resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + rollup@4.43.0: + resolution: {integrity: sha512-wdN2Kd3Twh8MAEOEJZsuxuLKCsBEo4PVNLK6tQWAn10VhsVewQLzcucMgLolRlhFybGxfclbPeEYBaP6RvUFGg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@3.9.0: + resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} + + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + strip-literal@2.1.1: + resolution: {integrity: sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinypool@0.8.4: + resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==} + engines: {node: '>=14.0.0'} + + tinyspy@2.2.1: + resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==} + engines: {node: '>=14.0.0'} + + type-detect@4.1.0: + resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} + engines: {node: '>=4'} + + ufo@1.6.1: + resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + + vite-node@1.6.1: + resolution: {integrity: sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + + vite@5.4.19: + resolution: {integrity: sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vitest@1.6.1: + resolution: {integrity: sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 1.6.1 + '@vitest/ui': 1.6.1 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + yocto-queue@1.2.1: + resolution: {integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==} + engines: {node: '>=12.20'} + +snapshots: + + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.8 + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@napi-rs/cli@2.18.4': {} + + '@rollup/rollup-android-arm-eabi@4.43.0': + optional: true + + '@rollup/rollup-android-arm64@4.43.0': + optional: true + + '@rollup/rollup-darwin-arm64@4.43.0': + optional: true + + '@rollup/rollup-darwin-x64@4.43.0': + optional: true + + '@rollup/rollup-freebsd-arm64@4.43.0': + optional: true + + '@rollup/rollup-freebsd-x64@4.43.0': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.43.0': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.43.0': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.43.0': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.43.0': + optional: true + + '@rollup/rollup-linux-loongarch64-gnu@4.43.0': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.43.0': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.43.0': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.43.0': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.43.0': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.43.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.43.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.43.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.43.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.43.0': + optional: true + + '@sinclair/typebox@0.27.8': {} + + '@types/estree@1.0.7': {} + + '@types/estree@1.0.8': {} + + '@vitest/expect@1.6.1': + dependencies: + '@vitest/spy': 1.6.1 + '@vitest/utils': 1.6.1 + chai: 4.5.0 + + '@vitest/runner@1.6.1': + dependencies: + '@vitest/utils': 1.6.1 + p-limit: 5.0.0 + pathe: 1.1.2 + + '@vitest/snapshot@1.6.1': + dependencies: + magic-string: 0.30.17 + pathe: 1.1.2 + pretty-format: 29.7.0 + + '@vitest/spy@1.6.1': + dependencies: + tinyspy: 2.2.1 + + '@vitest/utils@1.6.1': + dependencies: + diff-sequences: 29.6.3 + estree-walker: 3.0.3 + loupe: 2.3.7 + pretty-format: 29.7.0 + + acorn-walk@8.3.4: + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + ansi-styles@5.2.0: {} + + assertion-error@1.1.0: {} + + cac@6.7.14: {} + + chai@4.5.0: + dependencies: + assertion-error: 1.1.0 + check-error: 1.0.3 + deep-eql: 4.1.4 + get-func-name: 2.0.2 + loupe: 2.3.7 + pathval: 1.1.1 + type-detect: 4.1.0 + + check-error@1.0.3: + dependencies: + get-func-name: 2.0.2 + + confbox@0.1.8: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + debug@4.4.1: + dependencies: + ms: 2.1.3 + + deep-eql@4.1.4: + dependencies: + type-detect: 4.1.0 + + diff-sequences@29.6.3: {} + + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + execa@8.0.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + + fsevents@2.3.3: + optional: true + + get-func-name@2.0.2: {} + + get-stream@8.0.1: {} + + human-signals@5.0.0: {} + + is-stream@3.0.0: {} + + isexe@2.0.0: {} + + js-tokens@9.0.1: {} + + local-pkg@0.5.1: + dependencies: + mlly: 1.7.4 + pkg-types: 1.3.1 + + loupe@2.3.7: + dependencies: + get-func-name: 2.0.2 + + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + merge-stream@2.0.0: {} + + mimic-fn@4.0.0: {} + + mlly@1.7.4: + dependencies: + acorn: 8.15.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.1 + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + + p-limit@5.0.0: + dependencies: + yocto-queue: 1.2.1 + + path-key@3.1.1: {} + + path-key@4.0.0: {} + + pathe@1.1.2: {} + + pathe@2.0.3: {} + + pathval@1.1.1: {} + + picocolors@1.1.1: {} + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.7.4 + pathe: 2.0.3 + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + react-is@18.3.1: {} + + rollup@4.43.0: + dependencies: + '@types/estree': 1.0.7 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.43.0 + '@rollup/rollup-android-arm64': 4.43.0 + '@rollup/rollup-darwin-arm64': 4.43.0 + '@rollup/rollup-darwin-x64': 4.43.0 + '@rollup/rollup-freebsd-arm64': 4.43.0 + '@rollup/rollup-freebsd-x64': 4.43.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.43.0 + '@rollup/rollup-linux-arm-musleabihf': 4.43.0 + '@rollup/rollup-linux-arm64-gnu': 4.43.0 + '@rollup/rollup-linux-arm64-musl': 4.43.0 + '@rollup/rollup-linux-loongarch64-gnu': 4.43.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.43.0 + '@rollup/rollup-linux-riscv64-gnu': 4.43.0 + '@rollup/rollup-linux-riscv64-musl': 4.43.0 + '@rollup/rollup-linux-s390x-gnu': 4.43.0 + '@rollup/rollup-linux-x64-gnu': 4.43.0 + '@rollup/rollup-linux-x64-musl': 4.43.0 + '@rollup/rollup-win32-arm64-msvc': 4.43.0 + '@rollup/rollup-win32-ia32-msvc': 4.43.0 + '@rollup/rollup-win32-x64-msvc': 4.43.0 + fsevents: 2.3.3 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + siginfo@2.0.0: {} + + signal-exit@4.1.0: {} + + source-map-js@1.2.1: {} + + stackback@0.0.2: {} + + std-env@3.9.0: {} + + strip-final-newline@3.0.0: {} + + strip-literal@2.1.1: + dependencies: + js-tokens: 9.0.1 + + tinybench@2.9.0: {} + + tinypool@0.8.4: {} + + tinyspy@2.2.1: {} + + type-detect@4.1.0: {} + + ufo@1.6.1: {} + + vite-node@1.6.1: + dependencies: + cac: 6.7.14 + debug: 4.4.1 + pathe: 1.1.2 + picocolors: 1.1.1 + vite: 5.4.19 + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + vite@5.4.19: + dependencies: + esbuild: 0.21.5 + postcss: 8.5.6 + rollup: 4.43.0 + optionalDependencies: + fsevents: 2.3.3 + + vitest@1.6.1: + dependencies: + '@vitest/expect': 1.6.1 + '@vitest/runner': 1.6.1 + '@vitest/snapshot': 1.6.1 + '@vitest/spy': 1.6.1 + '@vitest/utils': 1.6.1 + acorn-walk: 8.3.4 + chai: 4.5.0 + debug: 4.4.1 + execa: 8.0.1 + local-pkg: 0.5.1 + magic-string: 0.30.17 + pathe: 1.1.2 + picocolors: 1.1.1 + std-env: 3.9.0 + strip-literal: 2.1.1 + tinybench: 2.9.0 + tinypool: 0.8.4 + vite: 5.4.19 + vite-node: 1.6.1 + why-is-node-running: 2.3.0 + transitivePeerDependencies: + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + yocto-queue@1.2.1: {} From da4c5d25bbd0ee719af809db4b7bf24488c34b22 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 13:43:46 +0200 Subject: [PATCH 03/61] adding mdx support --- .gitignore | 1 + napi_binding/.gitignore | 1 + napi_binding/Cargo.toml | 11 +- napi_binding/__tests__/parse.test.ts | 148 +++- napi_binding/index.d.ts | 7 +- napi_binding/index.js | 315 ------- napi_binding/package.json | 30 +- napi_binding/pnpm-lock.yaml | 1157 +++++++++++++++++++++++++- napi_binding/src/lib.rs | 10 +- 9 files changed, 1328 insertions(+), 352 deletions(-) delete mode 100644 napi_binding/index.js diff --git a/.gitignore b/.gitignore index 925c098c..8ab37ea0 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ fuzz/artifacts fuzz/hfuzz_target fuzz/hfuzz_workspace *.node +*.wasm diff --git a/napi_binding/.gitignore b/napi_binding/.gitignore index 51b72278..8fc295e3 100644 --- a/napi_binding/.gitignore +++ b/napi_binding/.gitignore @@ -1,3 +1,4 @@ node_modules index.*.node package-lock.json +out diff --git a/napi_binding/Cargo.toml b/napi_binding/Cargo.toml index 5660c7b3..1c99bf57 100644 --- a/napi_binding/Cargo.toml +++ b/napi_binding/Cargo.toml @@ -5,11 +5,16 @@ edition = "2021" publish = false [lib] -crate-type = ["cdylib"] +crate-type = ["cdylib", "lib"] + [dependencies] -napi = { version = "2", features = ["napi4", "serde-json"] } -napi-derive = "2" +napi = { version = "3.0.0-beta.8", default-features = false, features = ["napi3", "serde-json"] } +napi-derive = { version = "3.0.0-beta.8" } markdown = { path = "..", package = "markdown", version = "1.0.0", features = ["serde"] } serde = { version = "1", features = ["derive"] } serde_json = "1" + + +[build-dependencies] +napi-build = "2.2.1" diff --git a/napi_binding/__tests__/parse.test.ts b/napi_binding/__tests__/parse.test.ts index bc6af170..aa61ac2f 100644 --- a/napi_binding/__tests__/parse.test.ts +++ b/napi_binding/__tests__/parse.test.ts @@ -1,9 +1,20 @@ -import { describe, it, expect } from 'vitest' -import { parse } from '../index' +import { describe, it, expect } from "vitest"; +import { parse, parseMdx } from "../out/index.wasi.cjs"; -describe('parse', () => { - it('returns mdast', () => { - const ast = parse('# Hello') +describe("parse mdx", () => { + it("returns mdast", () => { + const ast = parseMdx(` +# Hello + +this is a paragraph + +here is some mdx + + +this is a callout + + + `); expect(ast).toMatchInlineSnapshot(` { "children": [ @@ -13,13 +24,13 @@ describe('parse', () => { "position": { "end": { "column": 8, - "line": 1, - "offset": 7, + "line": 2, + "offset": 8, }, "start": { "column": 3, - "line": 1, - "offset": 2, + "line": 2, + "offset": 3, }, }, "type": "text", @@ -30,23 +41,122 @@ describe('parse', () => { "position": { "end": { "column": 8, - "line": 1, - "offset": 7, + "line": 2, + "offset": 8, }, "start": { "column": 1, - "line": 1, - "offset": 0, + "line": 2, + "offset": 1, }, }, "type": "heading", }, + { + "children": [ + { + "position": { + "end": { + "column": 20, + "line": 4, + "offset": 29, + }, + "start": { + "column": 1, + "line": 4, + "offset": 10, + }, + }, + "type": "text", + "value": "this is a paragraph", + }, + ], + "position": { + "end": { + "column": 20, + "line": 4, + "offset": 29, + }, + "start": { + "column": 1, + "line": 4, + "offset": 10, + }, + }, + "type": "paragraph", + }, + { + "children": [ + { + "position": { + "end": { + "column": 17, + "line": 6, + "offset": 47, + }, + "start": { + "column": 1, + "line": 6, + "offset": 31, + }, + }, + "type": "text", + "value": "here is some mdx", + }, + ], + "position": { + "end": { + "column": 17, + "line": 6, + "offset": 47, + }, + "start": { + "column": 1, + "line": 6, + "offset": 31, + }, + }, + "type": "paragraph", + }, + { + "position": { + "end": { + "column": 18, + "line": 9, + "offset": 76, + }, + "start": { + "column": 1, + "line": 8, + "offset": 49, + }, + }, + "type": "html", + "value": " + this is a callout", + }, + { + "position": { + "end": { + "column": 11, + "line": 11, + "offset": 88, + }, + "start": { + "column": 1, + "line": 11, + "offset": 78, + }, + }, + "type": "html", + "value": "", + }, ], "position": { "end": { - "column": 8, - "line": 1, - "offset": 7, + "column": 5, + "line": 12, + "offset": 93, }, "start": { "column": 1, @@ -56,6 +166,6 @@ describe('parse', () => { }, "type": "root", } - `) - }) -}) + `); + }); +}); diff --git a/napi_binding/index.d.ts b/napi_binding/index.d.ts index 3842ae8d..6038653a 100644 --- a/napi_binding/index.d.ts +++ b/napi_binding/index.d.ts @@ -1,6 +1,5 @@ -/* tslint:disable */ -/* eslint-disable */ - /* auto-generated by NAPI-RS */ - +/* eslint-disable */ export declare function parse(input: string): any + +export declare function parseMdx(mdx: string): any diff --git a/napi_binding/index.js b/napi_binding/index.js deleted file mode 100644 index 337b8d4d..00000000 --- a/napi_binding/index.js +++ /dev/null @@ -1,315 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -/* prettier-ignore */ - -/* auto-generated by NAPI-RS */ - -const { existsSync, readFileSync } = require('fs') -const { join } = require('path') - -const { platform, arch } = process - -let nativeBinding = null -let localFileExisted = false -let loadError = null - -function isMusl() { - // For Node 10 - if (!process.report || typeof process.report.getReport !== 'function') { - try { - const lddPath = require('child_process').execSync('which ldd').toString().trim() - return readFileSync(lddPath, 'utf8').includes('musl') - } catch (e) { - return true - } - } else { - const { glibcVersionRuntime } = process.report.getReport().header - return !glibcVersionRuntime - } -} - -switch (platform) { - case 'android': - switch (arch) { - case 'arm64': - localFileExisted = existsSync(join(__dirname, 'index.android-arm64.node')) - try { - if (localFileExisted) { - nativeBinding = require('./index.android-arm64.node') - } else { - nativeBinding = require('markdown-napi-android-arm64') - } - } catch (e) { - loadError = e - } - break - case 'arm': - localFileExisted = existsSync(join(__dirname, 'index.android-arm-eabi.node')) - try { - if (localFileExisted) { - nativeBinding = require('./index.android-arm-eabi.node') - } else { - nativeBinding = require('markdown-napi-android-arm-eabi') - } - } catch (e) { - loadError = e - } - break - default: - throw new Error(`Unsupported architecture on Android ${arch}`) - } - break - case 'win32': - switch (arch) { - case 'x64': - localFileExisted = existsSync( - join(__dirname, 'index.win32-x64-msvc.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./index.win32-x64-msvc.node') - } else { - nativeBinding = require('markdown-napi-win32-x64-msvc') - } - } catch (e) { - loadError = e - } - break - case 'ia32': - localFileExisted = existsSync( - join(__dirname, 'index.win32-ia32-msvc.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./index.win32-ia32-msvc.node') - } else { - nativeBinding = require('markdown-napi-win32-ia32-msvc') - } - } catch (e) { - loadError = e - } - break - case 'arm64': - localFileExisted = existsSync( - join(__dirname, 'index.win32-arm64-msvc.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./index.win32-arm64-msvc.node') - } else { - nativeBinding = require('markdown-napi-win32-arm64-msvc') - } - } catch (e) { - loadError = e - } - break - default: - throw new Error(`Unsupported architecture on Windows: ${arch}`) - } - break - case 'darwin': - localFileExisted = existsSync(join(__dirname, 'index.darwin-universal.node')) - try { - if (localFileExisted) { - nativeBinding = require('./index.darwin-universal.node') - } else { - nativeBinding = require('markdown-napi-darwin-universal') - } - break - } catch {} - switch (arch) { - case 'x64': - localFileExisted = existsSync(join(__dirname, 'index.darwin-x64.node')) - try { - if (localFileExisted) { - nativeBinding = require('./index.darwin-x64.node') - } else { - nativeBinding = require('markdown-napi-darwin-x64') - } - } catch (e) { - loadError = e - } - break - case 'arm64': - localFileExisted = existsSync( - join(__dirname, 'index.darwin-arm64.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./index.darwin-arm64.node') - } else { - nativeBinding = require('markdown-napi-darwin-arm64') - } - } catch (e) { - loadError = e - } - break - default: - throw new Error(`Unsupported architecture on macOS: ${arch}`) - } - break - case 'freebsd': - if (arch !== 'x64') { - throw new Error(`Unsupported architecture on FreeBSD: ${arch}`) - } - localFileExisted = existsSync(join(__dirname, 'index.freebsd-x64.node')) - try { - if (localFileExisted) { - nativeBinding = require('./index.freebsd-x64.node') - } else { - nativeBinding = require('markdown-napi-freebsd-x64') - } - } catch (e) { - loadError = e - } - break - case 'linux': - switch (arch) { - case 'x64': - if (isMusl()) { - localFileExisted = existsSync( - join(__dirname, 'index.linux-x64-musl.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./index.linux-x64-musl.node') - } else { - nativeBinding = require('markdown-napi-linux-x64-musl') - } - } catch (e) { - loadError = e - } - } else { - localFileExisted = existsSync( - join(__dirname, 'index.linux-x64-gnu.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./index.linux-x64-gnu.node') - } else { - nativeBinding = require('markdown-napi-linux-x64-gnu') - } - } catch (e) { - loadError = e - } - } - break - case 'arm64': - if (isMusl()) { - localFileExisted = existsSync( - join(__dirname, 'index.linux-arm64-musl.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./index.linux-arm64-musl.node') - } else { - nativeBinding = require('markdown-napi-linux-arm64-musl') - } - } catch (e) { - loadError = e - } - } else { - localFileExisted = existsSync( - join(__dirname, 'index.linux-arm64-gnu.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./index.linux-arm64-gnu.node') - } else { - nativeBinding = require('markdown-napi-linux-arm64-gnu') - } - } catch (e) { - loadError = e - } - } - break - case 'arm': - if (isMusl()) { - localFileExisted = existsSync( - join(__dirname, 'index.linux-arm-musleabihf.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./index.linux-arm-musleabihf.node') - } else { - nativeBinding = require('markdown-napi-linux-arm-musleabihf') - } - } catch (e) { - loadError = e - } - } else { - localFileExisted = existsSync( - join(__dirname, 'index.linux-arm-gnueabihf.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./index.linux-arm-gnueabihf.node') - } else { - nativeBinding = require('markdown-napi-linux-arm-gnueabihf') - } - } catch (e) { - loadError = e - } - } - break - case 'riscv64': - if (isMusl()) { - localFileExisted = existsSync( - join(__dirname, 'index.linux-riscv64-musl.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./index.linux-riscv64-musl.node') - } else { - nativeBinding = require('markdown-napi-linux-riscv64-musl') - } - } catch (e) { - loadError = e - } - } else { - localFileExisted = existsSync( - join(__dirname, 'index.linux-riscv64-gnu.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./index.linux-riscv64-gnu.node') - } else { - nativeBinding = require('markdown-napi-linux-riscv64-gnu') - } - } catch (e) { - loadError = e - } - } - break - case 's390x': - localFileExisted = existsSync( - join(__dirname, 'index.linux-s390x-gnu.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./index.linux-s390x-gnu.node') - } else { - nativeBinding = require('markdown-napi-linux-s390x-gnu') - } - } catch (e) { - loadError = e - } - break - default: - throw new Error(`Unsupported architecture on Linux: ${arch}`) - } - break - default: - throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`) -} - -if (!nativeBinding) { - if (loadError) { - throw loadError - } - throw new Error(`Failed to load native binding`) -} - -const { parse } = nativeBinding - -module.exports.parse = parse diff --git a/napi_binding/package.json b/napi_binding/package.json index ad046be3..4017f25e 100644 --- a/napi_binding/package.json +++ b/napi_binding/package.json @@ -2,13 +2,37 @@ "name": "markdown-napi", "version": "0.1.0", "scripts": { - "build": "pnpm run build:platform && pnpm run build:wasm", + "build": "rm -rf out && pnpm napi build --release -o out", "build:wasm": "napi build --release --target wasm32-wasip1-threads --no-const-enum", "build:platform": "napi build --platform --release --no-const-enum", - "test": "vitest run" + "test": "vitest" + }, + "napi": { + + "targets": [ + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-linux-musl", + "x86_64-unknown-freebsd", + "i686-pc-windows-msvc", + "armv7-unknown-linux-gnueabihf", + "aarch64-unknown-linux-gnu", + "aarch64-apple-darwin", + "aarch64-unknown-linux-musl", + "aarch64-pc-windows-msvc", + "wasm32-wasip1-threads" + ], + "wasm": { + "initialMemory": 16384 + } }, "devDependencies": { - "@napi-rs/cli": "^2.16.1", + "@emnapi/runtime": "^1.4.3", + "@napi-rs/wasm-runtime": "^0.2.7", + + "@napi-rs/cli": "3.0.0-alpha.89", + "emnapi": "^1.4.3", "vitest": "^1.5.0" } } diff --git a/napi_binding/pnpm-lock.yaml b/napi_binding/pnpm-lock.yaml index dea6b6cf..2df363d0 100644 --- a/napi_binding/pnpm-lock.yaml +++ b/napi_binding/pnpm-lock.yaml @@ -8,15 +8,33 @@ importers: .: devDependencies: + '@emnapi/runtime': + specifier: ^1.4.3 + version: 1.4.3 '@napi-rs/cli': - specifier: ^2.16.1 - version: 2.18.4 + specifier: 3.0.0-alpha.89 + version: 3.0.0-alpha.89(@emnapi/runtime@1.4.3)(emnapi@1.4.3) + '@napi-rs/wasm-runtime': + specifier: ^0.2.7 + version: 0.2.11 + emnapi: + specifier: ^1.4.3 + version: 1.4.3 vitest: specifier: ^1.5.0 version: 1.6.1 packages: + '@emnapi/core@1.4.3': + resolution: {integrity: sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==} + + '@emnapi/runtime@1.4.3': + resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} + + '@emnapi/wasi-threads@1.0.2': + resolution: {integrity: sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==} + '@esbuild/aix-ppc64@0.21.5': resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} engines: {node: '>=12'} @@ -155,6 +173,127 @@ packages: cpu: [x64] os: [win32] + '@inquirer/checkbox@4.1.8': + resolution: {integrity: sha512-d/QAsnwuHX2OPolxvYcgSj7A9DO9H6gVOy2DvBTx+P2LH2iRTo/RSGV3iwCzW024nP9hw98KIuDmdyhZQj1UQg==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/confirm@5.1.12': + resolution: {integrity: sha512-dpq+ielV9/bqgXRUbNH//KsY6WEw9DrGPmipkpmgC1Y46cwuBTNx7PXFWTjc3MQ+urcc0QxoVHcMI0FW4Ok0hg==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/core@10.1.13': + resolution: {integrity: sha512-1viSxebkYN2nJULlzCxES6G9/stgHSepZ9LqqfdIGPHj5OHhiBUXVS0a6R0bEC2A+VL4D9w6QB66ebCr6HGllA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/editor@4.2.13': + resolution: {integrity: sha512-WbicD9SUQt/K8O5Vyk9iC2ojq5RHoCLK6itpp2fHsWe44VxxcA9z3GTWlvjSTGmMQpZr+lbVmrxdHcumJoLbMA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/expand@4.0.15': + resolution: {integrity: sha512-4Y+pbr/U9Qcvf+N/goHzPEXiHH8680lM3Dr3Y9h9FFw4gHS+zVpbj8LfbKWIb/jayIB4aSO4pWiBTrBYWkvi5A==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/figures@1.0.12': + resolution: {integrity: sha512-MJttijd8rMFcKJC8NYmprWr6hD3r9Gd9qUC0XwPNwoEPWSMVJwA2MlXxF+nhZZNMY+HXsWa+o7KY2emWYIn0jQ==} + engines: {node: '>=18'} + + '@inquirer/input@4.1.12': + resolution: {integrity: sha512-xJ6PFZpDjC+tC1P8ImGprgcsrzQRsUh9aH3IZixm1lAZFK49UGHxM3ltFfuInN2kPYNfyoPRh+tU4ftsjPLKqQ==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/number@3.0.15': + resolution: {integrity: sha512-xWg+iYfqdhRiM55MvqiTCleHzszpoigUpN5+t1OMcRkJrUrw7va3AzXaxvS+Ak7Gny0j2mFSTv2JJj8sMtbV2g==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/password@4.0.15': + resolution: {integrity: sha512-75CT2p43DGEnfGTaqFpbDC2p2EEMrq0S+IRrf9iJvYreMy5mAWj087+mdKyLHapUEPLjN10mNvABpGbk8Wdraw==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/prompts@7.5.3': + resolution: {integrity: sha512-8YL0WiV7J86hVAxrh3fE5mDCzcTDe1670unmJRz6ArDgN+DBK1a0+rbnNWp4DUB5rPMwqD5ZP6YHl9KK1mbZRg==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/rawlist@4.1.3': + resolution: {integrity: sha512-7XrV//6kwYumNDSsvJIPeAqa8+p7GJh7H5kRuxirct2cgOcSWwwNGoXDRgpNFbY/MG2vQ4ccIWCi8+IXXyFMZA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/search@3.0.15': + resolution: {integrity: sha512-YBMwPxYBrADqyvP4nNItpwkBnGGglAvCLVW8u4pRmmvOsHUtCAUIMbUrLX5B3tFL1/WsLGdQ2HNzkqswMs5Uaw==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/select@4.2.3': + resolution: {integrity: sha512-OAGhXU0Cvh0PhLz9xTF/kx6g6x+sP+PcyTiLvCrewI99P3BBeexD+VbuwkNDvqGkk3y2h5ZiWLeRP7BFlhkUDg==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/type@3.0.7': + resolution: {integrity: sha512-PfunHQcjwnju84L+ycmcMKB/pTPIngjUJvfnRhKY6FKPuYXlM4aQCb/nIdTFR6BEhMjFvngzvng/vBAJMZpLSA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + '@jest/schemas@29.6.3': resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -162,10 +301,381 @@ packages: '@jridgewell/sourcemap-codec@1.5.0': resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} - '@napi-rs/cli@2.18.4': - resolution: {integrity: sha512-SgJeA4df9DE2iAEpr3M2H0OKl/yjtg1BnRI5/JyowS71tUWhrfSu2LT0V3vlHET+g1hBVlrO60PmEXwUEKp8Mg==} - engines: {node: '>= 10'} + '@napi-rs/cli@3.0.0-alpha.89': + resolution: {integrity: sha512-Xi/B/unPVZJx12Qmj9+Z3+vfgmGdhp2tjtvH1VFjC6VrToh/i1fOBSv77j9WhYYWayFGhIit7nLcxQWxigXr8A==} + engines: {node: '>= 16'} hasBin: true + peerDependencies: + '@emnapi/runtime': ^1.1.0 + emnapi: ^1.1.0 + peerDependenciesMeta: + '@emnapi/runtime': + optional: true + emnapi: + optional: true + + '@napi-rs/cross-toolchain@0.0.19': + resolution: {integrity: sha512-StHXqYANdTaMFqJJ3JXHqKQMylOzOJPcrOCd9Nt2NIGfvfaXK3SzpmNfkJimkOAYfTsfpfuRERsML0bUZCpHBQ==} + peerDependencies: + '@napi-rs/cross-toolchain-arm64-target-aarch64': ^0.0.19 + '@napi-rs/cross-toolchain-arm64-target-armv7': ^0.0.19 + '@napi-rs/cross-toolchain-arm64-target-x86_64': ^0.0.19 + '@napi-rs/cross-toolchain-x64-target-aarch64': ^0.0.19 + '@napi-rs/cross-toolchain-x64-target-armv7': ^0.0.19 + '@napi-rs/cross-toolchain-x64-target-x86_64': ^0.0.19 + peerDependenciesMeta: + '@napi-rs/cross-toolchain-arm64-target-aarch64': + optional: true + '@napi-rs/cross-toolchain-arm64-target-armv7': + optional: true + '@napi-rs/cross-toolchain-arm64-target-x86_64': + optional: true + '@napi-rs/cross-toolchain-x64-target-aarch64': + optional: true + '@napi-rs/cross-toolchain-x64-target-armv7': + optional: true + '@napi-rs/cross-toolchain-x64-target-x86_64': + optional: true + + '@napi-rs/lzma-android-arm-eabi@1.4.3': + resolution: {integrity: sha512-XpjRUZ/EbWtVbMvW+ucon5Ykz7PjMoX65mIlUdAiVnaPGykzFAUrl8dl6Br5bfqnhQQfDjjUIgTAwWl3G++n1g==} + engines: {node: '>= 10'} + cpu: [arm] + os: [android] + + '@napi-rs/lzma-android-arm64@1.4.3': + resolution: {integrity: sha512-Bve6BF/4pnlO6HotIgRWgmUT3rbbW/QH471RF/GBA29GfEeUOPEdfQWC7tlzrLYsVFNX2KCWKd+XlxQNz9sRaA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@napi-rs/lzma-darwin-arm64@1.4.3': + resolution: {integrity: sha512-UxTb56kL6pSVTsZ1ShibnqLSwJZLTWtPU5TNYuyIjVNQYAIG8JQ5Yxz35azjwBCK7AjD8pBdpWLYUSyJRGAVAw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@napi-rs/lzma-darwin-x64@1.4.3': + resolution: {integrity: sha512-ps6HiwGKS1P4ottyV2/hVboZ0ugdM1Z1qO9YFpcuKweORfxAkxwJ6S8jOt7G27LQiWiiQHVwsUCODTHDFhOUPQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@napi-rs/lzma-freebsd-x64@1.4.3': + resolution: {integrity: sha512-W49h41U3+vLnbthbPzvJX1fQtTG+1jyUlfB+wX3oxILvIur06PjJRdMXrFtOZpWkFsihK9gO2DRkQYQJIIgTZw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@napi-rs/lzma-linux-arm-gnueabihf@1.4.3': + resolution: {integrity: sha512-11PNPiMGuwwxIxd9yPZY3Ek6RFGFRFQb/AtMStJIwlmJ6sM/djEknClLJVbVXbC/nqm7htVZEr+qmYgoDy0fAw==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@napi-rs/lzma-linux-arm64-gnu@1.4.3': + resolution: {integrity: sha512-XzlxZjSXTcrWFHbvvv2xbV5+bSV5IJqCJ8CCksc7xV3uWEAso9yBPJ8VSRD3GPc7ZoBDRqJmgCb/HQzHpLBekw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@napi-rs/lzma-linux-arm64-musl@1.4.3': + resolution: {integrity: sha512-k4fWiI4Pm61Esj8hnm7NWIbpZueTtP2jlJqmMhTqJyjqW3NUxbTHjSErZOZKIFRF1B3if4v5Tyzo7JL2X+BaSQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@napi-rs/lzma-linux-ppc64-gnu@1.4.3': + resolution: {integrity: sha512-tTIfk+TYZYbFySxaCMuzp4Zz1T3I6OYVYNAm+IrCSkZDLmUKUzBK3+Su+mT+PjcTNsAiHBa5NVjARXC7b7jmgQ==} + engines: {node: '>= 10'} + cpu: [ppc64] + os: [linux] + + '@napi-rs/lzma-linux-riscv64-gnu@1.4.3': + resolution: {integrity: sha512-HPyLYOYhkN7QYaWiKWhSnsLmx/l0pqgiiyaYeycgxCm9dwL8ummFWxveZqYjqdbUUvG7Mgi1jqgRe+55MVdyZQ==} + engines: {node: '>= 10'} + cpu: [riscv64] + os: [linux] + + '@napi-rs/lzma-linux-s390x-gnu@1.4.3': + resolution: {integrity: sha512-YkcV+RSZZIMM3D5sPZqvo2Q7/tHXBhgJWBi+6ceo46pTlqgn/nH+pVz+CzsDmLWz5hqNSXyv5IAhOcg2CH6rAg==} + engines: {node: '>= 10'} + cpu: [s390x] + os: [linux] + + '@napi-rs/lzma-linux-x64-gnu@1.4.3': + resolution: {integrity: sha512-ep6PLjN1+g4P12Hc7sLRmVpXXaHX22ykqxnOzjXUoj1KTph5XgM4+fUCyE5dsYI+lB4/tXqFuf9ZeFgHk5f00A==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@napi-rs/lzma-linux-x64-musl@1.4.3': + resolution: {integrity: sha512-QkCO6rVw0Z7eY0ziVc4aCFplbOTMpt0UBLPXWxsPd2lXtkAlRChzqaHOxdcL/HoLmBsqdCxmG0EZuHuAP/vKZQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@napi-rs/lzma-wasm32-wasi@1.4.3': + resolution: {integrity: sha512-+rMamB0xaeDyVt4OP4cV888cnmso+m78iUebNhGcrL/WXIziwql50KQrmj7PBdBCza/W7XEcraZT8pO8gSDGcg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@napi-rs/lzma-win32-arm64-msvc@1.4.3': + resolution: {integrity: sha512-6gQ+R6ztw11hswdsEu0jsOOXXnJPwhOA1yHRjqfuFemhf6esMd8l9b0uh3BfLBNe7qumtrH4KLrHu8yC9pSY3g==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@napi-rs/lzma-win32-ia32-msvc@1.4.3': + resolution: {integrity: sha512-+AJeJQoGE+QtZKlwM4VzDkfLmUa+6DsGOO5zdbIPlRCB6PEstRCXxp8lkMiQBNgk9f/IO0UEkRcJSZ+Hhqd8zw==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@napi-rs/lzma-win32-x64-msvc@1.4.3': + resolution: {integrity: sha512-66dFCX9ACpVUyTTom89nxhllc88yJyjxGFHO0M2olFcrSJArulfbE9kNIATgh04NDAe/l8VsDhnAxWuvJY1GuA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@napi-rs/lzma@1.4.3': + resolution: {integrity: sha512-uBjLLoUM9ll03jL/bP7XjyPg0vTU0vQ35N1vVqQHbzlK/fVZyuF2B1p/A6kqPsFFhaoBKgO6oaxsuerv091RtQ==} + engines: {node: '>= 10'} + + '@napi-rs/tar-android-arm-eabi@0.1.5': + resolution: {integrity: sha512-FM2qNG3ELeYibnZC8dfsCV4i/pql1nlLKVINfRC7TSwqFfgj5gbezZ0rT8gRPHbLyslVt6m4MPZfRE8Uj/MuCA==} + engines: {node: '>= 10'} + cpu: [arm] + os: [android] + + '@napi-rs/tar-android-arm64@0.1.5': + resolution: {integrity: sha512-OpP0QyD+K0a68nqyko793lLWiC2BN1wWF/Doatus1OCKxgj61vtrUPVO2cQGQS5i07I/+YGRF8lD0tQDrk4JDQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@napi-rs/tar-darwin-arm64@0.1.5': + resolution: {integrity: sha512-sfyM/9gxFabdMTFt4quvLJuKbXS6StGIUf7Cp3l8aV2WqCURJevdpN6wW8XtGBo/iSnAP52ERwMRdyIavPYruw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@napi-rs/tar-darwin-x64@0.1.5': + resolution: {integrity: sha512-NtY8bADKE/3ODBM3hW/RgPeeERJpI6/jgipT3eLJ/CQWY1VJ6t9GHR7anJKhx1oxVdmSfqfCGMolM8WPV9x9bw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@napi-rs/tar-freebsd-x64@0.1.5': + resolution: {integrity: sha512-azl0nWrDJAGg25cGVKEY7UtU5ABGz4sQASKvemDLwGbzMDtkJgCoPb+OunI1pezijRAyhiuZEQ4jK8S1qNAWCg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@napi-rs/tar-linux-arm-gnueabihf@0.1.5': + resolution: {integrity: sha512-OjGdKjaW7b0m96rAvsLthMBhwYSSgpTM/WkHqRJo91HCYQ6tHXDBnq4VIQx2FpwT1PoetvRsbSgy0tOc95iYjA==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@napi-rs/tar-linux-arm64-gnu@0.1.5': + resolution: {integrity: sha512-o3b2VE5c7+NFb6XRcXrdXgur1yhpx+XNItFoeJUMBE8z0AGAISf2DJSbcJawmefUvrGtr+iLr61hsr6f2hw+5Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@napi-rs/tar-linux-arm64-musl@0.1.5': + resolution: {integrity: sha512-5xTxsoPVqovnZ197CqTc+q3psRM4i+ErdiyfDgkG4nP045jh50gp22WKZuE24dc7/iS+IyUrM3+PRbmj2mzR8g==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@napi-rs/tar-linux-ppc64-gnu@0.1.5': + resolution: {integrity: sha512-7FF1u8EkDpCEPCgU0/kvuzsO+opB7eIbsGfKRIbOqrDT7c1DYxDetNTtukPvNoT2kvwfxxThgTfcPADPxdOE/w==} + engines: {node: '>= 10'} + cpu: [ppc64] + os: [linux] + + '@napi-rs/tar-linux-s390x-gnu@0.1.5': + resolution: {integrity: sha512-uyIZ7OLCLHtVBpogoJUD0GSAF1IUa3d5c5AVUemTLIwYkVgzdEB+khh3i2+/oKObf79ZKfQ8mYxOryHqfx+ulw==} + engines: {node: '>= 10'} + cpu: [s390x] + os: [linux] + + '@napi-rs/tar-linux-x64-gnu@0.1.5': + resolution: {integrity: sha512-y8pFyVTU6lSYiW2lse6i1Ns9yt9mBkAqPbcJnIjqC7ZqRd61T6g3XZDSrKmsM6ycTfsAqoE5WyyFxBjQN29AOA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@napi-rs/tar-linux-x64-musl@0.1.5': + resolution: {integrity: sha512-8phLYc0QX+tqvp34PQHUulZUi4sy/fdg1KgFHiyYExTRRleBB01vM7KSn7Bk9dwH7lannO5D7j4O8OY46Xcr/A==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@napi-rs/tar-wasm32-wasi@0.1.5': + resolution: {integrity: sha512-OpVWC/bwY0zb6nbQDg6koxeZGb441gXwPkaYVjaK4O0TJjNpRKbokLAMlGFtcc/sVSPjghFL0+enfnLDt/P7og==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@napi-rs/tar-win32-arm64-msvc@0.1.5': + resolution: {integrity: sha512-FXwQA2Ib55q98szshvDsitgo2iLW2lTD1Q53e8dPMGobPa2yL5e8IjJDCcMI7XJwBZPl9YjJk7nAb8y20DXF+Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@napi-rs/tar-win32-ia32-msvc@0.1.5': + resolution: {integrity: sha512-XEt58yFslNkwf2yJ+uX5nDNmPAk15Metkx2hVPeH29mOpuG2H8nuS8/42hZ+dQfZf3xABRjyurVMMH9JcgLZIQ==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@napi-rs/tar-win32-x64-msvc@0.1.5': + resolution: {integrity: sha512-9Rq0Ob4S5NGFwNL3kGQkgrYlObqQgw19QMSZdVuhzZ9sSxn9OSF5cWgZ/n1oMEPWK+u6n9GSN2XbPn4DI7pm7Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@napi-rs/tar@0.1.5': + resolution: {integrity: sha512-skgWKcpjtUqJUk1jwhVl8vXYCXQlFC532KiryU3hQBr6ZIJk0E0qD9FG99hUqtPko8mIMS5HDPO+uSnvHfgRVg==} + engines: {node: '>= 10'} + + '@napi-rs/wasm-runtime@0.2.11': + resolution: {integrity: sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA==} + + '@napi-rs/wasm-tools-android-arm-eabi@0.0.3': + resolution: {integrity: sha512-T2tme8w5jZ/ZCjJurqNtKCxYtGoDjW9v2rn1bfI60ewCfkYXNpxrTURdkOib85sz+BcwmOfXn0enbg5W9KohoQ==} + engines: {node: '>= 10'} + cpu: [arm] + os: [android] + + '@napi-rs/wasm-tools-android-arm64@0.0.3': + resolution: {integrity: sha512-siHTjrxxBrvsVty5X2jI5waAyzJpr756GqGVUqxqS2eoTuqYRfgaFNvX8asp9LAagFtOojfD0fZfuvxK7dc4Rw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@napi-rs/wasm-tools-darwin-arm64@0.0.3': + resolution: {integrity: sha512-0MqsSOYJ4jXcLv/nAInS8nwU+/hL0rSEJo7JXKj3dhkT9UNSj4zfidcOaIb05O9VskJBPmV040+edtWPHXNt2Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@napi-rs/wasm-tools-darwin-x64@0.0.3': + resolution: {integrity: sha512-yXAK2mrlBMZZYK/59JRHZu/c683HFpr5ork1cn++fy8gqUBRLbjuq47VDjA7oyLW5SmWqNDhmhjFTDGvfIvcUg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@napi-rs/wasm-tools-freebsd-x64@0.0.3': + resolution: {integrity: sha512-K1rne814utBd9Zo9LCggQ5h0TSnzGPzA+sG78Qr7KfFz8XQxEGDRH5wpzXyF1KaKav2RmO6wGMXlasDgIcq7GA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@napi-rs/wasm-tools-linux-arm64-gnu@0.0.3': + resolution: {integrity: sha512-Yu3gtpvGc2+hcay3SU5MK7EMrGPBq/V4i8mpw/MEYUCzOb7Vd9aL8CryElzlk0SIbktG08VYMdhFFFoJAjlYtg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@napi-rs/wasm-tools-linux-arm64-musl@0.0.3': + resolution: {integrity: sha512-XN+sPgEwFw3P47wDvtcQyOoZNghIL8gaiRjEGzprB+kE9N21GkuMbk3kdjiBBJkjqKF25f4fbOvNAY0jQEAO3A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@napi-rs/wasm-tools-linux-x64-gnu@0.0.3': + resolution: {integrity: sha512-mfMvMEqn33YtEjIyLPguZ6yDsNtF5zV7mqc99620YDyj2SLa0aI35TNTc7Dm+/hlgqHRKhdudsWGfYc4dBND2Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@napi-rs/wasm-tools-linux-x64-musl@0.0.3': + resolution: {integrity: sha512-KXMsXWGELoN5xgPCoRHbgt5TScSx8BK2GcCHKJ9OPZ2HMfsXbLgS/SNi6vz1CbLMZMLPBY2G6HAk0gzLGyS0mQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@napi-rs/wasm-tools-wasm32-wasi@0.0.3': + resolution: {integrity: sha512-v3iMHnAfMteogpbqHTFeLXPeAzL5AhpDJLvZvLXbuRiMsMRL0dn8CbcEnYja2P/Ui6Xlyky6PcaUsepOUTNb7A==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@napi-rs/wasm-tools-win32-arm64-msvc@0.0.3': + resolution: {integrity: sha512-HWrg9cW+u+rQKL9XCQILaGGs6mDYdwX9nwcTIvJAjrpGWu8Dp4wz6i66w6YKHqVng1suGYjjr+LH4/1e0tDaAg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@napi-rs/wasm-tools-win32-ia32-msvc@0.0.3': + resolution: {integrity: sha512-h99hAWvQKhcloyPfPi0IjrvKRToTE9Z4UVXoXZhcjpCGmr3o1qW+1FAupRy/TcVdMjUJNLE/aenml3UPqzQEQw==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@napi-rs/wasm-tools-win32-x64-msvc@0.0.3': + resolution: {integrity: sha512-7/6IpzMi9VGYxLcc9SJyu9ZIdbDwyyb09glVF/2SFEgke9F5H46XzRrAdSoRnjfcq/tdLyHKJbnpCIB257qVYg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@napi-rs/wasm-tools@0.0.3': + resolution: {integrity: sha512-p7NT5wnOIwmP0f3KbXlMabeld5dPFsADpHMWJaBodTSmnPE8P4msguxKJLKWquqAS1FY2dsjBZ62K0/hfiqAUg==} + engines: {node: '>= 10'} + + '@octokit/auth-token@6.0.0': + resolution: {integrity: sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==} + engines: {node: '>= 20'} + + '@octokit/core@7.0.2': + resolution: {integrity: sha512-ODsoD39Lq6vR6aBgvjTnA3nZGliknKboc9Gtxr7E4WDNqY24MxANKcuDQSF0jzapvGb3KWOEDrKfve4HoWGK+g==} + engines: {node: '>= 20'} + + '@octokit/endpoint@11.0.0': + resolution: {integrity: sha512-hoYicJZaqISMAI3JfaDr1qMNi48OctWuOih1m80bkYow/ayPw6Jj52tqWJ6GEoFTk1gBqfanSoI1iY99Z5+ekQ==} + engines: {node: '>= 20'} + + '@octokit/graphql@9.0.1': + resolution: {integrity: sha512-j1nQNU1ZxNFx2ZtKmL4sMrs4egy5h65OMDmSbVyuCzjOcwsHq6EaYjOTGXPQxgfiN8dJ4CriYHk6zF050WEULg==} + engines: {node: '>= 20'} + + '@octokit/openapi-types@25.1.0': + resolution: {integrity: sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==} + + '@octokit/plugin-paginate-rest@13.1.0': + resolution: {integrity: sha512-16iNOa4rTTjaWtfsPGJcYYL79FJakseX8TQFIPfVuSPC3s5nkS/DSNQPFPc5lJHgEDBWNMxSApHrEymNblhA9w==} + engines: {node: '>= 20'} + peerDependencies: + '@octokit/core': '>=6' + + '@octokit/plugin-request-log@6.0.0': + resolution: {integrity: sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q==} + engines: {node: '>= 20'} + peerDependencies: + '@octokit/core': '>=6' + + '@octokit/plugin-rest-endpoint-methods@16.0.0': + resolution: {integrity: sha512-kJVUQk6/dx/gRNLWUnAWKFs1kVPn5O5CYZyssyEoNYaFedqZxsfYs7DwI3d67hGz4qOwaJ1dpm07hOAD1BXx6g==} + engines: {node: '>= 20'} + peerDependencies: + '@octokit/core': '>=6' + + '@octokit/request-error@7.0.0': + resolution: {integrity: sha512-KRA7VTGdVyJlh0cP5Tf94hTiYVVqmt2f3I6mnimmaVz4UG3gQV/k4mDJlJv3X67iX6rmN7gSHCF8ssqeMnmhZg==} + engines: {node: '>= 20'} + + '@octokit/request@10.0.2': + resolution: {integrity: sha512-iYj4SJG/2bbhh+iIpFmG5u49DtJ4lipQ+aPakjL9OKpsGY93wM8w06gvFbEQxcMsZcCvk5th5KkIm2m8o14aWA==} + engines: {node: '>= 20'} + + '@octokit/rest@22.0.0': + resolution: {integrity: sha512-z6tmTu9BTnw51jYGulxrlernpsQYXpui1RK21vmXn8yF5bp6iX16yfTtJYGK5Mh1qDkvDOmp2n8sRMcQmR8jiA==} + engines: {node: '>= 20'} + + '@octokit/types@14.1.0': + resolution: {integrity: sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==} '@rollup/rollup-android-arm-eabi@4.43.0': resolution: {integrity: sha512-Krjy9awJl6rKbruhQDgivNbD1WuLb8xAclM4IR4cN5pHGAs2oIMMQJEiC3IC/9TZJ+QZkmZhlMO/6MBGxPidpw==} @@ -270,6 +780,9 @@ packages: '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + '@tybys/wasm-util@0.9.0': + resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} + '@types/estree@1.0.7': resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} @@ -300,13 +813,31 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + before-after-hook@4.0.0: + resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==} + cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -315,9 +846,31 @@ packages: resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} engines: {node: '>=4'} + chardet@0.7.0: + resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + check-error@1.0.3: resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} + + clipanion@4.0.0-rc.4: + resolution: {integrity: sha512-CXkMQxU6s9GklO/1f714dkKBMu1lopS1WFF0B8o4AxPykR1hpozxSiUZ5ZUeBjfPgCWqbcNOtZVFhB8Lkfp1+Q==} + peerDependencies: + typanion: '*' + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} @@ -342,6 +895,17 @@ packages: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + emnapi@1.4.3: + resolution: {integrity: sha512-qeLT07Xt4xNjlDJYtwtO664e44HXDaHnja7vWIy/g3xzZiNOcQh02gNblR6tkqnDzPPhc+dUeSYWbt6PoiYZKQ==} + peerDependencies: + node-addon-api: '>= 6.1.0' + peerDependenciesMeta: + node-addon-api: + optional: true + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + esbuild@0.21.5: resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} @@ -354,6 +918,13 @@ packages: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} + external-editor@3.1.0: + resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} + engines: {node: '>=4'} + + fast-content-type-parse@3.0.0: + resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -370,6 +941,14 @@ packages: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + is-stream@3.0.0: resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -380,10 +959,17 @@ packages: js-tokens@9.0.1: resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + local-pkg@0.5.1: resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==} engines: {node: '>=14'} + lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + loupe@2.3.7: resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} @@ -403,6 +989,10 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mute-stream@2.0.0: + resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} + engines: {node: ^18.17.0 || >=20.5.0} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -416,6 +1006,10 @@ packages: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} + os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + p-limit@5.0.0: resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} engines: {node: '>=18'} @@ -459,6 +1053,14 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + engines: {node: '>=10'} + hasBin: true + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -484,6 +1086,14 @@ packages: std-env@3.9.0: resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + strip-final-newline@3.0.0: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} engines: {node: '>=12'} @@ -502,13 +1112,33 @@ packages: resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==} engines: {node: '>=14.0.0'} + tmp@0.0.33: + resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} + engines: {node: '>=0.6.0'} + + toml@3.0.0: + resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typanion@3.14.0: + resolution: {integrity: sha512-ZW/lVMRabETuYCd9O9ZvMhAh8GslSqaUjxmK/JLPCh6l73CvLBiuXswj/+7LdnWOgYsQ130FqLzFz5aGT4I3Ug==} + type-detect@4.1.0: resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} engines: {node: '>=4'} + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + ufo@1.6.1: resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + universal-user-agent@7.0.3: + resolution: {integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==} + vite-node@1.6.1: resolution: {integrity: sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -570,6 +1200,9 @@ packages: jsdom: optional: true + wasm-sjlj@1.0.6: + resolution: {integrity: sha512-pjaKtLJejlWm6+okPV2X1A6nIsRDD4qeK97eCh8DP8KXi3Nzn/HY01vpHhZHlhDri12eZqipjm8HhdTVw+ATxw==} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -580,12 +1213,33 @@ packages: engines: {node: '>=8'} hasBin: true + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + yocto-queue@1.2.1: resolution: {integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==} engines: {node: '>=12.20'} + yoctocolors-cjs@2.1.2: + resolution: {integrity: sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==} + engines: {node: '>=18'} + snapshots: + '@emnapi/core@1.4.3': + dependencies: + '@emnapi/wasi-threads': 1.0.2 + tslib: 2.8.1 + + '@emnapi/runtime@1.4.3': + dependencies: + tslib: 2.8.1 + + '@emnapi/wasi-threads@1.0.2': + dependencies: + tslib: 2.8.1 + '@esbuild/aix-ppc64@0.21.5': optional: true @@ -655,13 +1309,404 @@ snapshots: '@esbuild/win32-x64@0.21.5': optional: true + '@inquirer/checkbox@4.1.8': + dependencies: + '@inquirer/core': 10.1.13 + '@inquirer/figures': 1.0.12 + '@inquirer/type': 3.0.7 + ansi-escapes: 4.3.2 + yoctocolors-cjs: 2.1.2 + + '@inquirer/confirm@5.1.12': + dependencies: + '@inquirer/core': 10.1.13 + '@inquirer/type': 3.0.7 + + '@inquirer/core@10.1.13': + dependencies: + '@inquirer/figures': 1.0.12 + '@inquirer/type': 3.0.7 + ansi-escapes: 4.3.2 + cli-width: 4.1.0 + mute-stream: 2.0.0 + signal-exit: 4.1.0 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.2 + + '@inquirer/editor@4.2.13': + dependencies: + '@inquirer/core': 10.1.13 + '@inquirer/type': 3.0.7 + external-editor: 3.1.0 + + '@inquirer/expand@4.0.15': + dependencies: + '@inquirer/core': 10.1.13 + '@inquirer/type': 3.0.7 + yoctocolors-cjs: 2.1.2 + + '@inquirer/figures@1.0.12': {} + + '@inquirer/input@4.1.12': + dependencies: + '@inquirer/core': 10.1.13 + '@inquirer/type': 3.0.7 + + '@inquirer/number@3.0.15': + dependencies: + '@inquirer/core': 10.1.13 + '@inquirer/type': 3.0.7 + + '@inquirer/password@4.0.15': + dependencies: + '@inquirer/core': 10.1.13 + '@inquirer/type': 3.0.7 + ansi-escapes: 4.3.2 + + '@inquirer/prompts@7.5.3': + dependencies: + '@inquirer/checkbox': 4.1.8 + '@inquirer/confirm': 5.1.12 + '@inquirer/editor': 4.2.13 + '@inquirer/expand': 4.0.15 + '@inquirer/input': 4.1.12 + '@inquirer/number': 3.0.15 + '@inquirer/password': 4.0.15 + '@inquirer/rawlist': 4.1.3 + '@inquirer/search': 3.0.15 + '@inquirer/select': 4.2.3 + + '@inquirer/rawlist@4.1.3': + dependencies: + '@inquirer/core': 10.1.13 + '@inquirer/type': 3.0.7 + yoctocolors-cjs: 2.1.2 + + '@inquirer/search@3.0.15': + dependencies: + '@inquirer/core': 10.1.13 + '@inquirer/figures': 1.0.12 + '@inquirer/type': 3.0.7 + yoctocolors-cjs: 2.1.2 + + '@inquirer/select@4.2.3': + dependencies: + '@inquirer/core': 10.1.13 + '@inquirer/figures': 1.0.12 + '@inquirer/type': 3.0.7 + ansi-escapes: 4.3.2 + yoctocolors-cjs: 2.1.2 + + '@inquirer/type@3.0.7': {} + '@jest/schemas@29.6.3': dependencies: '@sinclair/typebox': 0.27.8 '@jridgewell/sourcemap-codec@1.5.0': {} - '@napi-rs/cli@2.18.4': {} + '@napi-rs/cli@3.0.0-alpha.89(@emnapi/runtime@1.4.3)(emnapi@1.4.3)': + dependencies: + '@inquirer/prompts': 7.5.3 + '@napi-rs/cross-toolchain': 0.0.19 + '@napi-rs/wasm-tools': 0.0.3 + '@octokit/rest': 22.0.0 + clipanion: 4.0.0-rc.4(typanion@3.14.0) + colorette: 2.0.20 + debug: 4.4.1 + js-yaml: 4.1.0 + lodash-es: 4.17.21 + semver: 7.7.2 + toml: 3.0.0 + typanion: 3.14.0 + wasm-sjlj: 1.0.6 + optionalDependencies: + '@emnapi/runtime': 1.4.3 + emnapi: 1.4.3 + transitivePeerDependencies: + - '@napi-rs/cross-toolchain-arm64-target-aarch64' + - '@napi-rs/cross-toolchain-arm64-target-armv7' + - '@napi-rs/cross-toolchain-arm64-target-x86_64' + - '@napi-rs/cross-toolchain-x64-target-aarch64' + - '@napi-rs/cross-toolchain-x64-target-armv7' + - '@napi-rs/cross-toolchain-x64-target-x86_64' + - '@types/node' + - supports-color + + '@napi-rs/cross-toolchain@0.0.19': + dependencies: + '@napi-rs/lzma': 1.4.3 + '@napi-rs/tar': 0.1.5 + debug: 4.4.1 + transitivePeerDependencies: + - supports-color + + '@napi-rs/lzma-android-arm-eabi@1.4.3': + optional: true + + '@napi-rs/lzma-android-arm64@1.4.3': + optional: true + + '@napi-rs/lzma-darwin-arm64@1.4.3': + optional: true + + '@napi-rs/lzma-darwin-x64@1.4.3': + optional: true + + '@napi-rs/lzma-freebsd-x64@1.4.3': + optional: true + + '@napi-rs/lzma-linux-arm-gnueabihf@1.4.3': + optional: true + + '@napi-rs/lzma-linux-arm64-gnu@1.4.3': + optional: true + + '@napi-rs/lzma-linux-arm64-musl@1.4.3': + optional: true + + '@napi-rs/lzma-linux-ppc64-gnu@1.4.3': + optional: true + + '@napi-rs/lzma-linux-riscv64-gnu@1.4.3': + optional: true + + '@napi-rs/lzma-linux-s390x-gnu@1.4.3': + optional: true + + '@napi-rs/lzma-linux-x64-gnu@1.4.3': + optional: true + + '@napi-rs/lzma-linux-x64-musl@1.4.3': + optional: true + + '@napi-rs/lzma-wasm32-wasi@1.4.3': + dependencies: + '@napi-rs/wasm-runtime': 0.2.11 + optional: true + + '@napi-rs/lzma-win32-arm64-msvc@1.4.3': + optional: true + + '@napi-rs/lzma-win32-ia32-msvc@1.4.3': + optional: true + + '@napi-rs/lzma-win32-x64-msvc@1.4.3': + optional: true + + '@napi-rs/lzma@1.4.3': + optionalDependencies: + '@napi-rs/lzma-android-arm-eabi': 1.4.3 + '@napi-rs/lzma-android-arm64': 1.4.3 + '@napi-rs/lzma-darwin-arm64': 1.4.3 + '@napi-rs/lzma-darwin-x64': 1.4.3 + '@napi-rs/lzma-freebsd-x64': 1.4.3 + '@napi-rs/lzma-linux-arm-gnueabihf': 1.4.3 + '@napi-rs/lzma-linux-arm64-gnu': 1.4.3 + '@napi-rs/lzma-linux-arm64-musl': 1.4.3 + '@napi-rs/lzma-linux-ppc64-gnu': 1.4.3 + '@napi-rs/lzma-linux-riscv64-gnu': 1.4.3 + '@napi-rs/lzma-linux-s390x-gnu': 1.4.3 + '@napi-rs/lzma-linux-x64-gnu': 1.4.3 + '@napi-rs/lzma-linux-x64-musl': 1.4.3 + '@napi-rs/lzma-wasm32-wasi': 1.4.3 + '@napi-rs/lzma-win32-arm64-msvc': 1.4.3 + '@napi-rs/lzma-win32-ia32-msvc': 1.4.3 + '@napi-rs/lzma-win32-x64-msvc': 1.4.3 + + '@napi-rs/tar-android-arm-eabi@0.1.5': + optional: true + + '@napi-rs/tar-android-arm64@0.1.5': + optional: true + + '@napi-rs/tar-darwin-arm64@0.1.5': + optional: true + + '@napi-rs/tar-darwin-x64@0.1.5': + optional: true + + '@napi-rs/tar-freebsd-x64@0.1.5': + optional: true + + '@napi-rs/tar-linux-arm-gnueabihf@0.1.5': + optional: true + + '@napi-rs/tar-linux-arm64-gnu@0.1.5': + optional: true + + '@napi-rs/tar-linux-arm64-musl@0.1.5': + optional: true + + '@napi-rs/tar-linux-ppc64-gnu@0.1.5': + optional: true + + '@napi-rs/tar-linux-s390x-gnu@0.1.5': + optional: true + + '@napi-rs/tar-linux-x64-gnu@0.1.5': + optional: true + + '@napi-rs/tar-linux-x64-musl@0.1.5': + optional: true + + '@napi-rs/tar-wasm32-wasi@0.1.5': + dependencies: + '@napi-rs/wasm-runtime': 0.2.11 + optional: true + + '@napi-rs/tar-win32-arm64-msvc@0.1.5': + optional: true + + '@napi-rs/tar-win32-ia32-msvc@0.1.5': + optional: true + + '@napi-rs/tar-win32-x64-msvc@0.1.5': + optional: true + + '@napi-rs/tar@0.1.5': + optionalDependencies: + '@napi-rs/tar-android-arm-eabi': 0.1.5 + '@napi-rs/tar-android-arm64': 0.1.5 + '@napi-rs/tar-darwin-arm64': 0.1.5 + '@napi-rs/tar-darwin-x64': 0.1.5 + '@napi-rs/tar-freebsd-x64': 0.1.5 + '@napi-rs/tar-linux-arm-gnueabihf': 0.1.5 + '@napi-rs/tar-linux-arm64-gnu': 0.1.5 + '@napi-rs/tar-linux-arm64-musl': 0.1.5 + '@napi-rs/tar-linux-ppc64-gnu': 0.1.5 + '@napi-rs/tar-linux-s390x-gnu': 0.1.5 + '@napi-rs/tar-linux-x64-gnu': 0.1.5 + '@napi-rs/tar-linux-x64-musl': 0.1.5 + '@napi-rs/tar-wasm32-wasi': 0.1.5 + '@napi-rs/tar-win32-arm64-msvc': 0.1.5 + '@napi-rs/tar-win32-ia32-msvc': 0.1.5 + '@napi-rs/tar-win32-x64-msvc': 0.1.5 + + '@napi-rs/wasm-runtime@0.2.11': + dependencies: + '@emnapi/core': 1.4.3 + '@emnapi/runtime': 1.4.3 + '@tybys/wasm-util': 0.9.0 + + '@napi-rs/wasm-tools-android-arm-eabi@0.0.3': + optional: true + + '@napi-rs/wasm-tools-android-arm64@0.0.3': + optional: true + + '@napi-rs/wasm-tools-darwin-arm64@0.0.3': + optional: true + + '@napi-rs/wasm-tools-darwin-x64@0.0.3': + optional: true + + '@napi-rs/wasm-tools-freebsd-x64@0.0.3': + optional: true + + '@napi-rs/wasm-tools-linux-arm64-gnu@0.0.3': + optional: true + + '@napi-rs/wasm-tools-linux-arm64-musl@0.0.3': + optional: true + + '@napi-rs/wasm-tools-linux-x64-gnu@0.0.3': + optional: true + + '@napi-rs/wasm-tools-linux-x64-musl@0.0.3': + optional: true + + '@napi-rs/wasm-tools-wasm32-wasi@0.0.3': + dependencies: + '@napi-rs/wasm-runtime': 0.2.11 + optional: true + + '@napi-rs/wasm-tools-win32-arm64-msvc@0.0.3': + optional: true + + '@napi-rs/wasm-tools-win32-ia32-msvc@0.0.3': + optional: true + + '@napi-rs/wasm-tools-win32-x64-msvc@0.0.3': + optional: true + + '@napi-rs/wasm-tools@0.0.3': + optionalDependencies: + '@napi-rs/wasm-tools-android-arm-eabi': 0.0.3 + '@napi-rs/wasm-tools-android-arm64': 0.0.3 + '@napi-rs/wasm-tools-darwin-arm64': 0.0.3 + '@napi-rs/wasm-tools-darwin-x64': 0.0.3 + '@napi-rs/wasm-tools-freebsd-x64': 0.0.3 + '@napi-rs/wasm-tools-linux-arm64-gnu': 0.0.3 + '@napi-rs/wasm-tools-linux-arm64-musl': 0.0.3 + '@napi-rs/wasm-tools-linux-x64-gnu': 0.0.3 + '@napi-rs/wasm-tools-linux-x64-musl': 0.0.3 + '@napi-rs/wasm-tools-wasm32-wasi': 0.0.3 + '@napi-rs/wasm-tools-win32-arm64-msvc': 0.0.3 + '@napi-rs/wasm-tools-win32-ia32-msvc': 0.0.3 + '@napi-rs/wasm-tools-win32-x64-msvc': 0.0.3 + + '@octokit/auth-token@6.0.0': {} + + '@octokit/core@7.0.2': + dependencies: + '@octokit/auth-token': 6.0.0 + '@octokit/graphql': 9.0.1 + '@octokit/request': 10.0.2 + '@octokit/request-error': 7.0.0 + '@octokit/types': 14.1.0 + before-after-hook: 4.0.0 + universal-user-agent: 7.0.3 + + '@octokit/endpoint@11.0.0': + dependencies: + '@octokit/types': 14.1.0 + universal-user-agent: 7.0.3 + + '@octokit/graphql@9.0.1': + dependencies: + '@octokit/request': 10.0.2 + '@octokit/types': 14.1.0 + universal-user-agent: 7.0.3 + + '@octokit/openapi-types@25.1.0': {} + + '@octokit/plugin-paginate-rest@13.1.0(@octokit/core@7.0.2)': + dependencies: + '@octokit/core': 7.0.2 + '@octokit/types': 14.1.0 + + '@octokit/plugin-request-log@6.0.0(@octokit/core@7.0.2)': + dependencies: + '@octokit/core': 7.0.2 + + '@octokit/plugin-rest-endpoint-methods@16.0.0(@octokit/core@7.0.2)': + dependencies: + '@octokit/core': 7.0.2 + '@octokit/types': 14.1.0 + + '@octokit/request-error@7.0.0': + dependencies: + '@octokit/types': 14.1.0 + + '@octokit/request@10.0.2': + dependencies: + '@octokit/endpoint': 11.0.0 + '@octokit/request-error': 7.0.0 + '@octokit/types': 14.1.0 + fast-content-type-parse: 3.0.0 + universal-user-agent: 7.0.3 + + '@octokit/rest@22.0.0': + dependencies: + '@octokit/core': 7.0.2 + '@octokit/plugin-paginate-rest': 13.1.0(@octokit/core@7.0.2) + '@octokit/plugin-request-log': 6.0.0(@octokit/core@7.0.2) + '@octokit/plugin-rest-endpoint-methods': 16.0.0(@octokit/core@7.0.2) + + '@octokit/types@14.1.0': + dependencies: + '@octokit/openapi-types': 25.1.0 '@rollup/rollup-android-arm-eabi@4.43.0': optional: true @@ -725,6 +1770,10 @@ snapshots: '@sinclair/typebox@0.27.8': {} + '@tybys/wasm-util@0.9.0': + dependencies: + tslib: 2.8.1 + '@types/estree@1.0.7': {} '@types/estree@1.0.8': {} @@ -764,10 +1813,24 @@ snapshots: acorn@8.15.0: {} + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + + ansi-regex@5.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + ansi-styles@5.2.0: {} + argparse@2.0.1: {} + assertion-error@1.1.0: {} + before-after-hook@4.0.0: {} + cac@6.7.14: {} chai@4.5.0: @@ -780,10 +1843,26 @@ snapshots: pathval: 1.1.1 type-detect: 4.1.0 + chardet@0.7.0: {} + check-error@1.0.3: dependencies: get-func-name: 2.0.2 + cli-width@4.1.0: {} + + clipanion@4.0.0-rc.4(typanion@3.14.0): + dependencies: + typanion: 3.14.0 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + colorette@2.0.20: {} + confbox@0.1.8: {} cross-spawn@7.0.6: @@ -802,6 +1881,10 @@ snapshots: diff-sequences@29.6.3: {} + emnapi@1.4.3: {} + + emoji-regex@8.0.0: {} + esbuild@0.21.5: optionalDependencies: '@esbuild/aix-ppc64': 0.21.5 @@ -844,6 +1927,14 @@ snapshots: signal-exit: 4.1.0 strip-final-newline: 3.0.0 + external-editor@3.1.0: + dependencies: + chardet: 0.7.0 + iconv-lite: 0.4.24 + tmp: 0.0.33 + + fast-content-type-parse@3.0.0: {} + fsevents@2.3.3: optional: true @@ -853,17 +1944,29 @@ snapshots: human-signals@5.0.0: {} + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + + is-fullwidth-code-point@3.0.0: {} + is-stream@3.0.0: {} isexe@2.0.0: {} js-tokens@9.0.1: {} + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + local-pkg@0.5.1: dependencies: mlly: 1.7.4 pkg-types: 1.3.1 + lodash-es@4.17.21: {} + loupe@2.3.7: dependencies: get-func-name: 2.0.2 @@ -885,6 +1988,8 @@ snapshots: ms@2.1.3: {} + mute-stream@2.0.0: {} + nanoid@3.3.11: {} npm-run-path@5.3.0: @@ -895,6 +2000,8 @@ snapshots: dependencies: mimic-fn: 4.0.0 + os-tmpdir@1.0.2: {} + p-limit@5.0.0: dependencies: yocto-queue: 1.2.1 @@ -957,6 +2064,10 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.43.0 fsevents: 2.3.3 + safer-buffer@2.1.2: {} + + semver@7.7.2: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -973,6 +2084,16 @@ snapshots: std-env@3.9.0: {} + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + strip-final-newline@3.0.0: {} strip-literal@2.1.1: @@ -985,10 +2106,24 @@ snapshots: tinyspy@2.2.1: {} + tmp@0.0.33: + dependencies: + os-tmpdir: 1.0.2 + + toml@3.0.0: {} + + tslib@2.8.1: {} + + typanion@3.14.0: {} + type-detect@4.1.0: {} + type-fest@0.21.3: {} + ufo@1.6.1: {} + universal-user-agent@7.0.3: {} + vite-node@1.6.1: dependencies: cac: 6.7.14 @@ -1047,6 +2182,8 @@ snapshots: - supports-color - terser + wasm-sjlj@1.0.6: {} + which@2.0.2: dependencies: isexe: 2.0.0 @@ -1056,4 +2193,12 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + yocto-queue@1.2.1: {} + + yoctocolors-cjs@2.1.2: {} diff --git a/napi_binding/src/lib.rs b/napi_binding/src/lib.rs index b0de513f..2a8ba688 100644 --- a/napi_binding/src/lib.rs +++ b/napi_binding/src/lib.rs @@ -7,6 +7,12 @@ use serde_json::Value; pub fn parse(input: String) -> Result { let tree = to_mdast(&input, &ParseOptions::default()) .map_err(|e| Error::from_reason(format!("{:?}", e)))?; - serde_json::to_value(&tree) - .map_err(|e| Error::from_reason(e.to_string())) + serde_json::to_value(&tree).map_err(|e| Error::from_reason(e.to_string())) +} + +#[napi] +pub fn parse_mdx(mdx: String) -> Result { + let ast = + to_mdast(&mdx, &ParseOptions::mdx()).map_err(|e| Error::from_reason(format!("{:?}", e)))?; + serde_json::to_value(&ast).map_err(|e| Error::from_reason(e.to_string())) } From 250df48a247dd8e48d1b3dfb2cdb6b47bdba1549 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 14:07:21 +0200 Subject: [PATCH 04/61] adding napi release process --- {napi_binding/.cargo => .cargo}/config.toml | 0 .github/workflows/release-napi.yml | 177 +++++++ .gitignore | 3 + Cargo.toml | 2 +- napi/.cargo/config.toml | 5 + {napi_binding => napi}/.gitignore | 0 {napi_binding => napi}/Cargo.toml | 0 napi/README.md | 443 ++++++++++++++++++ .../__tests__/parse.test.ts | 0 napi/browser.js | 1 + {napi_binding => napi}/index.d.ts | 0 napi/index.js | 380 +++++++++++++++ napi/markdown-rs.wasi-browser.js | 58 +++ napi/markdown-rs.wasi.cjs | 89 ++++ napi/package.json | 53 +++ {napi_binding => napi}/src/lib.rs | 0 napi/wasi-worker-browser.mjs | 32 ++ napi/wasi-worker.mjs | 63 +++ napi_binding/package.json | 38 -- package.json | 53 +++ napi_binding/pnpm-lock.yaml => pnpm-lock.yaml | 0 pnpm-workspace.yaml | 3 + 22 files changed, 1361 insertions(+), 39 deletions(-) rename {napi_binding/.cargo => .cargo}/config.toml (100%) create mode 100644 .github/workflows/release-napi.yml create mode 100644 napi/.cargo/config.toml rename {napi_binding => napi}/.gitignore (100%) rename {napi_binding => napi}/Cargo.toml (100%) create mode 100644 napi/README.md rename {napi_binding => napi}/__tests__/parse.test.ts (100%) create mode 100644 napi/browser.js rename {napi_binding => napi}/index.d.ts (100%) create mode 100644 napi/index.js create mode 100644 napi/markdown-rs.wasi-browser.js create mode 100644 napi/markdown-rs.wasi.cjs create mode 100644 napi/package.json rename {napi_binding => napi}/src/lib.rs (100%) create mode 100644 napi/wasi-worker-browser.mjs create mode 100644 napi/wasi-worker.mjs delete mode 100644 napi_binding/package.json create mode 100644 package.json rename napi_binding/pnpm-lock.yaml => pnpm-lock.yaml (100%) create mode 100644 pnpm-workspace.yaml diff --git a/napi_binding/.cargo/config.toml b/.cargo/config.toml similarity index 100% rename from napi_binding/.cargo/config.toml rename to .cargo/config.toml diff --git a/.github/workflows/release-napi.yml b/.github/workflows/release-napi.yml new file mode 100644 index 00000000..09c622cb --- /dev/null +++ b/.github/workflows/release-napi.yml @@ -0,0 +1,177 @@ +name: Release NAPI + +permissions: {} + +on: + workflow_dispatch: + push: + # branches: + # - main + paths: + - package.json + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + DEBUG: "napi:*" + +jobs: + # check: + # name: Check version + # runs-on: ubuntu-latest + # outputs: + # version_changed: ${{ steps.version.outputs.changed }} + # steps: + # - uses: taiki-e/checkout-action@b13d20b7cda4e2f325ef19895128f7ff735c0b3d # v1.3.1 + + # - name: Check version changes + # uses: EndBug/version-check@36ff30f37c7deabe56a30caa043d127be658c425 # v2.1.5 + # id: version + # with: + # static-checking: localIsNew + # file-url: https://unpkg.com/oxc-resolver@latest/package.json + # file-name: package.json + + # - name: Set version name + # if: steps.version.outputs.changed == 'true' + # env: + # version: ${{ steps.version.outputs.version }} + # run: echo "version=${version}" + + build: + # needs: check + # if: needs.check.outputs.version_changed == 'true' + strategy: + fail-fast: false + matrix: + include: + - os: windows-latest + target: x86_64-pc-windows-msvc + build: | + pnpm build --target x86_64-pc-windows-msvc + + - os: windows-latest + target: aarch64-pc-windows-msvc + build: | + pnpm build --target aarch64-pc-windows-msvc + + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + build: | + pnpm build --target x86_64-unknown-linux-gnu --use-napi-cross + + - os: ubuntu-latest + target: x86_64-unknown-linux-musl + build: | + pnpm build --target x86_64-unknown-linux-musl -x + + - os: ubuntu-latest + target: aarch64-unknown-linux-gnu + build: | + pnpm build --target aarch64-unknown-linux-gnu --use-napi-cross + + - os: ubuntu-latest + target: aarch64-unknown-linux-musl + build: | + pnpm build --target aarch64-unknown-linux-musl -x + + - os: ubuntu-latest + target: armv7-unknown-linux-gnueabihf + build: | + pnpm build --target armv7-unknown-linux-gnueabihf --use-napi-cross + + - os: macos-latest + target: x86_64-apple-darwin + build: | + pnpm build --target x86_64-apple-darwin + + - os: macos-latest + target: aarch64-apple-darwin + build: | + pnpm build --target aarch64-apple-darwin + + - os: ubuntu-latest + target: wasm32-wasip1-threads + build: | + pnpm build --target wasm32-wasip1-threads + + - os: ubuntu-latest + target: s390x-unknown-linux-gnu + build: | + export CFLAGS="-fuse-ld=lld" + pnpm build --target s390x-unknown-linux-gnu --use-napi-cross + + - os: ubuntu-latest + target: riscv64gc-unknown-linux-gnu + build: | + sudo apt-get update + sudo apt-get install gcc-riscv64-linux-gnu g++-riscv64-linux-gnu -y + export CC=riscv64-linux-gnu-gcc + export CXX=riscv64-linux-gnu-g++ + pnpm build --target riscv64gc-unknown-linux-gnu + + name: Build ${{ matrix.target }} + runs-on: ${{ matrix.os }} + steps: + - uses: taiki-e/checkout-action@b13d20b7cda4e2f325ef19895128f7ff735c0b3d # v1.3.1 + - uses: oxc-project/setup-node@f42e3bda950c7454575e78ee4eaac880a077700c # v1.0.0 + - run: pnpm i + + - run: rustup target add ${{ matrix.target }} + + - uses: goto-bus-stop/setup-zig@abea47f85e598557f500fa1fd2ab7464fcb39406 # v2.2.1 + if: ${{ contains(matrix.target, 'musl') }} + with: + version: 0.13.0 + + - name: Build + run: ${{ matrix.build }} + shell: bash + env: + CC: clang # for mimalloc + + - name: Upload artifacts + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + if-no-files-found: "error" + name: bindings-${{ matrix.target }} + path: | + napi/*.node + napi/*.wasm + + + + publish: + name: Publish NAPI + runs-on: ubuntu-latest + permissions: + id-token: write # for `npm publish --provenance` + needs: + - build + steps: + - uses: taiki-e/checkout-action@b13d20b7cda4e2f325ef19895128f7ff735c0b3d # v1.3.1 + + - uses: oxc-project/setup-node@f42e3bda950c7454575e78ee4eaac880a077700c # v1.0.0 + + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + path: artifacts + + - run: pnpm napi create-npm-dirs --package-json-path package.json + + - run: pnpm napi artifacts --package-json-path package.json --npm-dir npm --build-output-dir napi + + - name: Publish npm packages as latest + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc + pnpm napi pre-publish --no-gh-release --tagstyle npm --package-json-path package.json --npm-dir npm + + # Publish root package + cp package.json napi/package.json + cp README.md napi/README.md + npm publish napi/ --tag latest --provenance --access public diff --git a/.gitignore b/.gitignore index 8ab37ea0..6f44369c 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,6 @@ fuzz/hfuzz_target fuzz/hfuzz_workspace *.node *.wasm +node_modules +/npm +target/ diff --git a/Cargo.toml b/Cargo.toml index d6278d91..f6431c7a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ rust-version = "1.56" version = "1.0.0" [workspace] -members = ["generate", "mdast_util_to_markdown", "napi_binding"] +members = ["generate", "mdast_util_to_markdown", "napi"] [workspace.dependencies] pretty_assertions = "1" diff --git a/napi/.cargo/config.toml b/napi/.cargo/config.toml new file mode 100644 index 00000000..9d0e3976 --- /dev/null +++ b/napi/.cargo/config.toml @@ -0,0 +1,5 @@ +[target.x86_64-apple-darwin] +rustflags = ["-C", "link-args=-Wl,-undefined,dynamic_lookup"] + +[target.aarch64-apple-darwin] +rustflags = ["-C", "link-args=-Wl,-undefined,dynamic_lookup"] diff --git a/napi_binding/.gitignore b/napi/.gitignore similarity index 100% rename from napi_binding/.gitignore rename to napi/.gitignore diff --git a/napi_binding/Cargo.toml b/napi/Cargo.toml similarity index 100% rename from napi_binding/Cargo.toml rename to napi/Cargo.toml diff --git a/napi/README.md b/napi/README.md new file mode 100644 index 00000000..f3710bab --- /dev/null +++ b/napi/README.md @@ -0,0 +1,443 @@ +

+
+ +
+
+
+

+ +# markdown-rs + +[![Build][badge-build-image]][badge-build-url] +[![Coverage][badge-coverage-image]][badge-coverage-url] + +CommonMark compliant markdown parser in Rust with ASTs and extensions. + +## Feature highlights + +* [x] **[compliant][commonmark]** + (100% to CommonMark) +* [x] **[extensions][]** + (100% GFM, 100% MDX, frontmatter, math) +* [x] **[safe][security]** + (100% safe Rust, also 100% safe HTML by default) +* [x] **[robust][test]** + (2300+ tests, 100% coverage, fuzz testing) +* [x] **[ast][mdast]** + (mdast) + +## Links + +* [GitHub: `wooorm/markdown-rs`][repo] +* [`crates.io`: `markdown`][crate] +* [`docs.rs`: `markdown`][docs] + +## When should I use this? + +* if you *just* want to turn markdown into HTML (with maybe a few extensions) +* if you want to do *really complex things* with markdown + +## What is this? + +`markdown-rs` is an open source markdown parser written in Rust. +It’s implemented as a state machine (`#![no_std]` + `alloc`) that emits +concrete tokens, +so that every byte is accounted for, +with positional info. +The API then exposes this information as an AST, +which is easier to work with, +or it compiles directly to HTML. + +While most markdown parsers work towards compliancy with CommonMark (or GFM), +this project goes further by following how the reference parsers (`cmark`, +`cmark-gfm`) work, +which is confirmed with thousands of extra tests. + +Other than CommonMark and GFM, +this project also supports common extensions to markdown such as +MDX, math, and frontmatter. + +This Rust crate has a sibling project in JavaScript: +[`micromark`][micromark] +(and [`mdast-util-from-markdown`][mdast-util-from-markdown] for the AST). + +P.S. if you want to *compile* MDX, +use [`mdxjs-rs`][mdxjs-rs]. + +## Questions + +* to learn markdown, + see this [cheatsheet and tutorial][cheat] +* for the API, + see the [crate docs][docs] +* for questions, + see [Discussions][] +* to help, + see [contribute][] or [sponsor][] below + +## Contents + +* [Install](#install) +* [Use](#use) +* [API](#api) +* [Extensions](#extensions) +* [Project](#project) + * [Overview](#overview) + * [File structure](#file-structure) + * [Test](#test) + * [Version](#version) + * [Security](#security) + * [Contribute](#contribute) + * [Sponsor](#sponsor) + * [Thanks](#thanks) +* [Related](#related) +* [License](#license) + +## Install + +With [Rust][] +(rust edition 2018+, ±version 1.56+), +install with `cargo`: + +```sh +cargo add markdown +``` + +## Use + +```rs +fn main() { + println!("{}", markdown::to_html("## Hi, *Saturn*! 🪐")); +} +``` + +Yields: + +```html +

Hi, Saturn! 🪐

+``` + +Extensions (in this case GFM): + +```rs +fn main() -> Result<(), markdown::message::Message> { + println!( + "{}", + markdown::to_html_with_options( + "* [x] contact ~Mercury~Venus at hi@venus.com!", + &markdown::Options::gfm() + )? + ); + + Ok(()) +} +``` + +Yields: + +```html + +``` + +Syntax tree ([mdast][]): + +```rs +fn main() -> Result<(), markdown::message::Message> { + println!( + "{:?}", + markdown::to_mdast("# Hi *Earth*!", &markdown::ParseOptions::default())? + ); + + Ok(()) +} +``` + +Yields: + +```text +Root { children: [Heading { children: [Text { value: "Hi ", position: Some(1:3-1:6 (2-5)) }, Emphasis { children: [Text { value: "Earth", position: Some(1:7-1:12 (6-11)) }], position: Some(1:6-1:13 (5-12)) }, Text { value: "!", position: Some(1:13-1:14 (12-13)) }], position: Some(1:1-1:14 (0-13)), depth: 1 }], position: Some(1:1-1:14 (0-13)) } +``` + +## API + +`markdown-rs` exposes +[`to_html`](https://docs.rs/markdown/latest/markdown/fn.to_html.html), +[`to_html_with_options`](https://docs.rs/markdown/latest/markdown/fn.to_html_with_options.html), +[`to_mdast`](https://docs.rs/markdown/latest/markdown/fn.to_mdast.html), +[`Options`](https://docs.rs/markdown/latest/markdown/struct.Options.html), +and a few other structs and enums. + +See the [crate docs][docs] for more info. + +## Extensions + +`markdown-rs` supports extensions to `CommonMark`. +These extensions are maintained in this project. +They are not enabled by default but can be turned on with options. + +* GFM + * autolink literal + * footnote + * strikethrough + * table + * tagfilter + * task list item +* MDX + * ESM + * expressions + * JSX +* frontmatter +* math + +It is not a goal of this project to support lots of different extensions. +It’s instead a goal to support very common and mostly standardized extensions. + +## Project + +`markdown-rs` is maintained as a single monolithic crate. + +### Overview + +The process to parse markdown looks like this: + +```txt + markdown-rs ++-------------------------------------------------+ +| +-------+ +---------+--html- | +| -markdown->+ parse +-events->+ compile + | +| +-------+ +---------+-mdast- | ++-------------------------------------------------+ +``` + +### File structure + +The files in `src/` are as follows: + +* `construct/*.rs` + — CommonMark, GFM, and other extension constructs used in markdown +* `util/*.rs` + — helpers often needed when parsing markdown +* `event.rs` + — things with meaning happening somewhere +* `lib.rs` + — public API +* `mdast.rs` + — syntax tree +* `parser.rs` + — turn a string of markdown into events +* `resolve.rs` + — steps to process events +* `state.rs` + — steps of the state machine +* `subtokenize.rs` + — handle content in other content +* `to_html.rs` + — turns events into a string of HTML +* `to_mdast.rs` + — turns events into a syntax tree +* `tokenizer.rs` + — glue the states of the state machine together +* `unist.rs` + — point and position, used in mdast + +### Test + +`markdown-rs` is tested with the \~650 CommonMark tests and more than 1k extra +tests confirmed with CM reference parsers. +Then there’s even more tests for GFM and other extensions. +These tests reach all branches in the code, +which means that this project has 100% code coverage. +Fuzz testing is used to check for things that might fall through coverage. + +The following bash scripts are useful when working on this project: + +* generate code (latest CM tests and Unicode info): + ```sh + cargo run --manifest-path generate/Cargo.toml + ``` +* run examples: + ```sh + RUST_BACKTRACE=1 RUST_LOG=trace cargo run --example lib --features log + ``` +* format: + ```sh + cargo fmt && cargo fix --all-features --all-targets --workspace + ``` +* lint: + ```sh + cargo fmt --check && cargo clippy --all-features --all-targets --workspace + ``` +* test: + ```sh + RUST_BACKTRACE=1 cargo test --all-features --workspace + ``` +* docs: + ```sh + cargo doc --document-private-items --examples --workspace + ``` +* fuzz: + ```sh + cargo install cargo-fuzz + cargo install honggfuzz + cargo +nightly fuzz run markdown_libfuzz + cargo hfuzz run markdown_honggfuzz + ``` + +### Version + +`markdown-rs` follows [SemVer](https://semver.org). + +### Security + +The typical security aspect discussed for markdown is [cross-site scripting +(XSS)][xss] attacks. +Markdown itself is safe if it does not include embedded HTML or dangerous +protocols in links/images (such as `javascript:`). +`markdown-rs` makes any markdown safe by default, +even if HTML is embedded or dangerous protocols are used, +as it encodes or drops them. + +Turning on the `allow_dangerous_html` or `allow_dangerous_protocol` options for +user-provided markdown opens you up to XSS attacks. + +Additionnally, +you should be able to set `allow_any_img_src` safely. +The default is to allow only `http:`, `https:`, and relative images, +which is what GitHub does. +But it should be safe to allow any value on `src`. + +The [HTML specification][whatwg-html-image] prohibits dangerous scripts in +images and all modern browsers respect this and are thus safe. +Opera 12 (from 2012) is a notable browser that did not respect this. + +An aspect related to XSS for security is syntax errors: +markdown itself has no syntax errors. +Some syntax extensions +(specifically, only MDX) +do include syntax errors. +For that reason, +`to_html_with_options` returns `Result`, +of which the error is a struct indicating where the problem happened, +what occurred, +and what was expected instead. +Make sure to handle your errors when using MDX. + +Another security aspect is DDoS attacks. +For example, +an attacker could throw a 100mb file at `markdown-rs`, +in which case it’s going to take a long while to finish. +It is also possible to crash `markdown-rs` with smaller payloads, +notably when thousands of +links, images, emphasis, or strong +are opened but not closed. +It is wise to cap the accepted size of input (500kb can hold a big book) and to +process content in a different thread so that it can be stopped when needed. + +For more information on markdown sanitation, +see +[`improper-markup-sanitization.md`][improper] by [**@chalker**][chalker]. + +### Contribute + +See [`contributing.md`][contributing] for ways to help. +See [`support.md`][support] for ways to get help. +See [`code-of-conduct.md`][coc] for how to communicate in and around this +project. + +### Sponsor + +Support this effort and give back by sponsoring: + +* [GitHub Sponsors](https://github.com/sponsors/wooorm) + (personal; monthly or one-time) +* [OpenCollective](https://opencollective.com/unified) or + [GitHub Sponsors](https://github.com/sponsors/unifiedjs) + (unified; monthly or one-time) + +### Thanks + +Special thanks go out to: + +* [Vercel][] for funding the initial development +* [**@Murderlon**][murderlon] for the design of the logo +* [**@johannhof**][johannhof] for the crate name + +## Related + +* [`micromark`][micromark] + — same as `markdown-rs` but in JavaScript +* [`mdxjs-rs`][mdxjs-rs] + — wraps `markdown-rs` to *compile* MDX to JavaScript + +## License + +[MIT][license] © [Titus Wormer][author] + +[badge-build-image]: https://github.com/wooorm/markdown-rs/workflows/main/badge.svg + +[badge-build-url]: https://github.com/wooorm/markdown-rs/actions + +[badge-coverage-image]: https://img.shields.io/codecov/c/github/wooorm/markdown-rs.svg + +[badge-coverage-url]: https://codecov.io/github/wooorm/markdown-rs + +[docs]: https://docs.rs/markdown/latest/markdown/ + +[crate]: https://crates.io/crates/markdown + +[repo]: https://github.com/wooorm/markdown-rs + +[discussions]: https://github.com/wooorm/markdown-rs/discussions + +[commonmark]: https://spec.commonmark.org + +[cheat]: https://commonmark.org/help/ + +[rust]: https://www.rust-lang.org + +[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting + +[improper]: https://github.com/ChALkeR/notes/blob/master/Improper-markup-sanitization.md + +[chalker]: https://github.com/ChALkeR + +[license]: license + +[author]: https://wooorm.com + +[mdast]: https://github.com/syntax-tree/mdast + +[micromark]: https://github.com/micromark/micromark + +[mdxjs-rs]: https://github.com/wooorm/mdxjs-rs + +[mdast-util-from-markdown]: https://github.com/syntax-tree/mdast-util-from-markdown + +[vercel]: https://vercel.com + +[murderlon]: https://github.com/murderlon + +[johannhof]: https://github.com/johannhof + +[contribute]: #contribute + +[sponsor]: #sponsor + +[extensions]: #extensions + +[security]: #security + +[test]: #test + +[contributing]: .github/contribute.md + +[support]: .github/support.md + +[coc]: .github/code-of-conduct.md + +[whatwg-html-image]: https://html.spec.whatwg.org/multipage/images.html#images-processing-model diff --git a/napi_binding/__tests__/parse.test.ts b/napi/__tests__/parse.test.ts similarity index 100% rename from napi_binding/__tests__/parse.test.ts rename to napi/__tests__/parse.test.ts diff --git a/napi/browser.js b/napi/browser.js new file mode 100644 index 00000000..bc4bd771 --- /dev/null +++ b/napi/browser.js @@ -0,0 +1 @@ +export * from 'markdown-rs-binding-wasm32-wasi' diff --git a/napi_binding/index.d.ts b/napi/index.d.ts similarity index 100% rename from napi_binding/index.d.ts rename to napi/index.d.ts diff --git a/napi/index.js b/napi/index.js new file mode 100644 index 00000000..d4d36fe1 --- /dev/null +++ b/napi/index.js @@ -0,0 +1,380 @@ +// prettier-ignore +/* eslint-disable */ +// @ts-nocheck +/* auto-generated by NAPI-RS */ + +const { createRequire } = require('node:module') +require = createRequire(__filename) + +const { readFileSync } = require('node:fs') +let nativeBinding = null +const loadErrors = [] + +const isMusl = () => { + let musl = false + if (process.platform === 'linux') { + musl = isMuslFromFilesystem() + if (musl === null) { + musl = isMuslFromReport() + } + if (musl === null) { + musl = isMuslFromChildProcess() + } + } + return musl +} + +const isFileMusl = (f) => f.includes('libc.musl-') || f.includes('ld-musl-') + +const isMuslFromFilesystem = () => { + try { + return readFileSync('/usr/bin/ldd', 'utf-8').includes('musl') + } catch { + return null + } +} + +const isMuslFromReport = () => { + let report = null + if (typeof process.report?.getReport === 'function') { + process.report.excludeNetwork = true + report = process.report.getReport() + } + if (!report) { + return null + } + if (report.header && report.header.glibcVersionRuntime) { + return false + } + if (Array.isArray(report.sharedObjects)) { + if (report.sharedObjects.some(isFileMusl)) { + return true + } + } + return false +} + +const isMuslFromChildProcess = () => { + try { + return require('child_process').execSync('ldd --version', { encoding: 'utf8' }).includes('musl') + } catch (e) { + // If we reach this case, we don't know if the system is musl or not, so is better to just fallback to false + return false + } +} + +function requireNative() { + if (process.env.NAPI_RS_NATIVE_LIBRARY_PATH) { + try { + nativeBinding = require(process.env.NAPI_RS_NATIVE_LIBRARY_PATH); + } catch (err) { + loadErrors.push(err) + } + } else if (process.platform === 'android') { + if (process.arch === 'arm64') { + try { + return require('./markdown-rs.android-arm64.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('markdown-rs-binding-android-arm64') + } catch (e) { + loadErrors.push(e) + } + + } else if (process.arch === 'arm') { + try { + return require('./markdown-rs.android-arm-eabi.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('markdown-rs-binding-android-arm-eabi') + } catch (e) { + loadErrors.push(e) + } + + } else { + loadErrors.push(new Error(`Unsupported architecture on Android ${process.arch}`)) + } + } else if (process.platform === 'win32') { + if (process.arch === 'x64') { + try { + return require('./markdown-rs.win32-x64-msvc.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('markdown-rs-binding-win32-x64-msvc') + } catch (e) { + loadErrors.push(e) + } + + } else if (process.arch === 'ia32') { + try { + return require('./markdown-rs.win32-ia32-msvc.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('markdown-rs-binding-win32-ia32-msvc') + } catch (e) { + loadErrors.push(e) + } + + } else if (process.arch === 'arm64') { + try { + return require('./markdown-rs.win32-arm64-msvc.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('markdown-rs-binding-win32-arm64-msvc') + } catch (e) { + loadErrors.push(e) + } + + } else { + loadErrors.push(new Error(`Unsupported architecture on Windows: ${process.arch}`)) + } + } else if (process.platform === 'darwin') { + try { + return require('./markdown-rs.darwin-universal.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('markdown-rs-binding-darwin-universal') + } catch (e) { + loadErrors.push(e) + } + + if (process.arch === 'x64') { + try { + return require('./markdown-rs.darwin-x64.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('markdown-rs-binding-darwin-x64') + } catch (e) { + loadErrors.push(e) + } + + } else if (process.arch === 'arm64') { + try { + return require('./markdown-rs.darwin-arm64.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('markdown-rs-binding-darwin-arm64') + } catch (e) { + loadErrors.push(e) + } + + } else { + loadErrors.push(new Error(`Unsupported architecture on macOS: ${process.arch}`)) + } + } else if (process.platform === 'freebsd') { + if (process.arch === 'x64') { + try { + return require('./markdown-rs.freebsd-x64.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('markdown-rs-binding-freebsd-x64') + } catch (e) { + loadErrors.push(e) + } + + } else if (process.arch === 'arm64') { + try { + return require('./markdown-rs.freebsd-arm64.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('markdown-rs-binding-freebsd-arm64') + } catch (e) { + loadErrors.push(e) + } + + } else { + loadErrors.push(new Error(`Unsupported architecture on FreeBSD: ${process.arch}`)) + } + } else if (process.platform === 'linux') { + if (process.arch === 'x64') { + if (isMusl()) { + try { + return require('./markdown-rs.linux-x64-musl.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('markdown-rs-binding-linux-x64-musl') + } catch (e) { + loadErrors.push(e) + } + + } else { + try { + return require('./markdown-rs.linux-x64-gnu.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('markdown-rs-binding-linux-x64-gnu') + } catch (e) { + loadErrors.push(e) + } + + } + } else if (process.arch === 'arm64') { + if (isMusl()) { + try { + return require('./markdown-rs.linux-arm64-musl.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('markdown-rs-binding-linux-arm64-musl') + } catch (e) { + loadErrors.push(e) + } + + } else { + try { + return require('./markdown-rs.linux-arm64-gnu.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('markdown-rs-binding-linux-arm64-gnu') + } catch (e) { + loadErrors.push(e) + } + + } + } else if (process.arch === 'arm') { + if (isMusl()) { + try { + return require('./markdown-rs.linux-arm-musleabihf.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('markdown-rs-binding-linux-arm-musleabihf') + } catch (e) { + loadErrors.push(e) + } + + } else { + try { + return require('./markdown-rs.linux-arm-gnueabihf.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('markdown-rs-binding-linux-arm-gnueabihf') + } catch (e) { + loadErrors.push(e) + } + + } + } else if (process.arch === 'riscv64') { + if (isMusl()) { + try { + return require('./markdown-rs.linux-riscv64-musl.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('markdown-rs-binding-linux-riscv64-musl') + } catch (e) { + loadErrors.push(e) + } + + } else { + try { + return require('./markdown-rs.linux-riscv64-gnu.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('markdown-rs-binding-linux-riscv64-gnu') + } catch (e) { + loadErrors.push(e) + } + + } + } else if (process.arch === 'ppc64') { + try { + return require('./markdown-rs.linux-ppc64-gnu.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('markdown-rs-binding-linux-ppc64-gnu') + } catch (e) { + loadErrors.push(e) + } + + } else if (process.arch === 's390x') { + try { + return require('./markdown-rs.linux-s390x-gnu.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('markdown-rs-binding-linux-s390x-gnu') + } catch (e) { + loadErrors.push(e) + } + + } else { + loadErrors.push(new Error(`Unsupported architecture on Linux: ${process.arch}`)) + } + } else { + loadErrors.push(new Error(`Unsupported OS: ${process.platform}, architecture: ${process.arch}`)) + } +} + +nativeBinding = requireNative() + +if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) { + try { + nativeBinding = require('./markdown-rs.wasi.cjs') + } catch (err) { + if (process.env.NAPI_RS_FORCE_WASI) { + loadErrors.push(err) + } + } + if (!nativeBinding) { + try { + nativeBinding = require('markdown-rs-binding-wasm32-wasi') + } catch (err) { + if (process.env.NAPI_RS_FORCE_WASI) { + loadErrors.push(err) + } + } + } +} + +if (!nativeBinding) { + if (loadErrors.length > 0) { + throw new Error( + `Cannot find native binding. ` + + `npm has a bug related to optional dependencies (https://github.com/npm/cli/issues/4828). ` + + 'Please try `npm i` again after removing both package-lock.json and node_modules directory.', + { cause: loadErrors } + ) + } + throw new Error(`Failed to load native binding`) +} + +module.exports = nativeBinding +module.exports.parse = nativeBinding.parse +module.exports.parseMdx = nativeBinding.parseMdx diff --git a/napi/markdown-rs.wasi-browser.js b/napi/markdown-rs.wasi-browser.js new file mode 100644 index 00000000..db2a630c --- /dev/null +++ b/napi/markdown-rs.wasi-browser.js @@ -0,0 +1,58 @@ +import { + createOnMessage as __wasmCreateOnMessageForFsProxy, + getDefaultContext as __emnapiGetDefaultContext, + instantiateNapiModuleSync as __emnapiInstantiateNapiModuleSync, + WASI as __WASI, +} from '@napi-rs/wasm-runtime' + + +const __wasi = new __WASI({ + version: 'preview1', +}) + +const __wasmUrl = new URL('./markdown-rs.wasm32-wasi.wasm', import.meta.url).href +const __emnapiContext = __emnapiGetDefaultContext() + +const __sharedMemory = new WebAssembly.Memory({ + initial: 16384, + maximum: 65536, + shared: true, +}) + +const __wasmFile = await fetch(__wasmUrl).then((res) => res.arrayBuffer()) + +const { + instance: __napiInstance, + module: __wasiModule, + napiModule: __napiModule, +} = __emnapiInstantiateNapiModuleSync(__wasmFile, { + context: __emnapiContext, + asyncWorkPoolSize: 4, + wasi: __wasi, + onCreateWorker() { + const worker = new Worker(new URL('./wasi-worker-browser.mjs', import.meta.url), { + type: 'module', + }) + + return worker + }, + overwriteImports(importObject) { + importObject.env = { + ...importObject.env, + ...importObject.napi, + ...importObject.emnapi, + memory: __sharedMemory, + } + return importObject + }, + beforeInit({ instance }) { + for (const name of Object.keys(instance.exports)) { + if (name.startsWith('__napi_register__')) { + instance.exports[name]() + } + } + }, +}) +export default __napiModule.exports +export const parse = __napiModule.exports.parse +export const parseMdx = __napiModule.exports.parseMdx diff --git a/napi/markdown-rs.wasi.cjs b/napi/markdown-rs.wasi.cjs new file mode 100644 index 00000000..c4541d1b --- /dev/null +++ b/napi/markdown-rs.wasi.cjs @@ -0,0 +1,89 @@ +/* eslint-disable */ +/* prettier-ignore */ + +/* auto-generated by NAPI-RS */ + +const __nodeFs = require('node:fs') +const __nodePath = require('node:path') +const { WASI: __nodeWASI } = require('node:wasi') +const { Worker } = require('node:worker_threads') + +const { + createOnMessage: __wasmCreateOnMessageForFsProxy, + getDefaultContext: __emnapiGetDefaultContext, + instantiateNapiModuleSync: __emnapiInstantiateNapiModuleSync, +} = require('@napi-rs/wasm-runtime') + +const __rootDir = __nodePath.parse(process.cwd()).root + +const __wasi = new __nodeWASI({ + version: 'preview1', + env: process.env, + preopens: { + [__rootDir]: __rootDir, + } +}) + +const __emnapiContext = __emnapiGetDefaultContext() + +const __sharedMemory = new WebAssembly.Memory({ + initial: 16384, + maximum: 65536, + shared: true, +}) + +let __wasmFilePath = __nodePath.join(__dirname, 'markdown-rs.wasm32-wasi.wasm') +const __wasmDebugFilePath = __nodePath.join(__dirname, 'markdown-rs.wasm32-wasi.debug.wasm') + +if (__nodeFs.existsSync(__wasmDebugFilePath)) { + __wasmFilePath = __wasmDebugFilePath +} else if (!__nodeFs.existsSync(__wasmFilePath)) { + try { + __wasmFilePath = __nodePath.resolve('markdown-rs-binding-wasm32-wasi') + } catch { + throw new Error('Cannot find markdown-rs.wasm32-wasi.wasm file, and markdown-rs-binding-wasm32-wasi package is not installed.') + } +} + +const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule } = __emnapiInstantiateNapiModuleSync(__nodeFs.readFileSync(__wasmFilePath), { + context: __emnapiContext, + asyncWorkPoolSize: (function() { + const threadsSizeFromEnv = Number(process.env.NAPI_RS_ASYNC_WORK_POOL_SIZE ?? process.env.UV_THREADPOOL_SIZE) + // NaN > 0 is false + if (threadsSizeFromEnv > 0) { + return threadsSizeFromEnv + } else { + return 4 + } + })(), + reuseWorker: true, + wasi: __wasi, + onCreateWorker() { + const worker = new Worker(__nodePath.join(__dirname, 'wasi-worker.mjs'), { + env: process.env, + }) + worker.onmessage = ({ data }) => { + __wasmCreateOnMessageForFsProxy(__nodeFs)(data) + } + return worker + }, + overwriteImports(importObject) { + importObject.env = { + ...importObject.env, + ...importObject.napi, + ...importObject.emnapi, + memory: __sharedMemory, + } + return importObject + }, + beforeInit({ instance }) { + for (const name of Object.keys(instance.exports)) { + if (name.startsWith('__napi_register__')) { + instance.exports[name]() + } + } + }, +}) +module.exports = __napiModule.exports +module.exports.parse = __napiModule.exports.parse +module.exports.parseMdx = __napiModule.exports.parseMdx diff --git a/napi/package.json b/napi/package.json new file mode 100644 index 00000000..1ba8756b --- /dev/null +++ b/napi/package.json @@ -0,0 +1,53 @@ +{ + "name": "@xmorse/markdown-rs", + "version": "0.0.0", + "scripts": { + "build:debug": "napi build --platform --manifest-path napi/Cargo.toml", + "build": "pnpm run build:debug --release", + "npm-dirs": "pnpm napi create-npm-dirs --package-json-path package.json", + "pre-publish": "pnpm napi pre-publish --no-gh-release --tagstyle npm --package-json-path package.json --npm-dir npm && cp package.json napi/package.json && cp README.md napi/README.md", + "artifacts": "pnpm napi artifacts --npm-dir npm --build-output-dir napi" + }, + "napi": { + "binaryName": "markdown-rs", + "packageName": "@xmorse/markdown-rs-binding", + "targets": [ + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-linux-musl", + "x86_64-unknown-freebsd", + "i686-pc-windows-msvc", + "armv7-unknown-linux-gnueabihf", + "aarch64-unknown-linux-gnu", + "aarch64-apple-darwin", + "aarch64-unknown-linux-musl", + "aarch64-pc-windows-msvc", + "wasm32-wasip1-threads" + ], + "wasm": { + "initialMemory": 16384 + } + }, + "devDependencies": { + "@emnapi/runtime": "^1.4.3", + "@napi-rs/wasm-runtime": "^0.2.7", + "@napi-rs/cli": "3.0.0-alpha.89", + "emnapi": "^1.4.3", + "vitest": "^1.5.0" + }, + "optionalDependencies": { + "@xmorse/markdown-rs-binding-darwin-x64": "0.0.0", + "@xmorse/markdown-rs-binding-win32-x64-msvc": "0.0.0", + "@xmorse/markdown-rs-binding-linux-x64-gnu": "0.0.0", + "@xmorse/markdown-rs-binding-linux-x64-musl": "0.0.0", + "@xmorse/markdown-rs-binding-freebsd-x64": "0.0.0", + "@xmorse/markdown-rs-binding-win32-ia32-msvc": "0.0.0", + "@xmorse/markdown-rs-binding-linux-arm-gnueabihf": "0.0.0", + "@xmorse/markdown-rs-binding-linux-arm64-gnu": "0.0.0", + "@xmorse/markdown-rs-binding-darwin-arm64": "0.0.0", + "@xmorse/markdown-rs-binding-linux-arm64-musl": "0.0.0", + "@xmorse/markdown-rs-binding-win32-arm64-msvc": "0.0.0", + "@xmorse/markdown-rs-binding-wasm32-wasi": "0.0.0" + } +} \ No newline at end of file diff --git a/napi_binding/src/lib.rs b/napi/src/lib.rs similarity index 100% rename from napi_binding/src/lib.rs rename to napi/src/lib.rs diff --git a/napi/wasi-worker-browser.mjs b/napi/wasi-worker-browser.mjs new file mode 100644 index 00000000..8b1b1722 --- /dev/null +++ b/napi/wasi-worker-browser.mjs @@ -0,0 +1,32 @@ +import { instantiateNapiModuleSync, MessageHandler, WASI } from '@napi-rs/wasm-runtime' + +const handler = new MessageHandler({ + onLoad({ wasmModule, wasmMemory }) { + const wasi = new WASI({ + print: function () { + // eslint-disable-next-line no-console + console.log.apply(console, arguments) + }, + printErr: function() { + // eslint-disable-next-line no-console + console.error.apply(console, arguments) + }, + }) + return instantiateNapiModuleSync(wasmModule, { + childThread: true, + wasi, + overwriteImports(importObject) { + importObject.env = { + ...importObject.env, + ...importObject.napi, + ...importObject.emnapi, + memory: wasmMemory, + } + }, + }) + }, +}) + +globalThis.onmessage = function (e) { + handler.handle(e) +} diff --git a/napi/wasi-worker.mjs b/napi/wasi-worker.mjs new file mode 100644 index 00000000..84b448fc --- /dev/null +++ b/napi/wasi-worker.mjs @@ -0,0 +1,63 @@ +import fs from "node:fs"; +import { createRequire } from "node:module"; +import { parse } from "node:path"; +import { WASI } from "node:wasi"; +import { parentPort, Worker } from "node:worker_threads"; + +const require = createRequire(import.meta.url); + +const { instantiateNapiModuleSync, MessageHandler, getDefaultContext } = require("@napi-rs/wasm-runtime"); + +if (parentPort) { + parentPort.on("message", (data) => { + globalThis.onmessage({ data }); + }); +} + +Object.assign(globalThis, { + self: globalThis, + require, + Worker, + importScripts: function (f) { + ;(0, eval)(fs.readFileSync(f, "utf8") + "//# sourceURL=" + f); + }, + postMessage: function (msg) { + if (parentPort) { + parentPort.postMessage(msg); + } + }, +}); + +const emnapiContext = getDefaultContext(); + +const __rootDir = parse(process.cwd()).root; + +const handler = new MessageHandler({ + onLoad({ wasmModule, wasmMemory }) { + const wasi = new WASI({ + version: 'preview1', + env: process.env, + preopens: { + [__rootDir]: __rootDir, + }, + }); + + return instantiateNapiModuleSync(wasmModule, { + childThread: true, + wasi, + context: emnapiContext, + overwriteImports(importObject) { + importObject.env = { + ...importObject.env, + ...importObject.napi, + ...importObject.emnapi, + memory: wasmMemory + }; + }, + }); + }, +}); + +globalThis.onmessage = function (e) { + handler.handle(e); +}; diff --git a/napi_binding/package.json b/napi_binding/package.json deleted file mode 100644 index 4017f25e..00000000 --- a/napi_binding/package.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "markdown-napi", - "version": "0.1.0", - "scripts": { - "build": "rm -rf out && pnpm napi build --release -o out", - "build:wasm": "napi build --release --target wasm32-wasip1-threads --no-const-enum", - "build:platform": "napi build --platform --release --no-const-enum", - "test": "vitest" - }, - "napi": { - - "targets": [ - "x86_64-apple-darwin", - "x86_64-pc-windows-msvc", - "x86_64-unknown-linux-gnu", - "x86_64-unknown-linux-musl", - "x86_64-unknown-freebsd", - "i686-pc-windows-msvc", - "armv7-unknown-linux-gnueabihf", - "aarch64-unknown-linux-gnu", - "aarch64-apple-darwin", - "aarch64-unknown-linux-musl", - "aarch64-pc-windows-msvc", - "wasm32-wasip1-threads" - ], - "wasm": { - "initialMemory": 16384 - } - }, - "devDependencies": { - "@emnapi/runtime": "^1.4.3", - "@napi-rs/wasm-runtime": "^0.2.7", - - "@napi-rs/cli": "3.0.0-alpha.89", - "emnapi": "^1.4.3", - "vitest": "^1.5.0" - } -} diff --git a/package.json b/package.json new file mode 100644 index 00000000..1ba8756b --- /dev/null +++ b/package.json @@ -0,0 +1,53 @@ +{ + "name": "@xmorse/markdown-rs", + "version": "0.0.0", + "scripts": { + "build:debug": "napi build --platform --manifest-path napi/Cargo.toml", + "build": "pnpm run build:debug --release", + "npm-dirs": "pnpm napi create-npm-dirs --package-json-path package.json", + "pre-publish": "pnpm napi pre-publish --no-gh-release --tagstyle npm --package-json-path package.json --npm-dir npm && cp package.json napi/package.json && cp README.md napi/README.md", + "artifacts": "pnpm napi artifacts --npm-dir npm --build-output-dir napi" + }, + "napi": { + "binaryName": "markdown-rs", + "packageName": "@xmorse/markdown-rs-binding", + "targets": [ + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-linux-musl", + "x86_64-unknown-freebsd", + "i686-pc-windows-msvc", + "armv7-unknown-linux-gnueabihf", + "aarch64-unknown-linux-gnu", + "aarch64-apple-darwin", + "aarch64-unknown-linux-musl", + "aarch64-pc-windows-msvc", + "wasm32-wasip1-threads" + ], + "wasm": { + "initialMemory": 16384 + } + }, + "devDependencies": { + "@emnapi/runtime": "^1.4.3", + "@napi-rs/wasm-runtime": "^0.2.7", + "@napi-rs/cli": "3.0.0-alpha.89", + "emnapi": "^1.4.3", + "vitest": "^1.5.0" + }, + "optionalDependencies": { + "@xmorse/markdown-rs-binding-darwin-x64": "0.0.0", + "@xmorse/markdown-rs-binding-win32-x64-msvc": "0.0.0", + "@xmorse/markdown-rs-binding-linux-x64-gnu": "0.0.0", + "@xmorse/markdown-rs-binding-linux-x64-musl": "0.0.0", + "@xmorse/markdown-rs-binding-freebsd-x64": "0.0.0", + "@xmorse/markdown-rs-binding-win32-ia32-msvc": "0.0.0", + "@xmorse/markdown-rs-binding-linux-arm-gnueabihf": "0.0.0", + "@xmorse/markdown-rs-binding-linux-arm64-gnu": "0.0.0", + "@xmorse/markdown-rs-binding-darwin-arm64": "0.0.0", + "@xmorse/markdown-rs-binding-linux-arm64-musl": "0.0.0", + "@xmorse/markdown-rs-binding-win32-arm64-msvc": "0.0.0", + "@xmorse/markdown-rs-binding-wasm32-wasi": "0.0.0" + } +} \ No newline at end of file diff --git a/napi_binding/pnpm-lock.yaml b/pnpm-lock.yaml similarity index 100% rename from napi_binding/pnpm-lock.yaml rename to pnpm-lock.yaml diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 00000000..f78a9757 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,3 @@ +packages: + - npm + - napi From ddbf3aef85f2b1d5a3db455a218489698a65fe0e Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 14:10:00 +0200 Subject: [PATCH 05/61] Update package.json --- package.json | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 1ba8756b..51c31c75 100644 --- a/package.json +++ b/package.json @@ -36,18 +36,5 @@ "emnapi": "^1.4.3", "vitest": "^1.5.0" }, - "optionalDependencies": { - "@xmorse/markdown-rs-binding-darwin-x64": "0.0.0", - "@xmorse/markdown-rs-binding-win32-x64-msvc": "0.0.0", - "@xmorse/markdown-rs-binding-linux-x64-gnu": "0.0.0", - "@xmorse/markdown-rs-binding-linux-x64-musl": "0.0.0", - "@xmorse/markdown-rs-binding-freebsd-x64": "0.0.0", - "@xmorse/markdown-rs-binding-win32-ia32-msvc": "0.0.0", - "@xmorse/markdown-rs-binding-linux-arm-gnueabihf": "0.0.0", - "@xmorse/markdown-rs-binding-linux-arm64-gnu": "0.0.0", - "@xmorse/markdown-rs-binding-darwin-arm64": "0.0.0", - "@xmorse/markdown-rs-binding-linux-arm64-musl": "0.0.0", - "@xmorse/markdown-rs-binding-win32-arm64-msvc": "0.0.0", - "@xmorse/markdown-rs-binding-wasm32-wasi": "0.0.0" - } -} \ No newline at end of file + "packageManager": "pnpm@10.12.1" +} From 00d9dad3caf35f801cae42f5cbda05135a03d6d1 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 14:11:09 +0200 Subject: [PATCH 06/61] Create .node-version --- .node-version | 1 + 1 file changed, 1 insertion(+) create mode 100644 .node-version diff --git a/.node-version b/.node-version new file mode 100644 index 00000000..517f3866 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +v22.14.0 From 6f96c73571b47c67054c70f82e536bec3a84a8e9 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 14:12:44 +0200 Subject: [PATCH 07/61] Update release-napi.yml --- .github/workflows/release-napi.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release-napi.yml b/.github/workflows/release-napi.yml index 09c622cb..aa2f1522 100644 --- a/.github/workflows/release-napi.yml +++ b/.github/workflows/release-napi.yml @@ -7,8 +7,8 @@ on: push: # branches: # - main - paths: - - package.json + # paths: + # - package.json concurrency: group: ${{ github.workflow }}-${{ github.ref }} From eeb9d07eea35dbf5be7d5bc0df8dfb49c6b0d87c Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 14:16:33 +0200 Subject: [PATCH 08/61] use setup node from actions --- .github/workflows/release-napi.yml | 13 ++++++++----- .node-version | 1 - 2 files changed, 8 insertions(+), 6 deletions(-) delete mode 100644 .node-version diff --git a/.github/workflows/release-napi.yml b/.github/workflows/release-napi.yml index aa2f1522..de7cd0df 100644 --- a/.github/workflows/release-napi.yml +++ b/.github/workflows/release-napi.yml @@ -116,8 +116,10 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: taiki-e/checkout-action@b13d20b7cda4e2f325ef19895128f7ff735c0b3d # v1.3.1 - - uses: oxc-project/setup-node@f42e3bda950c7454575e78ee4eaac880a077700c # v1.0.0 - - run: pnpm i + - uses: actions/setup-node@v4 + with: + node-version: 22 + - uses: pnpm/action-setup@v4 - run: rustup target add ${{ matrix.target }} @@ -141,8 +143,6 @@ jobs: napi/*.node napi/*.wasm - - publish: name: Publish NAPI runs-on: ubuntu-latest @@ -153,7 +153,10 @@ jobs: steps: - uses: taiki-e/checkout-action@b13d20b7cda4e2f325ef19895128f7ff735c0b3d # v1.3.1 - - uses: oxc-project/setup-node@f42e3bda950c7454575e78ee4eaac880a077700c # v1.0.0 + - uses: actions/setup-node@v4 + with: + node-version: 22 + - uses: pnpm/action-setup@v4 - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: diff --git a/.node-version b/.node-version deleted file mode 100644 index 517f3866..00000000 --- a/.node-version +++ /dev/null @@ -1 +0,0 @@ -v22.14.0 From b163178e054a7536f57b2849356fda4ead3a89c9 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 14:19:05 +0200 Subject: [PATCH 09/61] package.json --- napi/package.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/napi/package.json b/napi/package.json index 1ba8756b..17313197 100644 --- a/napi/package.json +++ b/napi/package.json @@ -2,7 +2,7 @@ "name": "@xmorse/markdown-rs", "version": "0.0.0", "scripts": { - "build:debug": "napi build --platform --manifest-path napi/Cargo.toml", + "build:debug": "pnpm napi build --platform --manifest-path napi/Cargo.toml", "build": "pnpm run build:debug --release", "npm-dirs": "pnpm napi create-npm-dirs --package-json-path package.json", "pre-publish": "pnpm napi pre-publish --no-gh-release --tagstyle npm --package-json-path package.json --npm-dir npm && cp package.json napi/package.json && cp README.md napi/README.md", @@ -50,4 +50,4 @@ "@xmorse/markdown-rs-binding-win32-arm64-msvc": "0.0.0", "@xmorse/markdown-rs-binding-wasm32-wasi": "0.0.0" } -} \ No newline at end of file +} diff --git a/package.json b/package.json index 51c31c75..d68a1d8d 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@xmorse/markdown-rs", "version": "0.0.0", "scripts": { - "build:debug": "napi build --platform --manifest-path napi/Cargo.toml", + "build:debug": "pnpm napi build --platform --manifest-path napi/Cargo.toml", "build": "pnpm run build:debug --release", "npm-dirs": "pnpm napi create-npm-dirs --package-json-path package.json", "pre-publish": "pnpm napi pre-publish --no-gh-release --tagstyle npm --package-json-path package.json --npm-dir npm && cp package.json napi/package.json && cp README.md napi/README.md", From c67a78adaa601e6be1bbce0e80d5c35bce90a1f3 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 14:30:36 +0200 Subject: [PATCH 10/61] Update release-napi.yml --- .github/workflows/release-napi.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release-napi.yml b/.github/workflows/release-napi.yml index de7cd0df..859bff6e 100644 --- a/.github/workflows/release-napi.yml +++ b/.github/workflows/release-napi.yml @@ -120,6 +120,7 @@ jobs: with: node-version: 22 - uses: pnpm/action-setup@v4 + - run: pnpm i -g @napi-rs/cli@alpha - run: rustup target add ${{ matrix.target }} From 0923d3e819bea9cff1e3db4cf75216304785a277 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 14:31:00 +0200 Subject: [PATCH 11/61] Update release-napi.yml --- .github/workflows/release-napi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-napi.yml b/.github/workflows/release-napi.yml index 859bff6e..f01f599a 100644 --- a/.github/workflows/release-napi.yml +++ b/.github/workflows/release-napi.yml @@ -120,7 +120,7 @@ jobs: with: node-version: 22 - uses: pnpm/action-setup@v4 - - run: pnpm i -g @napi-rs/cli@alpha + - run: pnpm i -g @napi-rs/cli@canary - run: rustup target add ${{ matrix.target }} From ee9234956635738c9a4e6858e9d171094e9a2961 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 14:39:27 +0200 Subject: [PATCH 12/61] Update release-napi.yml --- .github/workflows/release-napi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-napi.yml b/.github/workflows/release-napi.yml index f01f599a..3040cff8 100644 --- a/.github/workflows/release-napi.yml +++ b/.github/workflows/release-napi.yml @@ -120,7 +120,7 @@ jobs: with: node-version: 22 - uses: pnpm/action-setup@v4 - - run: pnpm i -g @napi-rs/cli@canary + - run: pnpm i - run: rustup target add ${{ matrix.target }} From de77211ff5ec3021b19156391626513dc9bfbeaa Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 14:41:52 +0200 Subject: [PATCH 13/61] package --- .github/workflows/release-napi.yml | 2 +- pnpm-lock.yaml | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-napi.yml b/.github/workflows/release-napi.yml index 3040cff8..b4b239d9 100644 --- a/.github/workflows/release-napi.yml +++ b/.github/workflows/release-napi.yml @@ -120,7 +120,7 @@ jobs: with: node-version: 22 - uses: pnpm/action-setup@v4 - - run: pnpm i + - run: pnpm i --frozen-lockfile=false - run: rustup target add ${{ matrix.target }} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2df363d0..bcb6c3d3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,6 +24,24 @@ importers: specifier: ^1.5.0 version: 1.6.1 + napi: + devDependencies: + '@emnapi/runtime': + specifier: ^1.4.3 + version: 1.4.3 + '@napi-rs/cli': + specifier: 3.0.0-alpha.89 + version: 3.0.0-alpha.89(@emnapi/runtime@1.4.3)(emnapi@1.4.3) + '@napi-rs/wasm-runtime': + specifier: ^0.2.7 + version: 0.2.11 + emnapi: + specifier: ^1.4.3 + version: 1.4.3 + vitest: + specifier: ^1.5.0 + version: 1.6.1 + packages: '@emnapi/core@1.4.3': From 5c78406df03857b8861d9f742bc1fc9c6b6c3031 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 14:43:46 +0200 Subject: [PATCH 14/61] Update package.json --- package.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/package.json b/package.json index d68a1d8d..78173f90 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,14 @@ "pre-publish": "pnpm napi pre-publish --no-gh-release --tagstyle npm --package-json-path package.json --npm-dir npm && cp package.json napi/package.json && cp README.md napi/README.md", "artifacts": "pnpm napi artifacts --npm-dir npm --build-output-dir napi" }, + "main": "index.js", + "browser": "browser.js", + "files": [ + "index.d.ts", + "index.js", + "browser.js", + "webcontainer-fallback.js" + ], "napi": { "binaryName": "markdown-rs", "packageName": "@xmorse/markdown-rs-binding", From 368f47b4543645fe8370d8ce4da27a6ebe1c1ec1 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 14:53:14 +0200 Subject: [PATCH 15/61] package --- .github/workflows/release-napi.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release-napi.yml b/.github/workflows/release-napi.yml index b4b239d9..b6cabe07 100644 --- a/.github/workflows/release-napi.yml +++ b/.github/workflows/release-napi.yml @@ -158,6 +158,7 @@ jobs: with: node-version: 22 - uses: pnpm/action-setup@v4 + - run: pnpm i --frozen-lockfile=false - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: From d2d168982a31577012bfed5f937d6fd31b765869 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 14:54:18 +0200 Subject: [PATCH 16/61] Update pnpm-workspace.yaml --- pnpm-workspace.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index f78a9757..962d95d8 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,5 @@ packages: - npm - napi + +neverBuiltDependencies: [] From c43301d5c08c6d644f43b61e356800fdcdd9d6bc Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 14:59:10 +0200 Subject: [PATCH 17/61] disable windows for now --- .github/workflows/release-napi.yml | 18 +++++++++--------- package.json | 1 - 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/.github/workflows/release-napi.yml b/.github/workflows/release-napi.yml index b6cabe07..20e6e87a 100644 --- a/.github/workflows/release-napi.yml +++ b/.github/workflows/release-napi.yml @@ -47,15 +47,15 @@ jobs: fail-fast: false matrix: include: - - os: windows-latest - target: x86_64-pc-windows-msvc - build: | - pnpm build --target x86_64-pc-windows-msvc - - - os: windows-latest - target: aarch64-pc-windows-msvc - build: | - pnpm build --target aarch64-pc-windows-msvc + # - os: windows-latest + # target: x86_64-pc-windows-msvc + # build: | + # pnpm build --target x86_64-pc-windows-msvc + + # - os: windows-latest + # target: aarch64-pc-windows-msvc + # build: | + # pnpm build --target aarch64-pc-windows-msvc - os: ubuntu-latest target: x86_64-unknown-linux-gnu diff --git a/package.json b/package.json index 78173f90..6c3aaeb2 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,6 @@ "webcontainer-fallback.js" ], "napi": { - "binaryName": "markdown-rs", "packageName": "@xmorse/markdown-rs-binding", "targets": [ "x86_64-apple-darwin", From 0c24e1f9f0ea227e0bc92d8def594a0f99cdabfd Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 15:02:28 +0200 Subject: [PATCH 18/61] fix root package.json --- package.json | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 6c3aaeb2..d2bd5d73 100644 --- a/package.json +++ b/package.json @@ -19,17 +19,16 @@ "napi": { "packageName": "@xmorse/markdown-rs-binding", "targets": [ - "x86_64-apple-darwin", - "x86_64-pc-windows-msvc", "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl", "x86_64-unknown-freebsd", - "i686-pc-windows-msvc", - "armv7-unknown-linux-gnueabihf", "aarch64-unknown-linux-gnu", - "aarch64-apple-darwin", "aarch64-unknown-linux-musl", - "aarch64-pc-windows-msvc", + "armv7-unknown-linux-gnueabihf", + "s390x-unknown-linux-gnu", + "riscv64gc-unknown-linux-gnu", + "x86_64-apple-darwin", + "aarch64-apple-darwin", "wasm32-wasip1-threads" ], "wasm": { From cc68c55331fdba482fc71d3e31bc75b0bc2365a7 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 15:09:52 +0200 Subject: [PATCH 19/61] workaround napi-rs bug with - --- .github/workflows/release-napi.yml | 1 + package.json | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-napi.yml b/.github/workflows/release-napi.yml index 20e6e87a..af120877 100644 --- a/.github/workflows/release-napi.yml +++ b/.github/workflows/release-napi.yml @@ -47,6 +47,7 @@ jobs: fail-fast: false matrix: include: + # TODO add in package.json "x86_64-pc-windows-msvc","aarch64-pc-windows-msvc", # - os: windows-latest # target: x86_64-pc-windows-msvc # build: | diff --git a/package.json b/package.json index d2bd5d73..dbd6a96a 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "webcontainer-fallback.js" ], "napi": { - "packageName": "@xmorse/markdown-rs-binding", + "binaryName": "markdownrs", + "packageName": "@xmorse/markdownrs", "targets": [ "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl", From b14cf0ca5525b605a6b5e2f62c7e0d36db8ad66a Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 15:16:25 +0200 Subject: [PATCH 20/61] lock to older version --- package.json | 3 +-- pnpm-lock.yaml | 48 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index dbd6a96a..e262d222 100644 --- a/package.json +++ b/package.json @@ -37,9 +37,8 @@ } }, "devDependencies": { - "@emnapi/runtime": "^1.4.3", + "@napi-rs/cli": "3.0.0-alpha.88", "@napi-rs/wasm-runtime": "^0.2.7", - "@napi-rs/cli": "3.0.0-alpha.89", "emnapi": "^1.4.3", "vitest": "^1.5.0" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bcb6c3d3..58b89ddb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,12 +8,9 @@ importers: .: devDependencies: - '@emnapi/runtime': - specifier: ^1.4.3 - version: 1.4.3 '@napi-rs/cli': - specifier: 3.0.0-alpha.89 - version: 3.0.0-alpha.89(@emnapi/runtime@1.4.3)(emnapi@1.4.3) + specifier: 3.0.0-alpha.88 + version: 3.0.0-alpha.88(@emnapi/runtime@1.4.3)(emnapi@1.4.3) '@napi-rs/wasm-runtime': specifier: ^0.2.7 version: 0.2.11 @@ -319,6 +316,19 @@ packages: '@jridgewell/sourcemap-codec@1.5.0': resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@napi-rs/cli@3.0.0-alpha.88': + resolution: {integrity: sha512-tAzLbGY+7JhRwAfeykv/Rl44mq3rufJzV5MuVQ2Nr+bMq6fr8winy0kV/myACDtYiXYx5Ax+XMHBKiLU2Xw5Ng==} + engines: {node: '>= 16'} + hasBin: true + peerDependencies: + '@emnapi/runtime': ^1.1.0 + emnapi: ^1.1.0 + peerDependenciesMeta: + '@emnapi/runtime': + optional: true + emnapi: + optional: true + '@napi-rs/cli@3.0.0-alpha.89': resolution: {integrity: sha512-Xi/B/unPVZJx12Qmj9+Z3+vfgmGdhp2tjtvH1VFjC6VrToh/i1fOBSv77j9WhYYWayFGhIit7nLcxQWxigXr8A==} engines: {node: '>= 16'} @@ -1423,6 +1433,34 @@ snapshots: '@jridgewell/sourcemap-codec@1.5.0': {} + '@napi-rs/cli@3.0.0-alpha.88(@emnapi/runtime@1.4.3)(emnapi@1.4.3)': + dependencies: + '@inquirer/prompts': 7.5.3 + '@napi-rs/cross-toolchain': 0.0.19 + '@napi-rs/wasm-tools': 0.0.3 + '@octokit/rest': 22.0.0 + clipanion: 4.0.0-rc.4(typanion@3.14.0) + colorette: 2.0.20 + debug: 4.4.1 + js-yaml: 4.1.0 + lodash-es: 4.17.21 + semver: 7.7.2 + toml: 3.0.0 + typanion: 3.14.0 + wasm-sjlj: 1.0.6 + optionalDependencies: + '@emnapi/runtime': 1.4.3 + emnapi: 1.4.3 + transitivePeerDependencies: + - '@napi-rs/cross-toolchain-arm64-target-aarch64' + - '@napi-rs/cross-toolchain-arm64-target-armv7' + - '@napi-rs/cross-toolchain-arm64-target-x86_64' + - '@napi-rs/cross-toolchain-x64-target-aarch64' + - '@napi-rs/cross-toolchain-x64-target-armv7' + - '@napi-rs/cross-toolchain-x64-target-x86_64' + - '@types/node' + - supports-color + '@napi-rs/cli@3.0.0-alpha.89(@emnapi/runtime@1.4.3)(emnapi@1.4.3)': dependencies: '@inquirer/prompts': 7.5.3 From 2acdf127fa11ed864e941550a43302e991c1ea98 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 15:19:11 +0200 Subject: [PATCH 21/61] run build once --- napi/browser.js | 2 +- napi/index.js | 95 ++++++++++++++++----------------- napi/markdownrs.wasi-browser.js | 58 ++++++++++++++++++++ napi/markdownrs.wasi.cjs | 89 ++++++++++++++++++++++++++++++ 4 files changed, 195 insertions(+), 49 deletions(-) create mode 100644 napi/markdownrs.wasi-browser.js create mode 100644 napi/markdownrs.wasi.cjs diff --git a/napi/browser.js b/napi/browser.js index bc4bd771..ea7f0c3d 100644 --- a/napi/browser.js +++ b/napi/browser.js @@ -1 +1 @@ -export * from 'markdown-rs-binding-wasm32-wasi' +export * from '@xmorse/markdownrs-wasm32-wasi' diff --git a/napi/index.js b/napi/index.js index d4d36fe1..73f78e20 100644 --- a/napi/index.js +++ b/napi/index.js @@ -73,24 +73,24 @@ function requireNative() { } else if (process.platform === 'android') { if (process.arch === 'arm64') { try { - return require('./markdown-rs.android-arm64.node') + return require('./markdownrs.android-arm64.node') } catch (e) { loadErrors.push(e) } try { - return require('markdown-rs-binding-android-arm64') + return require('@xmorse/markdownrs-android-arm64') } catch (e) { loadErrors.push(e) } } else if (process.arch === 'arm') { try { - return require('./markdown-rs.android-arm-eabi.node') + return require('./markdownrs.android-arm-eabi.node') } catch (e) { loadErrors.push(e) } try { - return require('markdown-rs-binding-android-arm-eabi') + return require('@xmorse/markdownrs-android-arm-eabi') } catch (e) { loadErrors.push(e) } @@ -101,36 +101,36 @@ function requireNative() { } else if (process.platform === 'win32') { if (process.arch === 'x64') { try { - return require('./markdown-rs.win32-x64-msvc.node') + return require('./markdownrs.win32-x64-msvc.node') } catch (e) { loadErrors.push(e) } try { - return require('markdown-rs-binding-win32-x64-msvc') + return require('@xmorse/markdownrs-win32-x64-msvc') } catch (e) { loadErrors.push(e) } } else if (process.arch === 'ia32') { try { - return require('./markdown-rs.win32-ia32-msvc.node') + return require('./markdownrs.win32-ia32-msvc.node') } catch (e) { loadErrors.push(e) } try { - return require('markdown-rs-binding-win32-ia32-msvc') + return require('@xmorse/markdownrs-win32-ia32-msvc') } catch (e) { loadErrors.push(e) } } else if (process.arch === 'arm64') { try { - return require('./markdown-rs.win32-arm64-msvc.node') + return require('./markdownrs.win32-arm64-msvc.node') } catch (e) { loadErrors.push(e) } try { - return require('markdown-rs-binding-win32-arm64-msvc') + return require('@xmorse/markdownrs-win32-arm64-msvc') } catch (e) { loadErrors.push(e) } @@ -140,36 +140,36 @@ function requireNative() { } } else if (process.platform === 'darwin') { try { - return require('./markdown-rs.darwin-universal.node') + return require('./markdownrs.darwin-universal.node') } catch (e) { loadErrors.push(e) } try { - return require('markdown-rs-binding-darwin-universal') + return require('@xmorse/markdownrs-darwin-universal') } catch (e) { loadErrors.push(e) } if (process.arch === 'x64') { try { - return require('./markdown-rs.darwin-x64.node') + return require('./markdownrs.darwin-x64.node') } catch (e) { loadErrors.push(e) } try { - return require('markdown-rs-binding-darwin-x64') + return require('@xmorse/markdownrs-darwin-x64') } catch (e) { loadErrors.push(e) } } else if (process.arch === 'arm64') { try { - return require('./markdown-rs.darwin-arm64.node') + return require('./markdownrs.darwin-arm64.node') } catch (e) { loadErrors.push(e) } try { - return require('markdown-rs-binding-darwin-arm64') + return require('@xmorse/markdownrs-darwin-arm64') } catch (e) { loadErrors.push(e) } @@ -180,24 +180,24 @@ function requireNative() { } else if (process.platform === 'freebsd') { if (process.arch === 'x64') { try { - return require('./markdown-rs.freebsd-x64.node') + return require('./markdownrs.freebsd-x64.node') } catch (e) { loadErrors.push(e) } try { - return require('markdown-rs-binding-freebsd-x64') + return require('@xmorse/markdownrs-freebsd-x64') } catch (e) { loadErrors.push(e) } } else if (process.arch === 'arm64') { try { - return require('./markdown-rs.freebsd-arm64.node') + return require('./markdownrs.freebsd-arm64.node') } catch (e) { loadErrors.push(e) } try { - return require('markdown-rs-binding-freebsd-arm64') + return require('@xmorse/markdownrs-freebsd-arm64') } catch (e) { loadErrors.push(e) } @@ -209,24 +209,24 @@ function requireNative() { if (process.arch === 'x64') { if (isMusl()) { try { - return require('./markdown-rs.linux-x64-musl.node') + return require('./markdownrs.linux-x64-musl.node') } catch (e) { loadErrors.push(e) } try { - return require('markdown-rs-binding-linux-x64-musl') + return require('@xmorse/markdownrs-linux-x64-musl') } catch (e) { loadErrors.push(e) } } else { try { - return require('./markdown-rs.linux-x64-gnu.node') + return require('./markdownrs.linux-x64-gnu.node') } catch (e) { loadErrors.push(e) } try { - return require('markdown-rs-binding-linux-x64-gnu') + return require('@xmorse/markdownrs-linux-x64-gnu') } catch (e) { loadErrors.push(e) } @@ -235,24 +235,24 @@ function requireNative() { } else if (process.arch === 'arm64') { if (isMusl()) { try { - return require('./markdown-rs.linux-arm64-musl.node') + return require('./markdownrs.linux-arm64-musl.node') } catch (e) { loadErrors.push(e) } try { - return require('markdown-rs-binding-linux-arm64-musl') + return require('@xmorse/markdownrs-linux-arm64-musl') } catch (e) { loadErrors.push(e) } } else { try { - return require('./markdown-rs.linux-arm64-gnu.node') + return require('./markdownrs.linux-arm64-gnu.node') } catch (e) { loadErrors.push(e) } try { - return require('markdown-rs-binding-linux-arm64-gnu') + return require('@xmorse/markdownrs-linux-arm64-gnu') } catch (e) { loadErrors.push(e) } @@ -261,24 +261,24 @@ function requireNative() { } else if (process.arch === 'arm') { if (isMusl()) { try { - return require('./markdown-rs.linux-arm-musleabihf.node') + return require('./markdownrs.linux-arm-musleabihf.node') } catch (e) { loadErrors.push(e) } try { - return require('markdown-rs-binding-linux-arm-musleabihf') + return require('@xmorse/markdownrs-linux-arm-musleabihf') } catch (e) { loadErrors.push(e) } } else { try { - return require('./markdown-rs.linux-arm-gnueabihf.node') + return require('./markdownrs.linux-arm-gnueabihf.node') } catch (e) { loadErrors.push(e) } try { - return require('markdown-rs-binding-linux-arm-gnueabihf') + return require('@xmorse/markdownrs-linux-arm-gnueabihf') } catch (e) { loadErrors.push(e) } @@ -287,24 +287,24 @@ function requireNative() { } else if (process.arch === 'riscv64') { if (isMusl()) { try { - return require('./markdown-rs.linux-riscv64-musl.node') + return require('./markdownrs.linux-riscv64-musl.node') } catch (e) { loadErrors.push(e) } try { - return require('markdown-rs-binding-linux-riscv64-musl') + return require('@xmorse/markdownrs-linux-riscv64-musl') } catch (e) { loadErrors.push(e) } } else { try { - return require('./markdown-rs.linux-riscv64-gnu.node') + return require('./markdownrs.linux-riscv64-gnu.node') } catch (e) { loadErrors.push(e) } try { - return require('markdown-rs-binding-linux-riscv64-gnu') + return require('@xmorse/markdownrs-linux-riscv64-gnu') } catch (e) { loadErrors.push(e) } @@ -312,24 +312,24 @@ function requireNative() { } } else if (process.arch === 'ppc64') { try { - return require('./markdown-rs.linux-ppc64-gnu.node') + return require('./markdownrs.linux-ppc64-gnu.node') } catch (e) { loadErrors.push(e) } try { - return require('markdown-rs-binding-linux-ppc64-gnu') + return require('@xmorse/markdownrs-linux-ppc64-gnu') } catch (e) { loadErrors.push(e) } } else if (process.arch === 's390x') { try { - return require('./markdown-rs.linux-s390x-gnu.node') + return require('./markdownrs.linux-s390x-gnu.node') } catch (e) { loadErrors.push(e) } try { - return require('markdown-rs-binding-linux-s390x-gnu') + return require('@xmorse/markdownrs-linux-s390x-gnu') } catch (e) { loadErrors.push(e) } @@ -346,7 +346,7 @@ nativeBinding = requireNative() if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) { try { - nativeBinding = require('./markdown-rs.wasi.cjs') + nativeBinding = require('./markdownrs.wasi.cjs') } catch (err) { if (process.env.NAPI_RS_FORCE_WASI) { loadErrors.push(err) @@ -354,7 +354,7 @@ if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) { } if (!nativeBinding) { try { - nativeBinding = require('markdown-rs-binding-wasm32-wasi') + nativeBinding = require('@xmorse/markdownrs-wasm32-wasi') } catch (err) { if (process.env.NAPI_RS_FORCE_WASI) { loadErrors.push(err) @@ -365,12 +365,11 @@ if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) { if (!nativeBinding) { if (loadErrors.length > 0) { - throw new Error( - `Cannot find native binding. ` + - `npm has a bug related to optional dependencies (https://github.com/npm/cli/issues/4828). ` + - 'Please try `npm i` again after removing both package-lock.json and node_modules directory.', - { cause: loadErrors } - ) + // TODO Link to documentation with potential fixes + // - The package owner could build/publish bindings for this arch + // - The user may need to bundle the correct files + // - The user may need to re-install node_modules to get new packages + throw new Error('Failed to load native binding', { cause: loadErrors }) } throw new Error(`Failed to load native binding`) } diff --git a/napi/markdownrs.wasi-browser.js b/napi/markdownrs.wasi-browser.js new file mode 100644 index 00000000..575efc66 --- /dev/null +++ b/napi/markdownrs.wasi-browser.js @@ -0,0 +1,58 @@ +import { + createOnMessage as __wasmCreateOnMessageForFsProxy, + getDefaultContext as __emnapiGetDefaultContext, + instantiateNapiModuleSync as __emnapiInstantiateNapiModuleSync, + WASI as __WASI, +} from '@napi-rs/wasm-runtime' + +import __wasmUrl from './markdownrs.wasm32-wasi.wasm?url' + +const __wasi = new __WASI({ + version: 'preview1', +}) + +const __emnapiContext = __emnapiGetDefaultContext() + +const __sharedMemory = new WebAssembly.Memory({ + initial: 16384, + maximum: 65536, + shared: true, +}) + +const __wasmFile = await fetch(__wasmUrl).then((res) => res.arrayBuffer()) + +const { + instance: __napiInstance, + module: __wasiModule, + napiModule: __napiModule, +} = __emnapiInstantiateNapiModuleSync(__wasmFile, { + context: __emnapiContext, + asyncWorkPoolSize: 4, + wasi: __wasi, + onCreateWorker() { + const worker = new Worker(new URL('./wasi-worker-browser.mjs', import.meta.url), { + type: 'module', + }) + + return worker + }, + overwriteImports(importObject) { + importObject.env = { + ...importObject.env, + ...importObject.napi, + ...importObject.emnapi, + memory: __sharedMemory, + } + return importObject + }, + beforeInit({ instance }) { + for (const name of Object.keys(instance.exports)) { + if (name.startsWith('__napi_register__')) { + instance.exports[name]() + } + } + }, +}) +export default __napiModule.exports +export const parse = __napiModule.exports.parse +export const parseMdx = __napiModule.exports.parseMdx diff --git a/napi/markdownrs.wasi.cjs b/napi/markdownrs.wasi.cjs new file mode 100644 index 00000000..815fa991 --- /dev/null +++ b/napi/markdownrs.wasi.cjs @@ -0,0 +1,89 @@ +/* eslint-disable */ +/* prettier-ignore */ + +/* auto-generated by NAPI-RS */ + +const __nodeFs = require('node:fs') +const __nodePath = require('node:path') +const { WASI: __nodeWASI } = require('node:wasi') +const { Worker } = require('node:worker_threads') + +const { + createOnMessage: __wasmCreateOnMessageForFsProxy, + getDefaultContext: __emnapiGetDefaultContext, + instantiateNapiModuleSync: __emnapiInstantiateNapiModuleSync, +} = require('@napi-rs/wasm-runtime') + +const __rootDir = __nodePath.parse(process.cwd()).root + +const __wasi = new __nodeWASI({ + version: 'preview1', + env: process.env, + preopens: { + [__rootDir]: __rootDir, + } +}) + +const __emnapiContext = __emnapiGetDefaultContext() + +const __sharedMemory = new WebAssembly.Memory({ + initial: 16384, + maximum: 65536, + shared: true, +}) + +let __wasmFilePath = __nodePath.join(__dirname, 'markdownrs.wasm32-wasi.wasm') +const __wasmDebugFilePath = __nodePath.join(__dirname, 'markdownrs.wasm32-wasi.debug.wasm') + +if (__nodeFs.existsSync(__wasmDebugFilePath)) { + __wasmFilePath = __wasmDebugFilePath +} else if (!__nodeFs.existsSync(__wasmFilePath)) { + try { + __wasmFilePath = __nodePath.resolve('@xmorse/markdownrs-wasm32-wasi') + } catch { + throw new Error('Cannot find markdownrs.wasm32-wasi.wasm file, and @xmorse/markdownrs-wasm32-wasi package is not installed.') + } +} + +const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule } = __emnapiInstantiateNapiModuleSync(__nodeFs.readFileSync(__wasmFilePath), { + context: __emnapiContext, + asyncWorkPoolSize: (function() { + const threadsSizeFromEnv = Number(process.env.NAPI_RS_ASYNC_WORK_POOL_SIZE ?? process.env.UV_THREADPOOL_SIZE) + // NaN > 0 is false + if (threadsSizeFromEnv > 0) { + return threadsSizeFromEnv + } else { + return 4 + } + })(), + reuseWorker: true, + wasi: __wasi, + onCreateWorker() { + const worker = new Worker(__nodePath.join(__dirname, 'wasi-worker.mjs'), { + env: process.env, + }) + worker.onmessage = ({ data }) => { + __wasmCreateOnMessageForFsProxy(__nodeFs)(data) + } + return worker + }, + overwriteImports(importObject) { + importObject.env = { + ...importObject.env, + ...importObject.napi, + ...importObject.emnapi, + memory: __sharedMemory, + } + return importObject + }, + beforeInit({ instance }) { + for (const name of Object.keys(instance.exports)) { + if (name.startsWith('__napi_register__')) { + instance.exports[name]() + } + } + }, +}) +module.exports = __napiModule.exports +module.exports.parse = __napiModule.exports.parse +module.exports.parseMdx = __napiModule.exports.parseMdx From db0ff41646be4f9bc23fabadf4a237e578e9b126 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 15:19:22 +0200 Subject: [PATCH 22/61] remove - --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e262d222..97bc5c87 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "@xmorse/markdown-rs", + "name": "@xmorse/markdownrs", "version": "0.0.0", "scripts": { "build:debug": "pnpm napi build --platform --manifest-path napi/Cargo.toml", From 9d48fa7ce9459a6e25db58f0a83d083ad8a58bf9 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 15:25:49 +0200 Subject: [PATCH 23/61] add publishConfig --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index 97bc5c87..d378ab1e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,10 @@ { "name": "@xmorse/markdownrs", "version": "0.0.0", + "publishConfig": { + "registry": "https://registry.npmjs.org/", + "access": "public" + }, "scripts": { "build:debug": "pnpm napi build --platform --manifest-path napi/Cargo.toml", "build": "pnpm run build:debug --release", From 1201c1401bac9c425a59cfe636d994a04a059253 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 15:33:25 +0200 Subject: [PATCH 24/61] fix wrong readme.md --- .github/workflows/release-napi.yml | 2 +- napi/package.json | 4 +--- package.json | 4 +--- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release-napi.yml b/.github/workflows/release-napi.yml index af120877..f73cbfbc 100644 --- a/.github/workflows/release-napi.yml +++ b/.github/workflows/release-napi.yml @@ -179,5 +179,5 @@ jobs: # Publish root package cp package.json napi/package.json - cp README.md napi/README.md + cp readme.md napi/readme.md npm publish napi/ --tag latest --provenance --access public diff --git a/napi/package.json b/napi/package.json index 17313197..f5a9fb41 100644 --- a/napi/package.json +++ b/napi/package.json @@ -4,9 +4,7 @@ "scripts": { "build:debug": "pnpm napi build --platform --manifest-path napi/Cargo.toml", "build": "pnpm run build:debug --release", - "npm-dirs": "pnpm napi create-npm-dirs --package-json-path package.json", - "pre-publish": "pnpm napi pre-publish --no-gh-release --tagstyle npm --package-json-path package.json --npm-dir npm && cp package.json napi/package.json && cp README.md napi/README.md", - "artifacts": "pnpm napi artifacts --npm-dir npm --build-output-dir napi" + "npm-dirs": "pnpm napi create-npm-dirs --package-json-path package.json" }, "napi": { "binaryName": "markdown-rs", diff --git a/package.json b/package.json index d378ab1e..cce9f42f 100644 --- a/package.json +++ b/package.json @@ -8,9 +8,7 @@ "scripts": { "build:debug": "pnpm napi build --platform --manifest-path napi/Cargo.toml", "build": "pnpm run build:debug --release", - "npm-dirs": "pnpm napi create-npm-dirs --package-json-path package.json", - "pre-publish": "pnpm napi pre-publish --no-gh-release --tagstyle npm --package-json-path package.json --npm-dir npm && cp package.json napi/package.json && cp README.md napi/README.md", - "artifacts": "pnpm napi artifacts --npm-dir npm --build-output-dir napi" + "npm-dirs": "pnpm napi create-npm-dirs --package-json-path package.json" }, "main": "index.js", "browser": "browser.js", From d17d1e9e2e287e80a07ef854ce10a5a581483043 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 15:34:26 +0200 Subject: [PATCH 25/61] fix mdx test --- napi/__tests__/parse.test.ts | 61 +++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/napi/__tests__/parse.test.ts b/napi/__tests__/parse.test.ts index aa61ac2f..42a344d4 100644 --- a/napi/__tests__/parse.test.ts +++ b/napi/__tests__/parse.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from "vitest"; -import { parse, parseMdx } from "../out/index.wasi.cjs"; +import { parse, parseMdx } from "../"; describe("parse mdx", () => { it("returns mdast", () => { @@ -119,23 +119,43 @@ this is a callout "type": "paragraph", }, { - "position": { - "end": { - "column": 18, - "line": 9, - "offset": 76, - }, - "start": { - "column": 1, - "line": 8, - "offset": 49, + "attributes": [], + "children": [ + { + "children": [ + { + "position": { + "end": { + "column": 18, + "line": 9, + "offset": 76, + }, + "start": { + "column": 1, + "line": 9, + "offset": 59, + }, + }, + "type": "text", + "value": "this is a callout", + }, + ], + "position": { + "end": { + "column": 18, + "line": 9, + "offset": 76, + }, + "start": { + "column": 1, + "line": 9, + "offset": 59, + }, + }, + "type": "paragraph", }, - }, - "type": "html", - "value": " - this is a callout", - }, - { + ], + "name": "Callout", "position": { "end": { "column": 11, @@ -144,12 +164,11 @@ this is a callout }, "start": { "column": 1, - "line": 11, - "offset": 78, + "line": 8, + "offset": 49, }, }, - "type": "html", - "value": "", + "type": "mdxJsxFlowElement", }, ], "position": { From 1c4a8fd2576beb2892faea4b5bcae3d3d740b1f1 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 15:51:58 +0200 Subject: [PATCH 26/61] adding more options in the exports --- napi/__tests__/parse.test.ts | 179 ++++++++++---------------------- napi/index.d.ts | 2 + napi/index.js | 1 + napi/markdownrs.wasi-browser.js | 1 + napi/markdownrs.wasi.cjs | 1 + napi/src/lib.rs | 19 +++- 6 files changed, 77 insertions(+), 126 deletions(-) diff --git a/napi/__tests__/parse.test.ts b/napi/__tests__/parse.test.ts index 42a344d4..3fbc7296 100644 --- a/napi/__tests__/parse.test.ts +++ b/napi/__tests__/parse.test.ts @@ -1,9 +1,33 @@ import { describe, it, expect } from "vitest"; -import { parse, parseMdx } from "../"; +import { parse, parseMdx, toHtml } from "../"; describe("parse mdx", () => { + it("returns html", () => { + const html = toHtml(` +# Hello + +this is a paragraph + +here is some mdx + + +this is a callout + +`); + expect(html).toMatchInlineSnapshot(` + "

Hello

+

this is a paragraph

+

here is some mdx

+ <Callout> + this is a callout + </Callout>" + `); + }); it("returns mdast", () => { const ast = parseMdx(` +import something from 'package' +export const x = 9 + # Hello this is a paragraph @@ -15,107 +39,45 @@ this is a callout `); - expect(ast).toMatchInlineSnapshot(` + expect(stripPositions(ast)).toMatchInlineSnapshot(` { "children": [ { "children": [ { - "position": { - "end": { - "column": 8, - "line": 2, - "offset": 8, - }, - "start": { - "column": 3, - "line": 2, - "offset": 3, - }, - }, + "type": "text", + "value": "import something from 'package' + export const x = 9", + }, + ], + "type": "paragraph", + }, + { + "children": [ + { "type": "text", "value": "Hello", }, ], "depth": 1, - "position": { - "end": { - "column": 8, - "line": 2, - "offset": 8, - }, - "start": { - "column": 1, - "line": 2, - "offset": 1, - }, - }, "type": "heading", }, { "children": [ { - "position": { - "end": { - "column": 20, - "line": 4, - "offset": 29, - }, - "start": { - "column": 1, - "line": 4, - "offset": 10, - }, - }, "type": "text", "value": "this is a paragraph", }, ], - "position": { - "end": { - "column": 20, - "line": 4, - "offset": 29, - }, - "start": { - "column": 1, - "line": 4, - "offset": 10, - }, - }, "type": "paragraph", }, { "children": [ { - "position": { - "end": { - "column": 17, - "line": 6, - "offset": 47, - }, - "start": { - "column": 1, - "line": 6, - "offset": 31, - }, - }, "type": "text", "value": "here is some mdx", }, ], - "position": { - "end": { - "column": 17, - "line": 6, - "offset": 47, - }, - "start": { - "column": 1, - "line": 6, - "offset": 31, - }, - }, "type": "paragraph", }, { @@ -124,67 +86,40 @@ this is a callout { "children": [ { - "position": { - "end": { - "column": 18, - "line": 9, - "offset": 76, - }, - "start": { - "column": 1, - "line": 9, - "offset": 59, - }, - }, "type": "text", "value": "this is a callout", }, ], - "position": { - "end": { - "column": 18, - "line": 9, - "offset": 76, - }, - "start": { - "column": 1, - "line": 9, - "offset": 59, - }, - }, "type": "paragraph", }, ], "name": "Callout", - "position": { - "end": { - "column": 11, - "line": 11, - "offset": 88, - }, - "start": { - "column": 1, - "line": 8, - "offset": 49, - }, - }, "type": "mdxJsxFlowElement", }, ], - "position": { - "end": { - "column": 5, - "line": 12, - "offset": 93, - }, - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, "type": "root", } `); }); }); + +/** + * Removes all "position" fields from an mdast/unist tree node (in-place). + * @param node - The tree node to clean. + * @returns The node without "position" fields. + */ +export function stripPositions>(node: T): T { + if (Array.isArray(node)) { + // @ts-ignore + return node.map(stripPositions); + } else if (node && typeof node === "object") { + const newNode: any = {}; + for (const key in node) { + if (key === "position") continue; + // Recursively clean properties that may be nodes or arrays of nodes + newNode[key] = stripPositions(node[key]); + } + return newNode; + } + return node; +} diff --git a/napi/index.d.ts b/napi/index.d.ts index 6038653a..42701fc9 100644 --- a/napi/index.d.ts +++ b/napi/index.d.ts @@ -3,3 +3,5 @@ export declare function parse(input: string): any export declare function parseMdx(mdx: string): any + +export declare function toHtml(mdx: string): any diff --git a/napi/index.js b/napi/index.js index 73f78e20..a229e323 100644 --- a/napi/index.js +++ b/napi/index.js @@ -377,3 +377,4 @@ if (!nativeBinding) { module.exports = nativeBinding module.exports.parse = nativeBinding.parse module.exports.parseMdx = nativeBinding.parseMdx +module.exports.toHtml = nativeBinding.toHtml diff --git a/napi/markdownrs.wasi-browser.js b/napi/markdownrs.wasi-browser.js index 575efc66..4228d415 100644 --- a/napi/markdownrs.wasi-browser.js +++ b/napi/markdownrs.wasi-browser.js @@ -56,3 +56,4 @@ const { export default __napiModule.exports export const parse = __napiModule.exports.parse export const parseMdx = __napiModule.exports.parseMdx +export const toHtml = __napiModule.exports.toHtml diff --git a/napi/markdownrs.wasi.cjs b/napi/markdownrs.wasi.cjs index 815fa991..bb7daba2 100644 --- a/napi/markdownrs.wasi.cjs +++ b/napi/markdownrs.wasi.cjs @@ -87,3 +87,4 @@ const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule module.exports = __napiModule.exports module.exports.parse = __napiModule.exports.parse module.exports.parseMdx = __napiModule.exports.parseMdx +module.exports.toHtml = __napiModule.exports.toHtml diff --git a/napi/src/lib.rs b/napi/src/lib.rs index 2a8ba688..5b373b66 100644 --- a/napi/src/lib.rs +++ b/napi/src/lib.rs @@ -1,18 +1,29 @@ -use markdown::{to_mdast, ParseOptions}; use napi::{bindgen_prelude::*, Error}; use napi_derive::napi; use serde_json::Value; #[napi] pub fn parse(input: String) -> Result { - let tree = to_mdast(&input, &ParseOptions::default()) + let tree = markdown::to_mdast(&input, &markdown::ParseOptions::default()) .map_err(|e| Error::from_reason(format!("{:?}", e)))?; serde_json::to_value(&tree).map_err(|e| Error::from_reason(e.to_string())) } #[napi] pub fn parse_mdx(mdx: String) -> Result { - let ast = - to_mdast(&mdx, &ParseOptions::mdx()).map_err(|e| Error::from_reason(format!("{:?}", e)))?; + // Enable ESM parsing in addition to MDX options + // markdown::ParseOptions::mdx() + let options = markdown::ParseOptions { + constructs: markdown::Constructs::mdx(), + ..Default::default() + }; + + let ast = markdown::to_mdast(&mdx, &options).map_err(|e| Error::from_reason(format!("{:?}", e)))?; serde_json::to_value(&ast).map_err(|e| Error::from_reason(e.to_string())) } + +#[napi] +pub fn to_html(mdx: String) -> Value { + let html = markdown::to_html(&mdx); + html.into() +} From 92adec77b2ed1b1710b0798ca2fa154fb33b464a Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 15:57:43 +0200 Subject: [PATCH 27/61] new version --- napi/__tests__/parse.test.ts | 67 +++++++++++++++++++++++++++++++++--- package.json | 2 +- 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/napi/__tests__/parse.test.ts b/napi/__tests__/parse.test.ts index 3fbc7296..740297bd 100644 --- a/napi/__tests__/parse.test.ts +++ b/napi/__tests__/parse.test.ts @@ -23,6 +23,20 @@ this is a callout </Callout>" `); }); + + it("handles broken jsx in mdx without panic", () => { + const error = catchErrorValue(() => + parseMdx(` +paragraph + + + + `), + ); + expect(error).toMatchInlineSnapshot( + `[Error: Message { place: Some(Point(6:5 (39))), reason: "Expected a closing tag for \`\` (4:1)", rule_id: "end-tag-mismatch", source: "markdown-rs" }]`, + ); + }); it("returns mdast", () => { const ast = parseMdx(` import something from 'package' @@ -32,9 +46,11 @@ export const x = 9 this is a paragraph -here is some mdx +here is some mdx {expression} - +> quote + + this is a callout @@ -75,13 +91,43 @@ this is a callout "children": [ { "type": "text", - "value": "here is some mdx", + "value": "here is some mdx ", + }, + { + "_markdownRsStops": [ + [ + 0, + 101, + ], + ], + "type": "mdxTextExpression", + "value": "expression", }, ], "type": "paragraph", }, { - "attributes": [], + "children": [ + { + "children": [ + { + "type": "text", + "value": "quote", + }, + ], + "type": "paragraph", + }, + ], + "type": "blockquote", + }, + { + "attributes": [ + { + "name": "type", + "type": "mdxJsxAttribute", + "value": "info", + }, + ], "children": [ { "children": [ @@ -123,3 +169,16 @@ export function stripPositions>(node: T): T { } return node; } + +/** + * Executes a function and returns either its value or the error thrown. + * @param fn - The function to execute. + * @returns The returned value, or the caught error. + */ +export function catchErrorValue(fn: () => T): T | Error { + try { + return fn(); + } catch (e) { + return e; + } +} diff --git a/package.json b/package.json index cce9f42f..a4aedab2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@xmorse/markdownrs", - "version": "0.0.0", + "version": "0.0.1", "publishConfig": { "registry": "https://registry.npmjs.org/", "access": "public" From 0096e70a27db7a1c5ffaa5a3e9ac6baeb5b72431 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 16:06:12 +0200 Subject: [PATCH 28/61] added more options --- napi/__tests__/parse.test.ts | 198 +++++++++++++++++++++++++++++++++++ napi/index.d.ts | 15 ++- napi/src/lib.rs | 65 ++++++++++-- 3 files changed, 269 insertions(+), 9 deletions(-) diff --git a/napi/__tests__/parse.test.ts b/napi/__tests__/parse.test.ts index 740297bd..bd6ab0f0 100644 --- a/napi/__tests__/parse.test.ts +++ b/napi/__tests__/parse.test.ts @@ -2,6 +2,204 @@ import { describe, it, expect } from "vitest"; import { parse, parseMdx, toHtml } from "../"; describe("parse mdx", () => { + it("parse accepts options parameter", () => { + const ast = parse("# Hello ~world~", { + gfmStrikethroughSingleTilde: true, + }); + expect(stripPositions(ast)).toMatchInlineSnapshot(` + { + "children": [ + { + "children": [ + { + "type": "text", + "value": "Hello ~world~", + }, + ], + "depth": 1, + "type": "heading", + }, + ], + "type": "root", + } + `); + }); + + it("parse_mdx accepts options parameter", () => { + const ast = parseMdx("# Hello {expression}", { + mdxExpressionParse: true, + gfmStrikethroughSingleTilde: false, + }); + expect(stripPositions(ast)).toMatchInlineSnapshot(` + { + "children": [ + { + "children": [ + { + "type": "text", + "value": "Hello ", + }, + { + "_markdownRsStops": [ + [ + 0, + 9, + ], + ], + "type": "mdxTextExpression", + "value": "expression", + }, + ], + "depth": 1, + "type": "heading", + }, + ], + "type": "root", + } + `); + }); + + it("parse works without options parameter", () => { + const ast = parse("# Hello world"); + expect(stripPositions(ast)).toMatchInlineSnapshot(` + { + "children": [ + { + "children": [ + { + "type": "text", + "value": "Hello world", + }, + ], + "depth": 1, + "type": "heading", + }, + ], + "type": "root", + } + `); + }); + + it("parse_mdx works without options parameter", () => { + const ast = parseMdx("# Hello {expression}"); + expect(stripPositions(ast)).toMatchInlineSnapshot(` + { + "children": [ + { + "children": [ + { + "type": "text", + "value": "Hello ", + }, + { + "_markdownRsStops": [ + [ + 0, + 9, + ], + ], + "type": "mdxTextExpression", + "value": "expression", + }, + ], + "depth": 1, + "type": "heading", + }, + ], + "type": "root", + } + `); + }); + + it("options affect math parsing behavior", () => { + const astWithSingleDollar = parse("$math$", { + mathTextSingleDollar: true, + }); + const astWithoutSingleDollar = parse("$math$", { + mathTextSingleDollar: false, + }); + expect(stripPositions(astWithSingleDollar)).toMatchInlineSnapshot(` + { + "children": [ + { + "children": [ + { + "type": "text", + "value": "$math$", + }, + ], + "type": "paragraph", + }, + ], + "type": "root", + } + `); + expect(stripPositions(astWithoutSingleDollar)).toMatchInlineSnapshot(` + { + "children": [ + { + "children": [ + { + "type": "text", + "value": "$math$", + }, + ], + "type": "paragraph", + }, + ], + "type": "root", + } + `); + }); + + it("options affect strikethrough parsing", () => { + const astWithSingleTilde = parse("~strikethrough~", { + gfmStrikethroughSingleTilde: true, + }); + const astWithoutSingleTilde = parse("~strikethrough~", { + gfmStrikethroughSingleTilde: false, + }); + expect(stripPositions(astWithSingleTilde)).toMatchInlineSnapshot(` + { + "children": [ + { + "children": [ + { + "type": "text", + "value": "~strikethrough~", + }, + ], + "type": "paragraph", + }, + ], + "type": "root", + } + `); + expect(stripPositions(astWithoutSingleTilde)).toMatchInlineSnapshot(` + { + "children": [ + { + "children": [ + { + "type": "text", + "value": "~strikethrough~", + }, + ], + "type": "paragraph", + }, + ], + "type": "root", + } + `); + }); + + it("mdx options work in parseMdx", () => { + const ast = parseMdx("import foo from 'bar'\n{expression}", { + mdxEsmParse: true, + mdxExpressionParse: true, + }); + expect(ast).toBeDefined(); + }); it("returns html", () => { const html = toHtml(` # Hello diff --git a/napi/index.d.ts b/napi/index.d.ts index 42701fc9..0b1e0789 100644 --- a/napi/index.d.ts +++ b/napi/index.d.ts @@ -1,7 +1,18 @@ /* auto-generated by NAPI-RS */ /* eslint-disable */ -export declare function parse(input: string): any +export declare function parse(input: string, options?: ParseOptions | undefined | null): any -export declare function parseMdx(mdx: string): any +export declare function parseMdx(mdx: string, options?: ParseOptions | undefined | null): any + +export interface ParseOptions { + /** Whether to support GFM strikethrough with a single tilde */ + gfmStrikethroughSingleTilde?: boolean + /** Whether to support math (text) with a single dollar */ + mathTextSingleDollar?: boolean + /** Whether to enable basic MDX expression parsing */ + mdxExpressionParse?: boolean + /** Whether to enable basic MDX ESM parsing */ + mdxEsmParse?: boolean +} export declare function toHtml(mdx: string): any diff --git a/napi/src/lib.rs b/napi/src/lib.rs index 5b373b66..aad7f25f 100644 --- a/napi/src/lib.rs +++ b/napi/src/lib.rs @@ -1,24 +1,75 @@ use napi::{bindgen_prelude::*, Error}; use napi_derive::napi; use serde_json::Value; +use markdown::{MdxExpressionKind, MdxSignal}; + +#[napi(object)] +pub struct ParseOptions { + /// Whether to support GFM strikethrough with a single tilde + pub gfm_strikethrough_single_tilde: Option, + /// Whether to support math (text) with a single dollar + pub math_text_single_dollar: Option, + /// Whether to enable basic MDX expression parsing + pub mdx_expression_parse: Option, + /// Whether to enable basic MDX ESM parsing + pub mdx_esm_parse: Option, +} + +impl ParseOptions { + fn to_rust_parse_options(&self) -> markdown::ParseOptions { + markdown::ParseOptions { + gfm_strikethrough_single_tilde: self.gfm_strikethrough_single_tilde.unwrap_or(true), + math_text_single_dollar: self.math_text_single_dollar.unwrap_or(true), + mdx_expression_parse: if self.mdx_expression_parse.unwrap_or(false) { + Some(Box::new(|_value: &str, _kind: &MdxExpressionKind| { + // Basic expression parsing that just returns success + MdxSignal::Ok + })) + } else { + None + }, + mdx_esm_parse: if self.mdx_esm_parse.unwrap_or(false) { + Some(Box::new(|_value: &str| { + // Basic ESM parsing that just returns success + MdxSignal::Ok + })) + } else { + None + }, + ..Default::default() + } + } +} #[napi] -pub fn parse(input: String) -> Result { - let tree = markdown::to_mdast(&input, &markdown::ParseOptions::default()) +pub fn parse(input: String, options: Option) -> Result { + let parse_options = match options { + Some(opts) => opts.to_rust_parse_options(), + None => markdown::ParseOptions::default(), + }; + + let tree = markdown::to_mdast(&input, &parse_options) .map_err(|e| Error::from_reason(format!("{:?}", e)))?; serde_json::to_value(&tree).map_err(|e| Error::from_reason(e.to_string())) } #[napi] -pub fn parse_mdx(mdx: String) -> Result { - // Enable ESM parsing in addition to MDX options - // markdown::ParseOptions::mdx() - let options = markdown::ParseOptions { +pub fn parse_mdx(mdx: String, options: Option) -> Result { + let mut mdx_options = markdown::ParseOptions { constructs: markdown::Constructs::mdx(), ..Default::default() }; - let ast = markdown::to_mdast(&mdx, &options).map_err(|e| Error::from_reason(format!("{:?}", e)))?; + // Override with user-provided options if available + if let Some(opts) = options { + let user_options = opts.to_rust_parse_options(); + mdx_options.gfm_strikethrough_single_tilde = user_options.gfm_strikethrough_single_tilde; + mdx_options.math_text_single_dollar = user_options.math_text_single_dollar; + mdx_options.mdx_expression_parse = user_options.mdx_expression_parse; + mdx_options.mdx_esm_parse = user_options.mdx_esm_parse; + } + + let ast = markdown::to_mdast(&mdx, &mdx_options).map_err(|e| Error::from_reason(format!("{:?}", e)))?; serde_json::to_value(&ast).map_err(|e| Error::from_reason(e.to_string())) } From 2e8ff1e61bfcf2415793af157d32b6dec8e0b363 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 16:08:03 +0200 Subject: [PATCH 29/61] esm works --- napi/__tests__/parse.test.ts | 54 ++++++++++++++++++++---------------- napi/src/lib.rs | 10 +++---- 2 files changed, 35 insertions(+), 29 deletions(-) diff --git a/napi/__tests__/parse.test.ts b/napi/__tests__/parse.test.ts index bd6ab0f0..4dd4baeb 100644 --- a/napi/__tests__/parse.test.ts +++ b/napi/__tests__/parse.test.ts @@ -1,5 +1,5 @@ -import { describe, it, expect } from "vitest"; -import { parse, parseMdx, toHtml } from "../"; +import { describe, expect, it } from "vitest"; +import { parse, parseMdx } from "../"; describe("parse mdx", () => { it("parse accepts options parameter", () => { @@ -194,34 +194,40 @@ describe("parse mdx", () => { }); it("mdx options work in parseMdx", () => { - const ast = parseMdx("import foo from 'bar'\n{expression}", { + const ast = parseMdx("import foo from 'bar'\n\n{expression}", { mdxEsmParse: true, mdxExpressionParse: true, }); - expect(ast).toBeDefined(); - }); - it("returns html", () => { - const html = toHtml(` -# Hello - -this is a paragraph - -here is some mdx - - -this is a callout - -`); - expect(html).toMatchInlineSnapshot(` - "

Hello

-

this is a paragraph

-

here is some mdx

- <Callout> - this is a callout - </Callout>" + expect(stripPositions(ast)).toMatchInlineSnapshot(` + { + "children": [ + { + "_markdownRsStops": [ + [ + 0, + 0, + ], + ], + "type": "mdxjsEsm", + "value": "import foo from 'bar'", + }, + { + "_markdownRsStops": [ + [ + 0, + 24, + ], + ], + "type": "mdxFlowExpression", + "value": "expression", + }, + ], + "type": "root", + } `); }); + it("handles broken jsx in mdx without panic", () => { const error = catchErrorValue(() => parseMdx(` diff --git a/napi/src/lib.rs b/napi/src/lib.rs index aad7f25f..53579982 100644 --- a/napi/src/lib.rs +++ b/napi/src/lib.rs @@ -73,8 +73,8 @@ pub fn parse_mdx(mdx: String, options: Option) -> Result { serde_json::to_value(&ast).map_err(|e| Error::from_reason(e.to_string())) } -#[napi] -pub fn to_html(mdx: String) -> Value { - let html = markdown::to_html(&mdx); - html.into() -} +// #[napi] +// pub fn to_html(mdx: String) -> Value { +// let html = markdown::to_html(&mdx); +// html.into() +// } From 6f2e20fb57d0eacce93f1c7652792d60b4003537 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 16:15:45 +0200 Subject: [PATCH 30/61] using napi package.json --- napi/package.json | 6 ++--- package.json | 41 +--------------------------------- pnpm-lock.yaml | 56 +---------------------------------------------- 3 files changed, 5 insertions(+), 98 deletions(-) diff --git a/napi/package.json b/napi/package.json index f5a9fb41..b7dec1dc 100644 --- a/napi/package.json +++ b/napi/package.json @@ -2,9 +2,9 @@ "name": "@xmorse/markdown-rs", "version": "0.0.0", "scripts": { - "build:debug": "pnpm napi build --platform --manifest-path napi/Cargo.toml", - "build": "pnpm run build:debug --release", - "npm-dirs": "pnpm napi create-npm-dirs --package-json-path package.json" + "build:debug": "pnpm napi build --platform --manifest-path Cargo.toml", + "test": "pnpm vitest", + "build": "pnpm run build:debug --release" }, "napi": { "binaryName": "markdown-rs", diff --git a/package.json b/package.json index a4aedab2..67d3185a 100644 --- a/package.json +++ b/package.json @@ -1,48 +1,9 @@ { - "name": "@xmorse/markdownrs", - "version": "0.0.1", - "publishConfig": { - "registry": "https://registry.npmjs.org/", - "access": "public" - }, + "name": "root", "scripts": { "build:debug": "pnpm napi build --platform --manifest-path napi/Cargo.toml", "build": "pnpm run build:debug --release", "npm-dirs": "pnpm napi create-npm-dirs --package-json-path package.json" }, - "main": "index.js", - "browser": "browser.js", - "files": [ - "index.d.ts", - "index.js", - "browser.js", - "webcontainer-fallback.js" - ], - "napi": { - "binaryName": "markdownrs", - "packageName": "@xmorse/markdownrs", - "targets": [ - "x86_64-unknown-linux-gnu", - "x86_64-unknown-linux-musl", - "x86_64-unknown-freebsd", - "aarch64-unknown-linux-gnu", - "aarch64-unknown-linux-musl", - "armv7-unknown-linux-gnueabihf", - "s390x-unknown-linux-gnu", - "riscv64gc-unknown-linux-gnu", - "x86_64-apple-darwin", - "aarch64-apple-darwin", - "wasm32-wasip1-threads" - ], - "wasm": { - "initialMemory": 16384 - } - }, - "devDependencies": { - "@napi-rs/cli": "3.0.0-alpha.88", - "@napi-rs/wasm-runtime": "^0.2.7", - "emnapi": "^1.4.3", - "vitest": "^1.5.0" - }, "packageManager": "pnpm@10.12.1" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 58b89ddb..01c29bf1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,20 +6,7 @@ settings: importers: - .: - devDependencies: - '@napi-rs/cli': - specifier: 3.0.0-alpha.88 - version: 3.0.0-alpha.88(@emnapi/runtime@1.4.3)(emnapi@1.4.3) - '@napi-rs/wasm-runtime': - specifier: ^0.2.7 - version: 0.2.11 - emnapi: - specifier: ^1.4.3 - version: 1.4.3 - vitest: - specifier: ^1.5.0 - version: 1.6.1 + .: {} napi: devDependencies: @@ -316,19 +303,6 @@ packages: '@jridgewell/sourcemap-codec@1.5.0': resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} - '@napi-rs/cli@3.0.0-alpha.88': - resolution: {integrity: sha512-tAzLbGY+7JhRwAfeykv/Rl44mq3rufJzV5MuVQ2Nr+bMq6fr8winy0kV/myACDtYiXYx5Ax+XMHBKiLU2Xw5Ng==} - engines: {node: '>= 16'} - hasBin: true - peerDependencies: - '@emnapi/runtime': ^1.1.0 - emnapi: ^1.1.0 - peerDependenciesMeta: - '@emnapi/runtime': - optional: true - emnapi: - optional: true - '@napi-rs/cli@3.0.0-alpha.89': resolution: {integrity: sha512-Xi/B/unPVZJx12Qmj9+Z3+vfgmGdhp2tjtvH1VFjC6VrToh/i1fOBSv77j9WhYYWayFGhIit7nLcxQWxigXr8A==} engines: {node: '>= 16'} @@ -1433,34 +1407,6 @@ snapshots: '@jridgewell/sourcemap-codec@1.5.0': {} - '@napi-rs/cli@3.0.0-alpha.88(@emnapi/runtime@1.4.3)(emnapi@1.4.3)': - dependencies: - '@inquirer/prompts': 7.5.3 - '@napi-rs/cross-toolchain': 0.0.19 - '@napi-rs/wasm-tools': 0.0.3 - '@octokit/rest': 22.0.0 - clipanion: 4.0.0-rc.4(typanion@3.14.0) - colorette: 2.0.20 - debug: 4.4.1 - js-yaml: 4.1.0 - lodash-es: 4.17.21 - semver: 7.7.2 - toml: 3.0.0 - typanion: 3.14.0 - wasm-sjlj: 1.0.6 - optionalDependencies: - '@emnapi/runtime': 1.4.3 - emnapi: 1.4.3 - transitivePeerDependencies: - - '@napi-rs/cross-toolchain-arm64-target-aarch64' - - '@napi-rs/cross-toolchain-arm64-target-armv7' - - '@napi-rs/cross-toolchain-arm64-target-x86_64' - - '@napi-rs/cross-toolchain-x64-target-aarch64' - - '@napi-rs/cross-toolchain-x64-target-armv7' - - '@napi-rs/cross-toolchain-x64-target-x86_64' - - '@types/node' - - supports-color - '@napi-rs/cli@3.0.0-alpha.89(@emnapi/runtime@1.4.3)(emnapi@1.4.3)': dependencies: '@inquirer/prompts': 7.5.3 From 984fe39f86e3d50c3937568a5cfd63a9b747a89d Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 16:18:40 +0200 Subject: [PATCH 31/61] export a single parse function --- .github/workflows/release-napi.yml | 9 ++- napi/__tests__/parse.test.ts | 26 ++++---- napi/browser.js | 2 +- napi/index.d.ts | 6 +- napi/index.js | 97 +++++++++++++++--------------- napi/markdown-rs.wasi-browser.js | 1 - napi/markdown-rs.wasi.cjs | 5 +- napi/markdownrs.wasi-browser.js | 2 - napi/markdownrs.wasi.cjs | 2 - napi/src/lib.rs | 42 +++++++------ 10 files changed, 93 insertions(+), 99 deletions(-) diff --git a/.github/workflows/release-napi.yml b/.github/workflows/release-napi.yml index f73cbfbc..34c5e03b 100644 --- a/.github/workflows/release-napi.yml +++ b/.github/workflows/release-napi.yml @@ -133,6 +133,7 @@ jobs: - name: Build run: ${{ matrix.build }} shell: bash + working-directory: napi env: CC: clang # for mimalloc @@ -165,9 +166,9 @@ jobs: with: path: artifacts - - run: pnpm napi create-npm-dirs --package-json-path package.json + - run: pnpm napi create-npm-dirs --package-json-path napi/package.json - - run: pnpm napi artifacts --package-json-path package.json --npm-dir npm --build-output-dir napi + - run: pnpm napi artifacts --package-json-path napi/package.json --npm-dir npm --build-output-dir napi - name: Publish npm packages as latest env: @@ -175,9 +176,7 @@ jobs: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} run: | echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc - pnpm napi pre-publish --no-gh-release --tagstyle npm --package-json-path package.json --npm-dir npm + pnpm napi pre-publish --no-gh-release --tagstyle npm --package-json-path napi/package.json --npm-dir npm # Publish root package - cp package.json napi/package.json - cp readme.md napi/readme.md npm publish napi/ --tag latest --provenance --access public diff --git a/napi/__tests__/parse.test.ts b/napi/__tests__/parse.test.ts index 4dd4baeb..4ef7711a 100644 --- a/napi/__tests__/parse.test.ts +++ b/napi/__tests__/parse.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from "vitest"; -import { parse, parseMdx } from "../"; +import { parse } from "../"; -describe("parse mdx", () => { +describe("parse", () => { it("parse accepts options parameter", () => { const ast = parse("# Hello ~world~", { gfmStrikethroughSingleTilde: true, @@ -25,8 +25,9 @@ describe("parse mdx", () => { `); }); - it("parse_mdx accepts options parameter", () => { - const ast = parseMdx("# Hello {expression}", { + it("parse with mdx option accepts options parameter", () => { + const ast = parse("# Hello {expression}", { + mdx: true, mdxExpressionParse: true, gfmStrikethroughSingleTilde: false, }); @@ -80,8 +81,8 @@ describe("parse mdx", () => { `); }); - it("parse_mdx works without options parameter", () => { - const ast = parseMdx("# Hello {expression}"); + it("parse with mdx option works without other options", () => { + const ast = parse("# Hello {expression}", { mdx: true }); expect(stripPositions(ast)).toMatchInlineSnapshot(` { "children": [ @@ -193,8 +194,9 @@ describe("parse mdx", () => { `); }); - it("mdx options work in parseMdx", () => { - const ast = parseMdx("import foo from 'bar'\n\n{expression}", { + it("mdx options work with parse function", () => { + const ast = parse("import foo from 'bar'\n\n{expression}", { + mdx: true, mdxEsmParse: true, mdxExpressionParse: true, }); @@ -230,19 +232,19 @@ describe("parse mdx", () => { it("handles broken jsx in mdx without panic", () => { const error = catchErrorValue(() => - parseMdx(` + parse(` paragraph - `), + `, { mdx: true }), ); expect(error).toMatchInlineSnapshot( `[Error: Message { place: Some(Point(6:5 (39))), reason: "Expected a closing tag for \`\` (4:1)", rule_id: "end-tag-mismatch", source: "markdown-rs" }]`, ); }); it("returns mdast", () => { - const ast = parseMdx(` + const ast = parse(` import something from 'package' export const x = 9 @@ -258,7 +260,7 @@ here is some mdx {expression} this is a callout - `); + `, { mdx: true }); expect(stripPositions(ast)).toMatchInlineSnapshot(` { "children": [ diff --git a/napi/browser.js b/napi/browser.js index ea7f0c3d..afdffabd 100644 --- a/napi/browser.js +++ b/napi/browser.js @@ -1 +1 @@ -export * from '@xmorse/markdownrs-wasm32-wasi' +export * from '@xmorse/markdown-rs-binding-wasm32-wasi' diff --git a/napi/index.d.ts b/napi/index.d.ts index 0b1e0789..4c912b61 100644 --- a/napi/index.d.ts +++ b/napi/index.d.ts @@ -2,9 +2,9 @@ /* eslint-disable */ export declare function parse(input: string, options?: ParseOptions | undefined | null): any -export declare function parseMdx(mdx: string, options?: ParseOptions | undefined | null): any - export interface ParseOptions { + /** Whether to parse as MDX */ + mdx?: boolean /** Whether to support GFM strikethrough with a single tilde */ gfmStrikethroughSingleTilde?: boolean /** Whether to support math (text) with a single dollar */ @@ -14,5 +14,3 @@ export interface ParseOptions { /** Whether to enable basic MDX ESM parsing */ mdxEsmParse?: boolean } - -export declare function toHtml(mdx: string): any diff --git a/napi/index.js b/napi/index.js index a229e323..05308f0e 100644 --- a/napi/index.js +++ b/napi/index.js @@ -73,24 +73,24 @@ function requireNative() { } else if (process.platform === 'android') { if (process.arch === 'arm64') { try { - return require('./markdownrs.android-arm64.node') + return require('./markdown-rs.android-arm64.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdownrs-android-arm64') + return require('@xmorse/markdown-rs-binding-android-arm64') } catch (e) { loadErrors.push(e) } } else if (process.arch === 'arm') { try { - return require('./markdownrs.android-arm-eabi.node') + return require('./markdown-rs.android-arm-eabi.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdownrs-android-arm-eabi') + return require('@xmorse/markdown-rs-binding-android-arm-eabi') } catch (e) { loadErrors.push(e) } @@ -101,36 +101,36 @@ function requireNative() { } else if (process.platform === 'win32') { if (process.arch === 'x64') { try { - return require('./markdownrs.win32-x64-msvc.node') + return require('./markdown-rs.win32-x64-msvc.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdownrs-win32-x64-msvc') + return require('@xmorse/markdown-rs-binding-win32-x64-msvc') } catch (e) { loadErrors.push(e) } } else if (process.arch === 'ia32') { try { - return require('./markdownrs.win32-ia32-msvc.node') + return require('./markdown-rs.win32-ia32-msvc.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdownrs-win32-ia32-msvc') + return require('@xmorse/markdown-rs-binding-win32-ia32-msvc') } catch (e) { loadErrors.push(e) } } else if (process.arch === 'arm64') { try { - return require('./markdownrs.win32-arm64-msvc.node') + return require('./markdown-rs.win32-arm64-msvc.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdownrs-win32-arm64-msvc') + return require('@xmorse/markdown-rs-binding-win32-arm64-msvc') } catch (e) { loadErrors.push(e) } @@ -140,36 +140,36 @@ function requireNative() { } } else if (process.platform === 'darwin') { try { - return require('./markdownrs.darwin-universal.node') + return require('./markdown-rs.darwin-universal.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdownrs-darwin-universal') + return require('@xmorse/markdown-rs-binding-darwin-universal') } catch (e) { loadErrors.push(e) } if (process.arch === 'x64') { try { - return require('./markdownrs.darwin-x64.node') + return require('./markdown-rs.darwin-x64.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdownrs-darwin-x64') + return require('@xmorse/markdown-rs-binding-darwin-x64') } catch (e) { loadErrors.push(e) } } else if (process.arch === 'arm64') { try { - return require('./markdownrs.darwin-arm64.node') + return require('./markdown-rs.darwin-arm64.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdownrs-darwin-arm64') + return require('@xmorse/markdown-rs-binding-darwin-arm64') } catch (e) { loadErrors.push(e) } @@ -180,24 +180,24 @@ function requireNative() { } else if (process.platform === 'freebsd') { if (process.arch === 'x64') { try { - return require('./markdownrs.freebsd-x64.node') + return require('./markdown-rs.freebsd-x64.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdownrs-freebsd-x64') + return require('@xmorse/markdown-rs-binding-freebsd-x64') } catch (e) { loadErrors.push(e) } } else if (process.arch === 'arm64') { try { - return require('./markdownrs.freebsd-arm64.node') + return require('./markdown-rs.freebsd-arm64.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdownrs-freebsd-arm64') + return require('@xmorse/markdown-rs-binding-freebsd-arm64') } catch (e) { loadErrors.push(e) } @@ -209,24 +209,24 @@ function requireNative() { if (process.arch === 'x64') { if (isMusl()) { try { - return require('./markdownrs.linux-x64-musl.node') + return require('./markdown-rs.linux-x64-musl.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdownrs-linux-x64-musl') + return require('@xmorse/markdown-rs-binding-linux-x64-musl') } catch (e) { loadErrors.push(e) } } else { try { - return require('./markdownrs.linux-x64-gnu.node') + return require('./markdown-rs.linux-x64-gnu.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdownrs-linux-x64-gnu') + return require('@xmorse/markdown-rs-binding-linux-x64-gnu') } catch (e) { loadErrors.push(e) } @@ -235,24 +235,24 @@ function requireNative() { } else if (process.arch === 'arm64') { if (isMusl()) { try { - return require('./markdownrs.linux-arm64-musl.node') + return require('./markdown-rs.linux-arm64-musl.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdownrs-linux-arm64-musl') + return require('@xmorse/markdown-rs-binding-linux-arm64-musl') } catch (e) { loadErrors.push(e) } } else { try { - return require('./markdownrs.linux-arm64-gnu.node') + return require('./markdown-rs.linux-arm64-gnu.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdownrs-linux-arm64-gnu') + return require('@xmorse/markdown-rs-binding-linux-arm64-gnu') } catch (e) { loadErrors.push(e) } @@ -261,24 +261,24 @@ function requireNative() { } else if (process.arch === 'arm') { if (isMusl()) { try { - return require('./markdownrs.linux-arm-musleabihf.node') + return require('./markdown-rs.linux-arm-musleabihf.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdownrs-linux-arm-musleabihf') + return require('@xmorse/markdown-rs-binding-linux-arm-musleabihf') } catch (e) { loadErrors.push(e) } } else { try { - return require('./markdownrs.linux-arm-gnueabihf.node') + return require('./markdown-rs.linux-arm-gnueabihf.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdownrs-linux-arm-gnueabihf') + return require('@xmorse/markdown-rs-binding-linux-arm-gnueabihf') } catch (e) { loadErrors.push(e) } @@ -287,24 +287,24 @@ function requireNative() { } else if (process.arch === 'riscv64') { if (isMusl()) { try { - return require('./markdownrs.linux-riscv64-musl.node') + return require('./markdown-rs.linux-riscv64-musl.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdownrs-linux-riscv64-musl') + return require('@xmorse/markdown-rs-binding-linux-riscv64-musl') } catch (e) { loadErrors.push(e) } } else { try { - return require('./markdownrs.linux-riscv64-gnu.node') + return require('./markdown-rs.linux-riscv64-gnu.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdownrs-linux-riscv64-gnu') + return require('@xmorse/markdown-rs-binding-linux-riscv64-gnu') } catch (e) { loadErrors.push(e) } @@ -312,24 +312,24 @@ function requireNative() { } } else if (process.arch === 'ppc64') { try { - return require('./markdownrs.linux-ppc64-gnu.node') + return require('./markdown-rs.linux-ppc64-gnu.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdownrs-linux-ppc64-gnu') + return require('@xmorse/markdown-rs-binding-linux-ppc64-gnu') } catch (e) { loadErrors.push(e) } } else if (process.arch === 's390x') { try { - return require('./markdownrs.linux-s390x-gnu.node') + return require('./markdown-rs.linux-s390x-gnu.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdownrs-linux-s390x-gnu') + return require('@xmorse/markdown-rs-binding-linux-s390x-gnu') } catch (e) { loadErrors.push(e) } @@ -346,7 +346,7 @@ nativeBinding = requireNative() if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) { try { - nativeBinding = require('./markdownrs.wasi.cjs') + nativeBinding = require('./markdown-rs.wasi.cjs') } catch (err) { if (process.env.NAPI_RS_FORCE_WASI) { loadErrors.push(err) @@ -354,7 +354,7 @@ if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) { } if (!nativeBinding) { try { - nativeBinding = require('@xmorse/markdownrs-wasm32-wasi') + nativeBinding = require('@xmorse/markdown-rs-binding-wasm32-wasi') } catch (err) { if (process.env.NAPI_RS_FORCE_WASI) { loadErrors.push(err) @@ -365,16 +365,15 @@ if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) { if (!nativeBinding) { if (loadErrors.length > 0) { - // TODO Link to documentation with potential fixes - // - The package owner could build/publish bindings for this arch - // - The user may need to bundle the correct files - // - The user may need to re-install node_modules to get new packages - throw new Error('Failed to load native binding', { cause: loadErrors }) + throw new Error( + `Cannot find native binding. ` + + `npm has a bug related to optional dependencies (https://github.com/npm/cli/issues/4828). ` + + 'Please try `npm i` again after removing both package-lock.json and node_modules directory.', + { cause: loadErrors } + ) } throw new Error(`Failed to load native binding`) } module.exports = nativeBinding module.exports.parse = nativeBinding.parse -module.exports.parseMdx = nativeBinding.parseMdx -module.exports.toHtml = nativeBinding.toHtml diff --git a/napi/markdown-rs.wasi-browser.js b/napi/markdown-rs.wasi-browser.js index db2a630c..074802bf 100644 --- a/napi/markdown-rs.wasi-browser.js +++ b/napi/markdown-rs.wasi-browser.js @@ -55,4 +55,3 @@ const { }) export default __napiModule.exports export const parse = __napiModule.exports.parse -export const parseMdx = __napiModule.exports.parseMdx diff --git a/napi/markdown-rs.wasi.cjs b/napi/markdown-rs.wasi.cjs index c4541d1b..dd5bd273 100644 --- a/napi/markdown-rs.wasi.cjs +++ b/napi/markdown-rs.wasi.cjs @@ -39,9 +39,9 @@ if (__nodeFs.existsSync(__wasmDebugFilePath)) { __wasmFilePath = __wasmDebugFilePath } else if (!__nodeFs.existsSync(__wasmFilePath)) { try { - __wasmFilePath = __nodePath.resolve('markdown-rs-binding-wasm32-wasi') + __wasmFilePath = __nodePath.resolve('@xmorse/markdown-rs-binding-wasm32-wasi') } catch { - throw new Error('Cannot find markdown-rs.wasm32-wasi.wasm file, and markdown-rs-binding-wasm32-wasi package is not installed.') + throw new Error('Cannot find markdown-rs.wasm32-wasi.wasm file, and @xmorse/markdown-rs-binding-wasm32-wasi package is not installed.') } } @@ -86,4 +86,3 @@ const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule }) module.exports = __napiModule.exports module.exports.parse = __napiModule.exports.parse -module.exports.parseMdx = __napiModule.exports.parseMdx diff --git a/napi/markdownrs.wasi-browser.js b/napi/markdownrs.wasi-browser.js index 4228d415..0e8b8ed7 100644 --- a/napi/markdownrs.wasi-browser.js +++ b/napi/markdownrs.wasi-browser.js @@ -55,5 +55,3 @@ const { }) export default __napiModule.exports export const parse = __napiModule.exports.parse -export const parseMdx = __napiModule.exports.parseMdx -export const toHtml = __napiModule.exports.toHtml diff --git a/napi/markdownrs.wasi.cjs b/napi/markdownrs.wasi.cjs index bb7daba2..3ecaf29e 100644 --- a/napi/markdownrs.wasi.cjs +++ b/napi/markdownrs.wasi.cjs @@ -86,5 +86,3 @@ const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule }) module.exports = __napiModule.exports module.exports.parse = __napiModule.exports.parse -module.exports.parseMdx = __napiModule.exports.parseMdx -module.exports.toHtml = __napiModule.exports.toHtml diff --git a/napi/src/lib.rs b/napi/src/lib.rs index 53579982..08547663 100644 --- a/napi/src/lib.rs +++ b/napi/src/lib.rs @@ -5,6 +5,8 @@ use markdown::{MdxExpressionKind, MdxSignal}; #[napi(object)] pub struct ParseOptions { + /// Whether to parse as MDX + pub mdx: Option, /// Whether to support GFM strikethrough with a single tilde pub gfm_strikethrough_single_tilde: Option, /// Whether to support math (text) with a single dollar @@ -43,36 +45,36 @@ impl ParseOptions { #[napi] pub fn parse(input: String, options: Option) -> Result { - let parse_options = match options { - Some(opts) => opts.to_rust_parse_options(), + let mut parse_options = match &options { + Some(opts) => { + if opts.mdx.unwrap_or(false) { + markdown::ParseOptions { + constructs: markdown::Constructs::mdx(), + ..Default::default() + } + } else { + markdown::ParseOptions::default() + } + } None => markdown::ParseOptions::default(), }; - let tree = markdown::to_mdast(&input, &parse_options) - .map_err(|e| Error::from_reason(format!("{:?}", e)))?; - serde_json::to_value(&tree).map_err(|e| Error::from_reason(e.to_string())) -} - -#[napi] -pub fn parse_mdx(mdx: String, options: Option) -> Result { - let mut mdx_options = markdown::ParseOptions { - constructs: markdown::Constructs::mdx(), - ..Default::default() - }; - // Override with user-provided options if available if let Some(opts) = options { let user_options = opts.to_rust_parse_options(); - mdx_options.gfm_strikethrough_single_tilde = user_options.gfm_strikethrough_single_tilde; - mdx_options.math_text_single_dollar = user_options.math_text_single_dollar; - mdx_options.mdx_expression_parse = user_options.mdx_expression_parse; - mdx_options.mdx_esm_parse = user_options.mdx_esm_parse; + parse_options.gfm_strikethrough_single_tilde = user_options.gfm_strikethrough_single_tilde; + parse_options.math_text_single_dollar = user_options.math_text_single_dollar; + parse_options.mdx_expression_parse = user_options.mdx_expression_parse; + parse_options.mdx_esm_parse = user_options.mdx_esm_parse; } - let ast = markdown::to_mdast(&mdx, &mdx_options).map_err(|e| Error::from_reason(format!("{:?}", e)))?; - serde_json::to_value(&ast).map_err(|e| Error::from_reason(e.to_string())) + let tree = markdown::to_mdast(&input, &parse_options) + .map_err(|e| Error::from_reason(format!("{:?}", e)))?; + serde_json::to_value(&tree).map_err(|e| Error::from_reason(e.to_string())) } + + // #[napi] // pub fn to_html(mdx: String) -> Value { // let html = markdown::to_html(&mdx); From 1a0f8a2a90815b3393502038eda85a510f251a73 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 16:27:41 +0200 Subject: [PATCH 32/61] added split_into_sections --- napi/__tests__/parse.test.ts | 371 ++++++++++++++++++++++++++++++- napi/index.d.ts | 11 + napi/index.js | 1 + napi/markdown-rs.wasi-browser.js | 1 + napi/markdown-rs.wasi.cjs | 1 + napi/src/lib.rs | 88 +++++++- 6 files changed, 469 insertions(+), 4 deletions(-) diff --git a/napi/__tests__/parse.test.ts b/napi/__tests__/parse.test.ts index 4ef7711a..c2ece4a1 100644 --- a/napi/__tests__/parse.test.ts +++ b/napi/__tests__/parse.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { parse } from "../"; +import { parse, splitIntoSections } from "../"; describe("parse", () => { it("parse accepts options parameter", () => { @@ -229,7 +229,6 @@ describe("parse", () => { `); }); - it("handles broken jsx in mdx without panic", () => { const error = catchErrorValue(() => parse(` @@ -243,6 +242,7 @@ paragraph `[Error: Message { place: Some(Point(6:5 (39))), reason: "Expected a closing tag for \`\` (4:1)", rule_id: "end-tag-mismatch", source: "markdown-rs" }]`, ); }); + it("returns mdast", () => { const ast = parse(` import something from 'package' @@ -355,6 +355,371 @@ this is a callout }); }); +describe("split_into_sections", () => { + it("splits basic markdown into sections", () => { + const sections = splitIntoSections(`# Hello World + +This is a paragraph. + +## Subheading + +Another paragraph.`); + + expect(sections).toMatchInlineSnapshot(` + [ + { + "position": { + "end": { + "column": 14, + "line": 1, + "offset": 13, + }, + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "raw": "# Hello World", + "type": "heading", + }, + { + "position": { + "end": { + "column": 21, + "line": 3, + "offset": 35, + }, + "start": { + "column": 1, + "line": 3, + "offset": 15, + }, + }, + "raw": "This is a paragraph.", + "type": "paragraph", + }, + { + "position": { + "end": { + "column": 14, + "line": 5, + "offset": 50, + }, + "start": { + "column": 1, + "line": 5, + "offset": 37, + }, + }, + "raw": "## Subheading", + "type": "heading", + }, + { + "position": { + "end": { + "column": 19, + "line": 7, + "offset": 70, + }, + "start": { + "column": 1, + "line": 7, + "offset": 52, + }, + }, + "raw": "Another paragraph.", + "type": "paragraph", + }, + ] + `); + }); + + it("handles empty content", () => { + const sections = splitIntoSections(""); + expect(sections).toMatchInlineSnapshot(`[]`); + }); + + it("works with single element", () => { + const sections = splitIntoSections("# Single Heading"); + expect(sections).toMatchInlineSnapshot(` + [ + { + "position": { + "end": { + "column": 17, + "line": 1, + "offset": 16, + }, + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "raw": "# Single Heading", + "type": "heading", + }, + ] + `); + }); + + it("works with different markdown elements", () => { + const content = `# Heading + +Paragraph with **bold** text. + +> Blockquote here + +- List item 1 +- List item 2 + +\`\`\`javascript +const code = "block"; +\`\`\``; + + const sections = splitIntoSections(content); + expect(sections).toMatchInlineSnapshot(` + [ + { + "position": { + "end": { + "column": 10, + "line": 1, + "offset": 9, + }, + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "raw": "# Heading", + "type": "heading", + }, + { + "position": { + "end": { + "column": 30, + "line": 3, + "offset": 40, + }, + "start": { + "column": 1, + "line": 3, + "offset": 11, + }, + }, + "raw": "Paragraph with **bold** text.", + "type": "paragraph", + }, + { + "position": { + "end": { + "column": 18, + "line": 5, + "offset": 59, + }, + "start": { + "column": 1, + "line": 5, + "offset": 42, + }, + }, + "raw": "> Blockquote here", + "type": "blockquote", + }, + { + "position": { + "end": { + "column": 1, + "line": 9, + "offset": 89, + }, + "start": { + "column": 1, + "line": 7, + "offset": 61, + }, + }, + "raw": "- List item 1 + - List item 2 + ", + "type": "list", + }, + { + "position": { + "end": { + "column": 4, + "line": 12, + "offset": 129, + }, + "start": { + "column": 1, + "line": 10, + "offset": 90, + }, + }, + "raw": "\`\`\`javascript + const code = "block"; + \`\`\`", + "type": "code", + }, + ] + `); + }); + + it("works with MDX content", () => { + const sections = splitIntoSections(`import React from 'react' + +# MDX Document + + + Content +`, { mdx: true }); + + expect(sections).toMatchInlineSnapshot(` + [ + { + "position": { + "end": { + "column": 26, + "line": 1, + "offset": 25, + }, + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "raw": "import React from 'react'", + "type": "paragraph", + }, + { + "position": { + "end": { + "column": 15, + "line": 3, + "offset": 41, + }, + "start": { + "column": 1, + "line": 3, + "offset": 27, + }, + }, + "raw": "# MDX Document", + "type": "heading", + }, + { + "position": { + "end": { + "column": 13, + "line": 7, + "offset": 90, + }, + "start": { + "column": 1, + "line": 5, + "offset": 43, + }, + }, + "raw": " + Content + ", + "type": "mdxJsxFlowElement", + }, + ] + `); + }); + + it("works with MDX and expression parsing enabled", () => { + const sections = splitIntoSections(`# Hello {world} + +{expression} + +`, { + mdx: true, + mdxExpressionParse: true + }); + + expect(sections).toMatchInlineSnapshot(` + [ + { + "position": { + "end": { + "column": 16, + "line": 1, + "offset": 15, + }, + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "raw": "# Hello {world}", + "type": "heading", + }, + { + "position": { + "end": { + "column": 13, + "line": 3, + "offset": 29, + }, + "start": { + "column": 1, + "line": 3, + "offset": 17, + }, + }, + "raw": "{expression}", + "type": "mdxFlowExpression", + }, + { + "position": { + "end": { + "column": 14, + "line": 5, + "offset": 44, + }, + "start": { + "column": 1, + "line": 5, + "offset": 31, + }, + }, + "raw": "", + "type": "mdxJsxFlowElement", + }, + ] + `); + }); + + it("preserves exact raw text with complex formatting", () => { + const content = "# Title\n\nParagraph with *emphasis* and `code`."; + const sections = splitIntoSections(content); + + expect(sections[0].raw).toBe("# Title"); + expect(sections[1].raw).toBe("Paragraph with *emphasis* and `code`."); + expect(sections[0].type).toBe("heading"); + expect(sections[1].type).toBe("paragraph"); + }); + + it("accepts parse options", () => { + const sections = splitIntoSections("# Title\n\nSome content", { + gfmStrikethroughSingleTilde: false, + mathTextSingleDollar: true + }); + + expect(sections).toHaveLength(2); + expect(sections[0].type).toBe("heading"); + expect(sections[1].type).toBe("paragraph"); + }); +}); + /** * Removes all "position" fields from an mdast/unist tree node (in-place). * @param node - The tree node to clean. @@ -387,4 +752,4 @@ export function catchErrorValue(fn: () => T): T | Error { } catch (e) { return e; } -} +} \ No newline at end of file diff --git a/napi/index.d.ts b/napi/index.d.ts index 4c912b61..0e252d98 100644 --- a/napi/index.d.ts +++ b/napi/index.d.ts @@ -14,3 +14,14 @@ export interface ParseOptions { /** Whether to enable basic MDX ESM parsing */ mdxEsmParse?: boolean } + +export interface Section { + /** Raw text content of the section */ + raw: string + /** Type of the section (e.g., "heading", "paragraph", etc.) */ + type: string + /** Position information */ + position?: any +} + +export declare function splitIntoSections(input: string, options?: ParseOptions | undefined | null): Array
diff --git a/napi/index.js b/napi/index.js index 05308f0e..b4f78cc2 100644 --- a/napi/index.js +++ b/napi/index.js @@ -377,3 +377,4 @@ if (!nativeBinding) { module.exports = nativeBinding module.exports.parse = nativeBinding.parse +module.exports.splitIntoSections = nativeBinding.splitIntoSections diff --git a/napi/markdown-rs.wasi-browser.js b/napi/markdown-rs.wasi-browser.js index 074802bf..06b73208 100644 --- a/napi/markdown-rs.wasi-browser.js +++ b/napi/markdown-rs.wasi-browser.js @@ -55,3 +55,4 @@ const { }) export default __napiModule.exports export const parse = __napiModule.exports.parse +export const splitIntoSections = __napiModule.exports.splitIntoSections diff --git a/napi/markdown-rs.wasi.cjs b/napi/markdown-rs.wasi.cjs index dd5bd273..21b9ee66 100644 --- a/napi/markdown-rs.wasi.cjs +++ b/napi/markdown-rs.wasi.cjs @@ -86,3 +86,4 @@ const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule }) module.exports = __napiModule.exports module.exports.parse = __napiModule.exports.parse +module.exports.splitIntoSections = __napiModule.exports.splitIntoSections diff --git a/napi/src/lib.rs b/napi/src/lib.rs index 08547663..44905176 100644 --- a/napi/src/lib.rs +++ b/napi/src/lib.rs @@ -1,7 +1,7 @@ +use markdown::{MdxExpressionKind, MdxSignal}; use napi::{bindgen_prelude::*, Error}; use napi_derive::napi; use serde_json::Value; -use markdown::{MdxExpressionKind, MdxSignal}; #[napi(object)] pub struct ParseOptions { @@ -17,6 +17,16 @@ pub struct ParseOptions { pub mdx_esm_parse: Option, } +#[napi(object)] +pub struct Section { + /// Raw text content of the section + pub raw: String, + /// Type of the section (e.g., "heading", "paragraph", etc.) + pub r#type: String, + /// Position information + pub position: Option, +} + impl ParseOptions { fn to_rust_parse_options(&self) -> markdown::ParseOptions { markdown::ParseOptions { @@ -73,7 +83,83 @@ pub fn parse(input: String, options: Option) -> Result { serde_json::to_value(&tree).map_err(|e| Error::from_reason(e.to_string())) } +#[napi] +pub fn split_into_sections(input: String, options: Option) -> Result> { + let mut parse_options = match &options { + Some(opts) => { + if opts.mdx.unwrap_or(false) { + markdown::ParseOptions { + constructs: markdown::Constructs::mdx(), + ..Default::default() + } + } else { + markdown::ParseOptions::default() + } + } + None => markdown::ParseOptions::default(), + }; + + // Override with user-provided options if available + if let Some(opts) = options { + let user_options = opts.to_rust_parse_options(); + parse_options.gfm_strikethrough_single_tilde = user_options.gfm_strikethrough_single_tilde; + parse_options.math_text_single_dollar = user_options.math_text_single_dollar; + parse_options.mdx_expression_parse = user_options.mdx_expression_parse; + parse_options.mdx_esm_parse = user_options.mdx_esm_parse; + } + + let tree = markdown::to_mdast(&input, &parse_options) + .map_err(|e| Error::from_reason(format!("{:?}", e)))?; + + // Convert AST to JSON to extract children + let ast_value = serde_json::to_value(&tree).map_err(|e| Error::from_reason(e.to_string()))?; + let mut sections = Vec::new(); + + if let Some(children) = ast_value.get("children").and_then(|c| c.as_array()) { + for child in children { + let node_type = child + .get("type") + .and_then(|t| t.as_str()) + .unwrap_or("unknown") + .to_string(); + + let position = child.get("position").cloned(); + + // Extract raw text from position + let raw = if let Some(pos) = &position { + if let (Some(start), Some(end)) = ( + pos.get("start") + .and_then(|s| s.get("offset")) + .and_then(|o| o.as_u64()), + pos.get("end") + .and_then(|e| e.get("offset")) + .and_then(|o| o.as_u64()), + ) { + let start_idx = start as usize; + let end_idx = end as usize; + if start_idx <= input.len() && end_idx <= input.len() && start_idx <= end_idx { + input[start_idx..end_idx].to_string() + } else { + String::new() + } + } else { + String::new() + } + } else { + String::new() + }; + + sections.push(Section { + raw, + r#type: node_type, + position, + }); + } + } + + Ok(sections) +} // #[napi] // pub fn to_html(mdx: String) -> Value { From 080f50257f6a4f57b31991e22439f9cb7e70cd90 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 16:29:37 +0200 Subject: [PATCH 33/61] add dep --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index 67d3185a..6cb1bf6b 100644 --- a/package.json +++ b/package.json @@ -5,5 +5,8 @@ "build": "pnpm run build:debug --release", "npm-dirs": "pnpm napi create-npm-dirs --package-json-path package.json" }, + "dependencies": { + "@napi-rs/cli": "3.0.0-alpha.89" + }, "packageManager": "pnpm@10.12.1" } From a5bd835754bf9a87adc2cfca691090609be2da28 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 16:29:53 +0200 Subject: [PATCH 34/61] nn --- napi/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/napi/package.json b/napi/package.json index b7dec1dc..77757673 100644 --- a/napi/package.json +++ b/napi/package.json @@ -1,6 +1,6 @@ { "name": "@xmorse/markdown-rs", - "version": "0.0.0", + "version": "0.0.2", "scripts": { "build:debug": "pnpm napi build --platform --manifest-path Cargo.toml", "test": "pnpm vitest", From aec84a5f2b118e63dd9a7aae6730f3411e98a31f Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 16:30:21 +0200 Subject: [PATCH 35/61] nn --- napi/index.js | 84 +++++++++++++++++++++++++------------------------- pnpm-lock.yaml | 6 +++- 2 files changed, 47 insertions(+), 43 deletions(-) diff --git a/napi/index.js b/napi/index.js index b4f78cc2..7e13ed3f 100644 --- a/napi/index.js +++ b/napi/index.js @@ -73,24 +73,24 @@ function requireNative() { } else if (process.platform === 'android') { if (process.arch === 'arm64') { try { - return require('./markdown-rs.android-arm64.node') + return require('./index.android-arm64.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdown-rs-binding-android-arm64') + return require('root-android-arm64') } catch (e) { loadErrors.push(e) } } else if (process.arch === 'arm') { try { - return require('./markdown-rs.android-arm-eabi.node') + return require('./index.android-arm-eabi.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdown-rs-binding-android-arm-eabi') + return require('root-android-arm-eabi') } catch (e) { loadErrors.push(e) } @@ -101,36 +101,36 @@ function requireNative() { } else if (process.platform === 'win32') { if (process.arch === 'x64') { try { - return require('./markdown-rs.win32-x64-msvc.node') + return require('./index.win32-x64-msvc.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdown-rs-binding-win32-x64-msvc') + return require('root-win32-x64-msvc') } catch (e) { loadErrors.push(e) } } else if (process.arch === 'ia32') { try { - return require('./markdown-rs.win32-ia32-msvc.node') + return require('./index.win32-ia32-msvc.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdown-rs-binding-win32-ia32-msvc') + return require('root-win32-ia32-msvc') } catch (e) { loadErrors.push(e) } } else if (process.arch === 'arm64') { try { - return require('./markdown-rs.win32-arm64-msvc.node') + return require('./index.win32-arm64-msvc.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdown-rs-binding-win32-arm64-msvc') + return require('root-win32-arm64-msvc') } catch (e) { loadErrors.push(e) } @@ -140,36 +140,36 @@ function requireNative() { } } else if (process.platform === 'darwin') { try { - return require('./markdown-rs.darwin-universal.node') + return require('./index.darwin-universal.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdown-rs-binding-darwin-universal') + return require('root-darwin-universal') } catch (e) { loadErrors.push(e) } if (process.arch === 'x64') { try { - return require('./markdown-rs.darwin-x64.node') + return require('./index.darwin-x64.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdown-rs-binding-darwin-x64') + return require('root-darwin-x64') } catch (e) { loadErrors.push(e) } } else if (process.arch === 'arm64') { try { - return require('./markdown-rs.darwin-arm64.node') + return require('./index.darwin-arm64.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdown-rs-binding-darwin-arm64') + return require('root-darwin-arm64') } catch (e) { loadErrors.push(e) } @@ -180,24 +180,24 @@ function requireNative() { } else if (process.platform === 'freebsd') { if (process.arch === 'x64') { try { - return require('./markdown-rs.freebsd-x64.node') + return require('./index.freebsd-x64.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdown-rs-binding-freebsd-x64') + return require('root-freebsd-x64') } catch (e) { loadErrors.push(e) } } else if (process.arch === 'arm64') { try { - return require('./markdown-rs.freebsd-arm64.node') + return require('./index.freebsd-arm64.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdown-rs-binding-freebsd-arm64') + return require('root-freebsd-arm64') } catch (e) { loadErrors.push(e) } @@ -209,24 +209,24 @@ function requireNative() { if (process.arch === 'x64') { if (isMusl()) { try { - return require('./markdown-rs.linux-x64-musl.node') + return require('./index.linux-x64-musl.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdown-rs-binding-linux-x64-musl') + return require('root-linux-x64-musl') } catch (e) { loadErrors.push(e) } } else { try { - return require('./markdown-rs.linux-x64-gnu.node') + return require('./index.linux-x64-gnu.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdown-rs-binding-linux-x64-gnu') + return require('root-linux-x64-gnu') } catch (e) { loadErrors.push(e) } @@ -235,24 +235,24 @@ function requireNative() { } else if (process.arch === 'arm64') { if (isMusl()) { try { - return require('./markdown-rs.linux-arm64-musl.node') + return require('./index.linux-arm64-musl.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdown-rs-binding-linux-arm64-musl') + return require('root-linux-arm64-musl') } catch (e) { loadErrors.push(e) } } else { try { - return require('./markdown-rs.linux-arm64-gnu.node') + return require('./index.linux-arm64-gnu.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdown-rs-binding-linux-arm64-gnu') + return require('root-linux-arm64-gnu') } catch (e) { loadErrors.push(e) } @@ -261,24 +261,24 @@ function requireNative() { } else if (process.arch === 'arm') { if (isMusl()) { try { - return require('./markdown-rs.linux-arm-musleabihf.node') + return require('./index.linux-arm-musleabihf.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdown-rs-binding-linux-arm-musleabihf') + return require('root-linux-arm-musleabihf') } catch (e) { loadErrors.push(e) } } else { try { - return require('./markdown-rs.linux-arm-gnueabihf.node') + return require('./index.linux-arm-gnueabihf.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdown-rs-binding-linux-arm-gnueabihf') + return require('root-linux-arm-gnueabihf') } catch (e) { loadErrors.push(e) } @@ -287,24 +287,24 @@ function requireNative() { } else if (process.arch === 'riscv64') { if (isMusl()) { try { - return require('./markdown-rs.linux-riscv64-musl.node') + return require('./index.linux-riscv64-musl.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdown-rs-binding-linux-riscv64-musl') + return require('root-linux-riscv64-musl') } catch (e) { loadErrors.push(e) } } else { try { - return require('./markdown-rs.linux-riscv64-gnu.node') + return require('./index.linux-riscv64-gnu.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdown-rs-binding-linux-riscv64-gnu') + return require('root-linux-riscv64-gnu') } catch (e) { loadErrors.push(e) } @@ -312,24 +312,24 @@ function requireNative() { } } else if (process.arch === 'ppc64') { try { - return require('./markdown-rs.linux-ppc64-gnu.node') + return require('./index.linux-ppc64-gnu.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdown-rs-binding-linux-ppc64-gnu') + return require('root-linux-ppc64-gnu') } catch (e) { loadErrors.push(e) } } else if (process.arch === 's390x') { try { - return require('./markdown-rs.linux-s390x-gnu.node') + return require('./index.linux-s390x-gnu.node') } catch (e) { loadErrors.push(e) } try { - return require('@xmorse/markdown-rs-binding-linux-s390x-gnu') + return require('root-linux-s390x-gnu') } catch (e) { loadErrors.push(e) } @@ -346,7 +346,7 @@ nativeBinding = requireNative() if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) { try { - nativeBinding = require('./markdown-rs.wasi.cjs') + nativeBinding = require('./index.wasi.cjs') } catch (err) { if (process.env.NAPI_RS_FORCE_WASI) { loadErrors.push(err) @@ -354,7 +354,7 @@ if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) { } if (!nativeBinding) { try { - nativeBinding = require('@xmorse/markdown-rs-binding-wasm32-wasi') + nativeBinding = require('root-wasm32-wasi') } catch (err) { if (process.env.NAPI_RS_FORCE_WASI) { loadErrors.push(err) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 01c29bf1..4bae6c93 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,7 +6,11 @@ settings: importers: - .: {} + .: + dependencies: + '@napi-rs/cli': + specifier: 3.0.0-alpha.89 + version: 3.0.0-alpha.89(@emnapi/runtime@1.4.3)(emnapi@1.4.3) napi: devDependencies: From 4901324dc66c8bf9d50cc4b0018b192d73169866 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 16:31:06 +0200 Subject: [PATCH 36/61] publishConfig --- napi/package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/napi/package.json b/napi/package.json index 77757673..2979005d 100644 --- a/napi/package.json +++ b/napi/package.json @@ -6,6 +6,9 @@ "test": "pnpm vitest", "build": "pnpm run build:debug --release" }, + "publishConfig": { + "access": "public" + }, "napi": { "binaryName": "markdown-rs", "packageName": "@xmorse/markdown-rs-binding", From 81c38eec9c4ecc590e76d8d788793a612dc865a2 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 16:31:27 +0200 Subject: [PATCH 37/61] nn --- napi/package.json | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/napi/package.json b/napi/package.json index 2979005d..34a4d4d3 100644 --- a/napi/package.json +++ b/napi/package.json @@ -36,19 +36,5 @@ "@napi-rs/cli": "3.0.0-alpha.89", "emnapi": "^1.4.3", "vitest": "^1.5.0" - }, - "optionalDependencies": { - "@xmorse/markdown-rs-binding-darwin-x64": "0.0.0", - "@xmorse/markdown-rs-binding-win32-x64-msvc": "0.0.0", - "@xmorse/markdown-rs-binding-linux-x64-gnu": "0.0.0", - "@xmorse/markdown-rs-binding-linux-x64-musl": "0.0.0", - "@xmorse/markdown-rs-binding-freebsd-x64": "0.0.0", - "@xmorse/markdown-rs-binding-win32-ia32-msvc": "0.0.0", - "@xmorse/markdown-rs-binding-linux-arm-gnueabihf": "0.0.0", - "@xmorse/markdown-rs-binding-linux-arm64-gnu": "0.0.0", - "@xmorse/markdown-rs-binding-darwin-arm64": "0.0.0", - "@xmorse/markdown-rs-binding-linux-arm64-musl": "0.0.0", - "@xmorse/markdown-rs-binding-win32-arm64-msvc": "0.0.0", - "@xmorse/markdown-rs-binding-wasm32-wasi": "0.0.0" } } From 7aa0b534f69e7327b8242bd5de12a3efd38bcb6e Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 16:32:13 +0200 Subject: [PATCH 38/61] fix targets --- napi/package.json | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/napi/package.json b/napi/package.json index 34a4d4d3..a5f401a9 100644 --- a/napi/package.json +++ b/napi/package.json @@ -13,17 +13,16 @@ "binaryName": "markdown-rs", "packageName": "@xmorse/markdown-rs-binding", "targets": [ - "x86_64-apple-darwin", - "x86_64-pc-windows-msvc", "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl", "x86_64-unknown-freebsd", - "i686-pc-windows-msvc", - "armv7-unknown-linux-gnueabihf", "aarch64-unknown-linux-gnu", - "aarch64-apple-darwin", "aarch64-unknown-linux-musl", - "aarch64-pc-windows-msvc", + "armv7-unknown-linux-gnueabihf", + "s390x-unknown-linux-gnu", + "riscv64gc-unknown-linux-gnu", + "x86_64-apple-darwin", + "aarch64-apple-darwin", "wasm32-wasip1-threads" ], "wasm": { From 911945a7d4d5c946196ca9da7851f23a9005f138 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 16:32:36 +0200 Subject: [PATCH 39/61] remove freebsd --- napi/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/napi/package.json b/napi/package.json index a5f401a9..20f0d6cf 100644 --- a/napi/package.json +++ b/napi/package.json @@ -15,7 +15,6 @@ "targets": [ "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl", - "x86_64-unknown-freebsd", "aarch64-unknown-linux-gnu", "aarch64-unknown-linux-musl", "armv7-unknown-linux-gnueabihf", From efaa7691908b02df07a50656cdaef84d5cda2183 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 16:50:07 +0200 Subject: [PATCH 40/61] adding benchmark, does not work tho --- napi/__tests__/parse.bench.ts | 285 ++++++++++++++ napi/__tests__/parse.test.ts | 71 +++- napi/package.json | 3 + napi/vitest.config.ts | 11 + pnpm-lock.yaml | 702 ++++++++++++++++++++++++++++++++++ 5 files changed, 1054 insertions(+), 18 deletions(-) create mode 100644 napi/__tests__/parse.bench.ts create mode 100644 napi/vitest.config.ts diff --git a/napi/__tests__/parse.bench.ts b/napi/__tests__/parse.bench.ts new file mode 100644 index 00000000..578c3c2e --- /dev/null +++ b/napi/__tests__/parse.bench.ts @@ -0,0 +1,285 @@ +import { bench, describe } from "vitest"; +import { parse, splitIntoSections } from "../"; +import { remark } from "remark"; +import remarkMdx from "remark-mdx"; + +// Create remark processor +const remarkProcessor = remark().use(remarkMdx); + +// Long MDX content for benchmarking +let longMdxContent = `import React from 'react' +import { Button, Card, Chart } from './components' +import { useEffect, useState } from 'react' + +export const metadata = { + title: 'Performance Benchmark Document', + author: 'Benchmark Suite', + date: '2024-01-01' +} + +# Performance Test Document + +This is a comprehensive MDX document designed to test parsing performance across different implementations. + +## Introduction + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + +### Interactive Components + + +

This document contains various MDX elements to stress-test the parser:

+ +
    +
  • **JSX Components** with props
  • +
  • *JavaScript expressions* in {new Date().getFullYear()}
  • +
  • \`Inline code\` and code blocks
  • +
  • Tables, lists, and blockquotes
  • +
+ + +
+ +## Data Visualization + + + +## Code Examples + +Here's a TypeScript example: + +\`\`\`typescript +interface PerformanceMetrics { + parseTime: number; + memoryUsage: number; + operationsPerSecond: number; +} + +class BenchmarkRunner { + private metrics: PerformanceMetrics[] = []; + + async runBenchmark(iterations: number): Promise { + const startTime = performance.now(); + const startMemory = process.memoryUsage().heapUsed; + + for (let i = 0; i < iterations; i++) { + await this.executeOperation(); + } + + const endTime = performance.now(); + const endMemory = process.memoryUsage().heapUsed; + + return { + parseTime: endTime - startTime, + memoryUsage: endMemory - startMemory, + operationsPerSecond: iterations / ((endTime - startTime) / 1000) + }; + } +} +\`\`\` + +### JavaScript Example + +\`\`\`javascript +function calculatePerformance(data) { + return data + .filter(item => item.value > 0) + .map(item => ({ + ...item, + normalized: item.value / Math.max(...data.map(d => d.value)) + })) + .sort((a, b) => b.normalized - a.normalized); +} + +const results = calculatePerformance([ + { name: 'Parser A', value: 1200 }, + { name: 'Parser B', value: 800 }, + { name: 'Parser C', value: 1500 } +]); +\`\`\` + +## Mathematical Expressions + +Performance can be measured using various metrics: $T = \\frac{n}{ops/sec}$ + +Where: +- $T$ is total time +- $n$ is number of operations +- $ops/sec$ is operations per second + +Complex equation: $$\\sum_{i=1}^{n} \\frac{1}{T_i} = \\frac{n}{\\bar{T}}$$ + +## Tables and Data + +| Parser | Speed (ops/sec) | Memory (MB) | Bundle Size (KB) | +|--------|-----------------|-------------|------------------| +| markdown-rs | {1000 + Math.floor(Math.random() * 500)} | 12.4 | 89.2 | +| remark | {800 + Math.floor(Math.random() * 300)} | 18.7 | 156.8 | +| marked | {900 + Math.floor(Math.random() * 400)} | 15.2 | 45.6 | + +## Lists and Formatting + +### Features Comparison + +1. **Parsing Speed** + - Raw text processing + - AST generation time + - Memory allocation efficiency + +2. **Bundle Size** + - Core library size + - Plugin ecosystem impact + - Tree-shaking effectiveness + +3. **Developer Experience** + - API simplicity + - TypeScript support + - Error handling + +### Pros and Cons + +- ✅ Fast parsing performance +- ✅ Low memory footprint +- ✅ Rust-based reliability +- ❌ Smaller ecosystem +- ❌ Learning curve for Rust integration + +> **Important Note**: Performance benchmarks can vary significantly based on: +> - Hardware specifications +> - Node.js version +> - System load +> - Input document complexity + +## Complex Nested Components + + +
+

Nested Component Example

+ Performance: {(Math.random() * 100).toFixed(2)}% +
+ +
+

This tests deeply nested JSX parsing with multiple levels:

+ +
+
+ Parse Time: + {(Math.random() * 50).toFixed(2)}ms +
+
+ Memory: + {(Math.random() * 20).toFixed(1)}MB +
+
+ + +
+
+ +## Multiple Sections for Load Testing + +${Array(5) + .fill( + ` +### Section {index} + +This is section number {index} with various content types: + +- Regular **bold** and *italic* text +- \`Inline code snippets\` +- [External links](https://example.com) + +#### Subsection Code + +\`\`\`json +{ + "benchmark": "section-{index}", + "timestamp": {Date.now()}, + "data": [1, 2, 3, 4, 5] +} +\`\`\` + +
+

JSX content in section {index}

+ +
+ +> Blockquote in section {index} with **formatting** and \`code\` + +| Item | Value | +|------|-------| +| A{index} | {Math.random()} | +| B{index} | {Math.random()} | +`, + ) + .join("\n\n")} + +## Final Performance Summary + + + + +

+ Based on our comprehensive testing, markdown-rs shows significant + performance advantages in parsing speed and memory efficiency. + Current timestamp: {new Date().toISOString()} +

+
+ +--- + +*End of benchmark document. This is a comprehensive MDX performance test.* + +`; + +longMdxContent = longMdxContent.repeat(10); + +describe("MDX Parsing Performance Comparison", () => { + bench("markdown-rs parse", () => { + const res = parse(longMdxContent, { + mdx: true, + mdxExpressionParse: true, + mdxEsmParse: true, + }); + console.log(res); + }); + + bench("markdown-rs splitIntoSections", () => { + splitIntoSections(longMdxContent, { + mdx: true, + mdxExpressionParse: true, + mdxEsmParse: true, + }); + }); + + bench("remark + remark-mdx parse", () => { + remarkProcessor.runSync(remarkProcessor.parse(longMdxContent)); + }); +}); diff --git a/napi/__tests__/parse.test.ts b/napi/__tests__/parse.test.ts index c2ece4a1..86eab539 100644 --- a/napi/__tests__/parse.test.ts +++ b/napi/__tests__/parse.test.ts @@ -231,12 +231,15 @@ describe("parse", () => { it("handles broken jsx in mdx without panic", () => { const error = catchErrorValue(() => - parse(` + parse( + ` paragraph - `, { mdx: true }), + `, + { mdx: true }, + ), ); expect(error).toMatchInlineSnapshot( `[Error: Message { place: Some(Point(6:5 (39))), reason: "Expected a closing tag for \`\` (4:1)", rule_id: "end-tag-mismatch", source: "markdown-rs" }]`, @@ -244,7 +247,8 @@ paragraph }); it("returns mdast", () => { - const ast = parse(` + const ast = parse( + ` import something from 'package' export const x = 9 @@ -260,7 +264,9 @@ here is some mdx {expression} this is a callout - `, { mdx: true }); + `, + { mdx: true }, + ); expect(stripPositions(ast)).toMatchInlineSnapshot(` { "children": [ @@ -364,7 +370,7 @@ This is a paragraph. ## Subheading Another paragraph.`); - + expect(sections).toMatchInlineSnapshot(` [ { @@ -570,14 +576,17 @@ const code = "block"; }); it("works with MDX content", () => { - const sections = splitIntoSections(`import React from 'react' + const sections = splitIntoSections( + `import React from 'react' # MDX Document Content -`, { mdx: true }); - +`, + { mdx: true }, + ); + expect(sections).toMatchInlineSnapshot(` [ { @@ -635,15 +644,18 @@ const code = "block"; }); it("works with MDX and expression parsing enabled", () => { - const sections = splitIntoSections(`# Hello {world} + const sections = splitIntoSections( + `# Hello {world} {expression} -`, { - mdx: true, - mdxExpressionParse: true - }); - +`, + { + mdx: true, + mdxExpressionParse: true, + }, + ); + expect(sections).toMatchInlineSnapshot(` [ { @@ -698,10 +710,33 @@ const code = "block"; `); }); + it("extracts frontmatter section", () => { + const content = `--- +title: Hello World +tags: + - test + - doc +--- + +# Heading + +Content goes here. +`; + const sections = splitIntoSections(content, { mdx: true, }); + + expect(sections[0].type).toBe("yaml"); + expect(sections[0].raw).toBe(`--- +title: Hello World +tags: + - test + - doc +---`); + }); + it("preserves exact raw text with complex formatting", () => { const content = "# Title\n\nParagraph with *emphasis* and `code`."; const sections = splitIntoSections(content); - + expect(sections[0].raw).toBe("# Title"); expect(sections[1].raw).toBe("Paragraph with *emphasis* and `code`."); expect(sections[0].type).toBe("heading"); @@ -711,9 +746,9 @@ const code = "block"; it("accepts parse options", () => { const sections = splitIntoSections("# Title\n\nSome content", { gfmStrikethroughSingleTilde: false, - mathTextSingleDollar: true + mathTextSingleDollar: true, }); - + expect(sections).toHaveLength(2); expect(sections[0].type).toBe("heading"); expect(sections[1].type).toBe("paragraph"); @@ -752,4 +787,4 @@ export function catchErrorValue(fn: () => T): T | Error { } catch (e) { return e; } -} \ No newline at end of file +} diff --git a/napi/package.json b/napi/package.json index 20f0d6cf..b238433d 100644 --- a/napi/package.json +++ b/napi/package.json @@ -4,6 +4,7 @@ "scripts": { "build:debug": "pnpm napi build --platform --manifest-path Cargo.toml", "test": "pnpm vitest", + "bench": "pnpm vitest bench", "build": "pnpm run build:debug --release" }, "publishConfig": { @@ -33,6 +34,8 @@ "@napi-rs/wasm-runtime": "^0.2.7", "@napi-rs/cli": "3.0.0-alpha.89", "emnapi": "^1.4.3", + "remark": "^15.0.1", + "remark-mdx": "^3.0.1", "vitest": "^1.5.0" } } diff --git a/napi/vitest.config.ts b/napi/vitest.config.ts new file mode 100644 index 00000000..bb229ce9 --- /dev/null +++ b/napi/vitest.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + // poolOptions: { + // threads: { + // maxThreads: 1, + // }, + // }, + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4bae6c93..38941f46 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,6 +26,12 @@ importers: emnapi: specifier: ^1.4.3 version: 1.4.3 + remark: + specifier: ^15.0.1 + version: 15.0.1 + remark-mdx: + specifier: ^3.0.1 + version: 3.1.0 vitest: specifier: ^1.5.0 version: 1.6.1 @@ -789,12 +795,33 @@ packages: '@tybys/wasm-util@0.9.0': resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + '@types/estree@1.0.7': resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@vitest/expect@1.6.1': resolution: {integrity: sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==} @@ -810,6 +837,11 @@ packages: '@vitest/utils@1.6.1': resolution: {integrity: sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==} + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn-walk@8.3.4: resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} @@ -841,6 +873,9 @@ packages: assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + before-after-hook@4.0.0: resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==} @@ -848,10 +883,25 @@ packages: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + chai@4.5.0: resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} engines: {node: '>=4'} + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + chardet@0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} @@ -893,10 +943,20 @@ packages: supports-color: optional: true + decode-named-character-reference@1.2.0: + resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} + deep-eql@4.1.4: resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} engines: {node: '>=6'} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -917,6 +977,12 @@ packages: engines: {node: '>=12'} hasBin: true + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + + estree-util-visit@2.0.0: + resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} + estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} @@ -924,6 +990,9 @@ packages: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + external-editor@3.1.0: resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} engines: {node: '>=4'} @@ -951,10 +1020,26 @@ packages: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + is-stream@3.0.0: resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -976,15 +1061,126 @@ packages: lodash-es@4.17.21: resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + loupe@2.3.7: resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + mdast-util-from-markdown@2.0.2: + resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + + mdast-util-mdx-jsx@3.2.0: + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + + mdast-util-mdx@3.0.0: + resolution: {integrity: sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==} + + mdast-util-mdxjs-esm@2.0.1: + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-mdx-expression@3.0.1: + resolution: {integrity: sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==} + + micromark-extension-mdx-jsx@3.0.2: + resolution: {integrity: sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==} + + micromark-extension-mdx-md@2.0.0: + resolution: {integrity: sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==} + + micromark-extension-mdxjs-esm@3.0.0: + resolution: {integrity: sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==} + + micromark-extension-mdxjs@3.0.0: + resolution: {integrity: sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-mdx-expression@2.0.3: + resolution: {integrity: sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-events-to-acorn@2.0.3: + resolution: {integrity: sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + mimic-fn@4.0.0: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} @@ -1020,6 +1216,9 @@ packages: resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} engines: {node: '>=18'} + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -1054,6 +1253,18 @@ packages: react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + remark-mdx@3.1.0: + resolution: {integrity: sha512-Ngl/H3YXyBV9RcRNdlYsZujAmhsxwzxpDzpDEhFBVAGthS4GDgnctpDjgFl/ULx5UEDzqtW1cyBSNKqYYrqLBA==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + + remark@15.0.1: + resolution: {integrity: sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==} + rollup@4.43.0: resolution: {integrity: sha512-wdN2Kd3Twh8MAEOEJZsuxuLKCsBEo4PVNLK6tQWAn10VhsVewQLzcucMgLolRlhFybGxfclbPeEYBaP6RvUFGg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -1096,6 +1307,9 @@ packages: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -1125,6 +1339,9 @@ packages: toml@3.0.0: resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -1142,9 +1359,33 @@ packages: ufo@1.6.1: resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unist-util-is@6.0.0: + resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} + + unist-util-position-from-estree@2.0.0: + resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.1: + resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} + + unist-util-visit@5.0.0: + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + universal-user-agent@7.0.3: resolution: {integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==} + vfile-message@4.0.2: + resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + vite-node@1.6.1: resolution: {integrity: sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -1231,6 +1472,9 @@ packages: resolution: {integrity: sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==} engines: {node: '>=18'} + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + snapshots: '@emnapi/core@1.4.3': @@ -1780,10 +2024,32 @@ snapshots: dependencies: tslib: 2.8.1 + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.8 + '@types/estree@1.0.7': {} '@types/estree@1.0.8': {} + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/ms@2.1.0': {} + + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + '@vitest/expect@1.6.1': dependencies: '@vitest/spy': 1.6.1 @@ -1813,6 +2079,10 @@ snapshots: loupe: 2.3.7 pretty-format: 29.7.0 + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + acorn-walk@8.3.4: dependencies: acorn: 8.15.0 @@ -1835,10 +2105,14 @@ snapshots: assertion-error@1.1.0: {} + bail@2.0.2: {} + before-after-hook@4.0.0: {} cac@6.7.14: {} + ccount@2.0.1: {} + chai@4.5.0: dependencies: assertion-error: 1.1.0 @@ -1849,6 +2123,14 @@ snapshots: pathval: 1.1.1 type-detect: 4.1.0 + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + chardet@0.7.0: {} check-error@1.0.3: @@ -1881,10 +2163,20 @@ snapshots: dependencies: ms: 2.1.3 + decode-named-character-reference@1.2.0: + dependencies: + character-entities: 2.0.2 + deep-eql@4.1.4: dependencies: type-detect: 4.1.0 + dequal@2.0.3: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + diff-sequences@29.6.3: {} emnapi@1.4.3: {} @@ -1917,6 +2209,13 @@ snapshots: '@esbuild/win32-ia32': 0.21.5 '@esbuild/win32-x64': 0.21.5 + estree-util-is-identifier-name@3.0.0: {} + + estree-util-visit@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/unist': 3.0.3 + estree-walker@3.0.3: dependencies: '@types/estree': 1.0.8 @@ -1933,6 +2232,8 @@ snapshots: signal-exit: 4.1.0 strip-final-newline: 3.0.0 + extend@3.0.2: {} + external-editor@3.1.0: dependencies: chardet: 0.7.0 @@ -1954,8 +2255,21 @@ snapshots: dependencies: safer-buffer: 2.1.2 + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + + is-decimal@2.0.1: {} + is-fullwidth-code-point@3.0.0: {} + is-hexadecimal@2.0.1: {} + + is-plain-obj@4.1.0: {} + is-stream@3.0.0: {} isexe@2.0.0: {} @@ -1973,6 +2287,8 @@ snapshots: lodash-es@4.17.21: {} + longest-streak@3.1.0: {} + loupe@2.3.7: dependencies: get-func-name: 2.0.2 @@ -1981,8 +2297,301 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 + mdast-util-from-markdown@2.0.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-expression@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.2.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx@3.0.0: + dependencies: + mdast-util-from-markdown: 2.0.2 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdxjs-esm@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.0 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.0.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + merge-stream@2.0.0: {} + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-mdx-expression@3.0.1: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-mdx-jsx@3.0.2: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.2 + + micromark-extension-mdx-md@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-mdxjs-esm@3.0.0: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.2 + + micromark-extension-mdxjs@3.0.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + micromark-extension-mdx-expression: 3.0.1 + micromark-extension-mdx-jsx: 3.0.2 + micromark-extension-mdx-md: 2.0.0 + micromark-extension-mdxjs-esm: 3.0.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-mdx-expression@2.0.3: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.2 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.2.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-events-to-acorn@2.0.3: + dependencies: + '@types/estree': 1.0.8 + '@types/unist': 3.0.3 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.2 + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.12 + debug: 4.4.1 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + mimic-fn@4.0.0: {} mlly@1.7.4: @@ -2012,6 +2621,16 @@ snapshots: dependencies: yocto-queue: 1.2.1 + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.2.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + path-key@3.1.1: {} path-key@4.0.0: {} @@ -2044,6 +2663,37 @@ snapshots: react-is@18.3.1: {} + remark-mdx@3.1.0: + dependencies: + mdast-util-mdx: 3.0.0 + micromark-extension-mdxjs: 3.0.0 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.2 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + + remark@15.0.1: + dependencies: + '@types/mdast': 4.0.4 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + rollup@4.43.0: dependencies: '@types/estree': 1.0.7 @@ -2096,6 +2746,11 @@ snapshots: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -2118,6 +2773,8 @@ snapshots: toml@3.0.0: {} + trough@2.2.0: {} + tslib@2.8.1: {} typanion@3.14.0: {} @@ -2128,8 +2785,51 @@ snapshots: ufo@1.6.1: {} + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unist-util-is@6.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position-from-estree@2.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.1: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.0 + + unist-util-visit@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.0 + unist-util-visit-parents: 6.0.1 + universal-user-agent@7.0.3: {} + vfile-message@4.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.2 + vite-node@1.6.1: dependencies: cac: 6.7.14 @@ -2208,3 +2908,5 @@ snapshots: yocto-queue@1.2.1: {} yoctocolors-cjs@2.1.2: {} + + zwitch@2.0.4: {} From 256113852278b44dd143706a60c6f38aa61801cd Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 17:00:33 +0200 Subject: [PATCH 41/61] add support for fronmatter --- napi/AGENTS.md | 8 +++++ napi/__tests__/parse.test.ts | 5 +++- napi/index.d.ts | 2 ++ napi/package.json | 3 +- napi/src/lib.rs | 58 +++++++++++------------------------- 5 files changed, 34 insertions(+), 42 deletions(-) create mode 100644 napi/AGENTS.md diff --git a/napi/AGENTS.md b/napi/AGENTS.md new file mode 100644 index 00000000..b9170a68 --- /dev/null +++ b/napi/AGENTS.md @@ -0,0 +1,8 @@ + +This is the package that handles NAPI bindings for markdown-rs. It also supports wasm. + +## Testing + +Tests use vitest, use expect().toMatchInlineSnapshot() mostly. Never pass the snapshot yourself, instead leave it empty and then run the test with `pnpm vitest --run -u` to update snapshots, then read the test file again and make sure it has the expected result. + +When making changes in rust run `pnpm build:debug` to make sure the Rust compiles. If not fix all the errors. Try to not change other crates source code, which are unrelated to the npm package diff --git a/napi/__tests__/parse.test.ts b/napi/__tests__/parse.test.ts index 86eab539..f79792c9 100644 --- a/napi/__tests__/parse.test.ts +++ b/napi/__tests__/parse.test.ts @@ -722,7 +722,10 @@ tags: Content goes here. `; - const sections = splitIntoSections(content, { mdx: true, }); + const sections = splitIntoSections(content, { + mdx: true, + frontmatter: true, + }); expect(sections[0].type).toBe("yaml"); expect(sections[0].raw).toBe(`--- diff --git a/napi/index.d.ts b/napi/index.d.ts index 0e252d98..ecd2918d 100644 --- a/napi/index.d.ts +++ b/napi/index.d.ts @@ -13,6 +13,8 @@ export interface ParseOptions { mdxExpressionParse?: boolean /** Whether to enable basic MDX ESM parsing */ mdxEsmParse?: boolean + /** Whether to support frontmatter */ + frontmatter?: boolean } export interface Section { diff --git a/napi/package.json b/napi/package.json index b238433d..67e7aa64 100644 --- a/napi/package.json +++ b/napi/package.json @@ -1,6 +1,6 @@ { "name": "@xmorse/markdown-rs", - "version": "0.0.2", + "version": "0.0.3", "scripts": { "build:debug": "pnpm napi build --platform --manifest-path Cargo.toml", "test": "pnpm vitest", @@ -10,6 +10,7 @@ "publishConfig": { "access": "public" }, + "repository": "https://github.com/remorses/markdown-rs", "napi": { "binaryName": "markdown-rs", "packageName": "@xmorse/markdown-rs-binding", diff --git a/napi/src/lib.rs b/napi/src/lib.rs index 44905176..58ddb6b7 100644 --- a/napi/src/lib.rs +++ b/napi/src/lib.rs @@ -15,6 +15,8 @@ pub struct ParseOptions { pub mdx_expression_parse: Option, /// Whether to enable basic MDX ESM parsing pub mdx_esm_parse: Option, + /// Whether to support frontmatter + pub frontmatter: Option, } #[napi(object)] @@ -29,7 +31,19 @@ pub struct Section { impl ParseOptions { fn to_rust_parse_options(&self) -> markdown::ParseOptions { + let mut constructs = if self.mdx.unwrap_or(false) { + markdown::Constructs::mdx() + } else { + markdown::Constructs::default() + }; + + // Enable frontmatter if requested + if self.frontmatter.unwrap_or(false) { + constructs.frontmatter = true; + } + markdown::ParseOptions { + constructs, gfm_strikethrough_single_tilde: self.gfm_strikethrough_single_tilde.unwrap_or(true), math_text_single_dollar: self.math_text_single_dollar.unwrap_or(true), mdx_expression_parse: if self.mdx_expression_parse.unwrap_or(false) { @@ -55,29 +69,11 @@ impl ParseOptions { #[napi] pub fn parse(input: String, options: Option) -> Result { - let mut parse_options = match &options { - Some(opts) => { - if opts.mdx.unwrap_or(false) { - markdown::ParseOptions { - constructs: markdown::Constructs::mdx(), - ..Default::default() - } - } else { - markdown::ParseOptions::default() - } - } + let parse_options = match options { + Some(opts) => opts.to_rust_parse_options(), None => markdown::ParseOptions::default(), }; - // Override with user-provided options if available - if let Some(opts) = options { - let user_options = opts.to_rust_parse_options(); - parse_options.gfm_strikethrough_single_tilde = user_options.gfm_strikethrough_single_tilde; - parse_options.math_text_single_dollar = user_options.math_text_single_dollar; - parse_options.mdx_expression_parse = user_options.mdx_expression_parse; - parse_options.mdx_esm_parse = user_options.mdx_esm_parse; - } - let tree = markdown::to_mdast(&input, &parse_options) .map_err(|e| Error::from_reason(format!("{:?}", e)))?; serde_json::to_value(&tree).map_err(|e| Error::from_reason(e.to_string())) @@ -85,29 +81,11 @@ pub fn parse(input: String, options: Option) -> Result { #[napi] pub fn split_into_sections(input: String, options: Option) -> Result> { - let mut parse_options = match &options { - Some(opts) => { - if opts.mdx.unwrap_or(false) { - markdown::ParseOptions { - constructs: markdown::Constructs::mdx(), - ..Default::default() - } - } else { - markdown::ParseOptions::default() - } - } + let parse_options = match options { + Some(opts) => opts.to_rust_parse_options(), None => markdown::ParseOptions::default(), }; - // Override with user-provided options if available - if let Some(opts) = options { - let user_options = opts.to_rust_parse_options(); - parse_options.gfm_strikethrough_single_tilde = user_options.gfm_strikethrough_single_tilde; - parse_options.math_text_single_dollar = user_options.math_text_single_dollar; - parse_options.mdx_expression_parse = user_options.mdx_expression_parse; - parse_options.mdx_esm_parse = user_options.mdx_esm_parse; - } - let tree = markdown::to_mdast(&input, &parse_options) .map_err(|e| Error::from_reason(format!("{:?}", e)))?; From 48971b8665884cd313700be8edc9b9e7707dd8ef Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 17:04:24 +0200 Subject: [PATCH 42/61] meta strings --- napi/__tests__/parse.test.ts | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/napi/__tests__/parse.test.ts b/napi/__tests__/parse.test.ts index f79792c9..35457ccf 100644 --- a/napi/__tests__/parse.test.ts +++ b/napi/__tests__/parse.test.ts @@ -25,6 +25,23 @@ describe("parse", () => { `); }); + it("parse code block with metastring", () => { + const ast = parse("```js metastring\nconsole.log('hello world');\n```"); + expect(stripPositions(ast)).toMatchInlineSnapshot(` + { + "children": [ + { + "lang": "js", + "meta": "metastring", + "type": "code", + "value": "console.log('hello world');", + }, + ], + "type": "root", + } + `); + }); + it("parse with mdx option accepts options parameter", () => { const ast = parse("# Hello {expression}", { mdx: true, @@ -480,7 +497,7 @@ Paragraph with **bold** text. - List item 1 - List item 2 -\`\`\`javascript +\`\`\`javascript metastring const code = "block"; \`\`\``; @@ -558,7 +575,7 @@ const code = "block"; "end": { "column": 4, "line": 12, - "offset": 129, + "offset": 140, }, "start": { "column": 1, @@ -566,7 +583,7 @@ const code = "block"; "offset": 90, }, }, - "raw": "\`\`\`javascript + "raw": "\`\`\`javascript metastring const code = "block"; \`\`\`", "type": "code", From 8d11d99987f796d63152743844701bb87a842582 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 17:06:14 +0200 Subject: [PATCH 43/61] heading handling --- napi/__tests__/parse.test.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/napi/__tests__/parse.test.ts b/napi/__tests__/parse.test.ts index 35457ccf..92a37899 100644 --- a/napi/__tests__/parse.test.ts +++ b/napi/__tests__/parse.test.ts @@ -25,6 +25,27 @@ describe("parse", () => { `); }); + it("parse handles level 2 heading", () => { + const ast = parse("## My Subheading"); + expect(stripPositions(ast)).toMatchInlineSnapshot(` + { + "children": [ + { + "children": [ + { + "type": "text", + "value": "My Subheading", + }, + ], + "depth": 2, + "type": "heading", + }, + ], + "type": "root", + } + `); + }); + it("parse code block with metastring", () => { const ast = parse("```js metastring\nconsole.log('hello world');\n```"); expect(stripPositions(ast)).toMatchInlineSnapshot(` From f5977e4f7154da1617f74c846cdb7673c488241c Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 17:13:48 +0200 Subject: [PATCH 44/61] add gfm option --- napi/__tests__/parse.test.ts | 99 ++++++++++++++++++++++++++++++++ napi/index.d.ts | 2 + napi/markdown-rs.wasi-browser.js | 58 ------------------- napi/markdown-rs.wasi.cjs | 89 ---------------------------- napi/markdownrs.wasi-browser.js | 57 ------------------ napi/markdownrs.wasi.cjs | 88 ---------------------------- napi/src/lib.rs | 14 ++++- napi/wasi-worker-browser.mjs | 32 ----------- napi/wasi-worker.mjs | 63 -------------------- src/configuration.rs | 1 + 10 files changed, 115 insertions(+), 388 deletions(-) delete mode 100644 napi/markdown-rs.wasi-browser.js delete mode 100644 napi/markdown-rs.wasi.cjs delete mode 100644 napi/markdownrs.wasi-browser.js delete mode 100644 napi/markdownrs.wasi.cjs delete mode 100644 napi/wasi-worker-browser.mjs delete mode 100644 napi/wasi-worker.mjs diff --git a/napi/__tests__/parse.test.ts b/napi/__tests__/parse.test.ts index 92a37899..7e3defaa 100644 --- a/napi/__tests__/parse.test.ts +++ b/napi/__tests__/parse.test.ts @@ -25,6 +25,105 @@ describe("parse", () => { `); }); + it("parse parses tables with gfm option", () => { + const ast = parse( + ` + | Name | Age | + |-------|------------| + | Alice |
| + | Bob | 23 | + `, + { gfm: true, mdx: true }, + ); + expect(stripPositions(ast)).toMatchInlineSnapshot(` + { + "children": [ + { + "align": [ + null, + null, + ], + "children": [ + { + "children": [ + { + "children": [ + { + "type": "text", + "value": "Name", + }, + ], + "type": "tableCell", + }, + { + "children": [ + { + "type": "text", + "value": "Age", + }, + ], + "type": "tableCell", + }, + ], + "type": "tableRow", + }, + { + "children": [ + { + "children": [ + { + "type": "text", + "value": "Alice", + }, + ], + "type": "tableCell", + }, + { + "children": [ + { + "attributes": [], + "children": [], + "name": "div", + "type": "mdxJsxTextElement", + }, + ], + "type": "tableCell", + }, + ], + "type": "tableRow", + }, + { + "children": [ + { + "children": [ + { + "type": "text", + "value": "Bob", + }, + ], + "type": "tableCell", + }, + { + "children": [ + { + "type": "text", + "value": "23", + }, + ], + "type": "tableCell", + }, + ], + "type": "tableRow", + }, + ], + "type": "table", + }, + ], + "type": "root", + } + `); + }); + it("parse handles level 2 heading", () => { const ast = parse("## My Subheading"); expect(stripPositions(ast)).toMatchInlineSnapshot(` diff --git a/napi/index.d.ts b/napi/index.d.ts index ecd2918d..2056045e 100644 --- a/napi/index.d.ts +++ b/napi/index.d.ts @@ -5,6 +5,8 @@ export declare function parse(input: string, options?: ParseOptions | undefined export interface ParseOptions { /** Whether to parse as MDX */ mdx?: boolean + /** Whether to enable GitHub Flavored Markdown (GFM) constructs */ + gfm?: boolean /** Whether to support GFM strikethrough with a single tilde */ gfmStrikethroughSingleTilde?: boolean /** Whether to support math (text) with a single dollar */ diff --git a/napi/markdown-rs.wasi-browser.js b/napi/markdown-rs.wasi-browser.js deleted file mode 100644 index 06b73208..00000000 --- a/napi/markdown-rs.wasi-browser.js +++ /dev/null @@ -1,58 +0,0 @@ -import { - createOnMessage as __wasmCreateOnMessageForFsProxy, - getDefaultContext as __emnapiGetDefaultContext, - instantiateNapiModuleSync as __emnapiInstantiateNapiModuleSync, - WASI as __WASI, -} from '@napi-rs/wasm-runtime' - - -const __wasi = new __WASI({ - version: 'preview1', -}) - -const __wasmUrl = new URL('./markdown-rs.wasm32-wasi.wasm', import.meta.url).href -const __emnapiContext = __emnapiGetDefaultContext() - -const __sharedMemory = new WebAssembly.Memory({ - initial: 16384, - maximum: 65536, - shared: true, -}) - -const __wasmFile = await fetch(__wasmUrl).then((res) => res.arrayBuffer()) - -const { - instance: __napiInstance, - module: __wasiModule, - napiModule: __napiModule, -} = __emnapiInstantiateNapiModuleSync(__wasmFile, { - context: __emnapiContext, - asyncWorkPoolSize: 4, - wasi: __wasi, - onCreateWorker() { - const worker = new Worker(new URL('./wasi-worker-browser.mjs', import.meta.url), { - type: 'module', - }) - - return worker - }, - overwriteImports(importObject) { - importObject.env = { - ...importObject.env, - ...importObject.napi, - ...importObject.emnapi, - memory: __sharedMemory, - } - return importObject - }, - beforeInit({ instance }) { - for (const name of Object.keys(instance.exports)) { - if (name.startsWith('__napi_register__')) { - instance.exports[name]() - } - } - }, -}) -export default __napiModule.exports -export const parse = __napiModule.exports.parse -export const splitIntoSections = __napiModule.exports.splitIntoSections diff --git a/napi/markdown-rs.wasi.cjs b/napi/markdown-rs.wasi.cjs deleted file mode 100644 index 21b9ee66..00000000 --- a/napi/markdown-rs.wasi.cjs +++ /dev/null @@ -1,89 +0,0 @@ -/* eslint-disable */ -/* prettier-ignore */ - -/* auto-generated by NAPI-RS */ - -const __nodeFs = require('node:fs') -const __nodePath = require('node:path') -const { WASI: __nodeWASI } = require('node:wasi') -const { Worker } = require('node:worker_threads') - -const { - createOnMessage: __wasmCreateOnMessageForFsProxy, - getDefaultContext: __emnapiGetDefaultContext, - instantiateNapiModuleSync: __emnapiInstantiateNapiModuleSync, -} = require('@napi-rs/wasm-runtime') - -const __rootDir = __nodePath.parse(process.cwd()).root - -const __wasi = new __nodeWASI({ - version: 'preview1', - env: process.env, - preopens: { - [__rootDir]: __rootDir, - } -}) - -const __emnapiContext = __emnapiGetDefaultContext() - -const __sharedMemory = new WebAssembly.Memory({ - initial: 16384, - maximum: 65536, - shared: true, -}) - -let __wasmFilePath = __nodePath.join(__dirname, 'markdown-rs.wasm32-wasi.wasm') -const __wasmDebugFilePath = __nodePath.join(__dirname, 'markdown-rs.wasm32-wasi.debug.wasm') - -if (__nodeFs.existsSync(__wasmDebugFilePath)) { - __wasmFilePath = __wasmDebugFilePath -} else if (!__nodeFs.existsSync(__wasmFilePath)) { - try { - __wasmFilePath = __nodePath.resolve('@xmorse/markdown-rs-binding-wasm32-wasi') - } catch { - throw new Error('Cannot find markdown-rs.wasm32-wasi.wasm file, and @xmorse/markdown-rs-binding-wasm32-wasi package is not installed.') - } -} - -const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule } = __emnapiInstantiateNapiModuleSync(__nodeFs.readFileSync(__wasmFilePath), { - context: __emnapiContext, - asyncWorkPoolSize: (function() { - const threadsSizeFromEnv = Number(process.env.NAPI_RS_ASYNC_WORK_POOL_SIZE ?? process.env.UV_THREADPOOL_SIZE) - // NaN > 0 is false - if (threadsSizeFromEnv > 0) { - return threadsSizeFromEnv - } else { - return 4 - } - })(), - reuseWorker: true, - wasi: __wasi, - onCreateWorker() { - const worker = new Worker(__nodePath.join(__dirname, 'wasi-worker.mjs'), { - env: process.env, - }) - worker.onmessage = ({ data }) => { - __wasmCreateOnMessageForFsProxy(__nodeFs)(data) - } - return worker - }, - overwriteImports(importObject) { - importObject.env = { - ...importObject.env, - ...importObject.napi, - ...importObject.emnapi, - memory: __sharedMemory, - } - return importObject - }, - beforeInit({ instance }) { - for (const name of Object.keys(instance.exports)) { - if (name.startsWith('__napi_register__')) { - instance.exports[name]() - } - } - }, -}) -module.exports = __napiModule.exports -module.exports.parse = __napiModule.exports.parse -module.exports.splitIntoSections = __napiModule.exports.splitIntoSections diff --git a/napi/markdownrs.wasi-browser.js b/napi/markdownrs.wasi-browser.js deleted file mode 100644 index 0e8b8ed7..00000000 --- a/napi/markdownrs.wasi-browser.js +++ /dev/null @@ -1,57 +0,0 @@ -import { - createOnMessage as __wasmCreateOnMessageForFsProxy, - getDefaultContext as __emnapiGetDefaultContext, - instantiateNapiModuleSync as __emnapiInstantiateNapiModuleSync, - WASI as __WASI, -} from '@napi-rs/wasm-runtime' - -import __wasmUrl from './markdownrs.wasm32-wasi.wasm?url' - -const __wasi = new __WASI({ - version: 'preview1', -}) - -const __emnapiContext = __emnapiGetDefaultContext() - -const __sharedMemory = new WebAssembly.Memory({ - initial: 16384, - maximum: 65536, - shared: true, -}) - -const __wasmFile = await fetch(__wasmUrl).then((res) => res.arrayBuffer()) - -const { - instance: __napiInstance, - module: __wasiModule, - napiModule: __napiModule, -} = __emnapiInstantiateNapiModuleSync(__wasmFile, { - context: __emnapiContext, - asyncWorkPoolSize: 4, - wasi: __wasi, - onCreateWorker() { - const worker = new Worker(new URL('./wasi-worker-browser.mjs', import.meta.url), { - type: 'module', - }) - - return worker - }, - overwriteImports(importObject) { - importObject.env = { - ...importObject.env, - ...importObject.napi, - ...importObject.emnapi, - memory: __sharedMemory, - } - return importObject - }, - beforeInit({ instance }) { - for (const name of Object.keys(instance.exports)) { - if (name.startsWith('__napi_register__')) { - instance.exports[name]() - } - } - }, -}) -export default __napiModule.exports -export const parse = __napiModule.exports.parse diff --git a/napi/markdownrs.wasi.cjs b/napi/markdownrs.wasi.cjs deleted file mode 100644 index 3ecaf29e..00000000 --- a/napi/markdownrs.wasi.cjs +++ /dev/null @@ -1,88 +0,0 @@ -/* eslint-disable */ -/* prettier-ignore */ - -/* auto-generated by NAPI-RS */ - -const __nodeFs = require('node:fs') -const __nodePath = require('node:path') -const { WASI: __nodeWASI } = require('node:wasi') -const { Worker } = require('node:worker_threads') - -const { - createOnMessage: __wasmCreateOnMessageForFsProxy, - getDefaultContext: __emnapiGetDefaultContext, - instantiateNapiModuleSync: __emnapiInstantiateNapiModuleSync, -} = require('@napi-rs/wasm-runtime') - -const __rootDir = __nodePath.parse(process.cwd()).root - -const __wasi = new __nodeWASI({ - version: 'preview1', - env: process.env, - preopens: { - [__rootDir]: __rootDir, - } -}) - -const __emnapiContext = __emnapiGetDefaultContext() - -const __sharedMemory = new WebAssembly.Memory({ - initial: 16384, - maximum: 65536, - shared: true, -}) - -let __wasmFilePath = __nodePath.join(__dirname, 'markdownrs.wasm32-wasi.wasm') -const __wasmDebugFilePath = __nodePath.join(__dirname, 'markdownrs.wasm32-wasi.debug.wasm') - -if (__nodeFs.existsSync(__wasmDebugFilePath)) { - __wasmFilePath = __wasmDebugFilePath -} else if (!__nodeFs.existsSync(__wasmFilePath)) { - try { - __wasmFilePath = __nodePath.resolve('@xmorse/markdownrs-wasm32-wasi') - } catch { - throw new Error('Cannot find markdownrs.wasm32-wasi.wasm file, and @xmorse/markdownrs-wasm32-wasi package is not installed.') - } -} - -const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule } = __emnapiInstantiateNapiModuleSync(__nodeFs.readFileSync(__wasmFilePath), { - context: __emnapiContext, - asyncWorkPoolSize: (function() { - const threadsSizeFromEnv = Number(process.env.NAPI_RS_ASYNC_WORK_POOL_SIZE ?? process.env.UV_THREADPOOL_SIZE) - // NaN > 0 is false - if (threadsSizeFromEnv > 0) { - return threadsSizeFromEnv - } else { - return 4 - } - })(), - reuseWorker: true, - wasi: __wasi, - onCreateWorker() { - const worker = new Worker(__nodePath.join(__dirname, 'wasi-worker.mjs'), { - env: process.env, - }) - worker.onmessage = ({ data }) => { - __wasmCreateOnMessageForFsProxy(__nodeFs)(data) - } - return worker - }, - overwriteImports(importObject) { - importObject.env = { - ...importObject.env, - ...importObject.napi, - ...importObject.emnapi, - memory: __sharedMemory, - } - return importObject - }, - beforeInit({ instance }) { - for (const name of Object.keys(instance.exports)) { - if (name.startsWith('__napi_register__')) { - instance.exports[name]() - } - } - }, -}) -module.exports = __napiModule.exports -module.exports.parse = __napiModule.exports.parse diff --git a/napi/src/lib.rs b/napi/src/lib.rs index 58ddb6b7..02d2efef 100644 --- a/napi/src/lib.rs +++ b/napi/src/lib.rs @@ -7,6 +7,8 @@ use serde_json::Value; pub struct ParseOptions { /// Whether to parse as MDX pub mdx: Option, + /// Whether to enable GitHub Flavored Markdown (GFM) constructs + pub gfm: Option, /// Whether to support GFM strikethrough with a single tilde pub gfm_strikethrough_single_tilde: Option, /// Whether to support math (text) with a single dollar @@ -36,7 +38,17 @@ impl ParseOptions { } else { markdown::Constructs::default() }; - + + // Enable GFM constructs if requested + if self.gfm.unwrap_or(false) { + constructs.gfm_autolink_literal = true; + constructs.gfm_label_start_footnote = true; + constructs.gfm_footnote_definition = true; + constructs.gfm_strikethrough = true; + constructs.gfm_table = true; + constructs.gfm_task_list_item = true; + } + // Enable frontmatter if requested if self.frontmatter.unwrap_or(false) { constructs.frontmatter = true; diff --git a/napi/wasi-worker-browser.mjs b/napi/wasi-worker-browser.mjs deleted file mode 100644 index 8b1b1722..00000000 --- a/napi/wasi-worker-browser.mjs +++ /dev/null @@ -1,32 +0,0 @@ -import { instantiateNapiModuleSync, MessageHandler, WASI } from '@napi-rs/wasm-runtime' - -const handler = new MessageHandler({ - onLoad({ wasmModule, wasmMemory }) { - const wasi = new WASI({ - print: function () { - // eslint-disable-next-line no-console - console.log.apply(console, arguments) - }, - printErr: function() { - // eslint-disable-next-line no-console - console.error.apply(console, arguments) - }, - }) - return instantiateNapiModuleSync(wasmModule, { - childThread: true, - wasi, - overwriteImports(importObject) { - importObject.env = { - ...importObject.env, - ...importObject.napi, - ...importObject.emnapi, - memory: wasmMemory, - } - }, - }) - }, -}) - -globalThis.onmessage = function (e) { - handler.handle(e) -} diff --git a/napi/wasi-worker.mjs b/napi/wasi-worker.mjs deleted file mode 100644 index 84b448fc..00000000 --- a/napi/wasi-worker.mjs +++ /dev/null @@ -1,63 +0,0 @@ -import fs from "node:fs"; -import { createRequire } from "node:module"; -import { parse } from "node:path"; -import { WASI } from "node:wasi"; -import { parentPort, Worker } from "node:worker_threads"; - -const require = createRequire(import.meta.url); - -const { instantiateNapiModuleSync, MessageHandler, getDefaultContext } = require("@napi-rs/wasm-runtime"); - -if (parentPort) { - parentPort.on("message", (data) => { - globalThis.onmessage({ data }); - }); -} - -Object.assign(globalThis, { - self: globalThis, - require, - Worker, - importScripts: function (f) { - ;(0, eval)(fs.readFileSync(f, "utf8") + "//# sourceURL=" + f); - }, - postMessage: function (msg) { - if (parentPort) { - parentPort.postMessage(msg); - } - }, -}); - -const emnapiContext = getDefaultContext(); - -const __rootDir = parse(process.cwd()).root; - -const handler = new MessageHandler({ - onLoad({ wasmModule, wasmMemory }) { - const wasi = new WASI({ - version: 'preview1', - env: process.env, - preopens: { - [__rootDir]: __rootDir, - }, - }); - - return instantiateNapiModuleSync(wasmModule, { - childThread: true, - wasi, - context: emnapiContext, - overwriteImports(importObject) { - importObject.env = { - ...importObject.env, - ...importObject.napi, - ...importObject.emnapi, - memory: wasmMemory - }; - }, - }); - }, -}); - -globalThis.onmessage = function (e) { - handler.handle(e); -}; diff --git a/src/configuration.rs b/src/configuration.rs index 4f0281f3..06e0ec9c 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -433,6 +433,7 @@ impl Constructs { mdx_expression_flow: true, mdx_expression_text: true, mdx_jsx_flow: true, + mdx_jsx_text: true, ..Self::default() } From a5fe72ae90de8afc21b7e6743a70be732eca75e1 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 17:24:15 +0200 Subject: [PATCH 45/61] remove positions from tests, simpler split into sections --- napi/__tests__/parse.test.ts | 252 +++++------------------------------ napi/index.d.ts | 11 +- napi/src/lib.rs | 55 ++------ 3 files changed, 42 insertions(+), 276 deletions(-) diff --git a/napi/__tests__/parse.test.ts b/napi/__tests__/parse.test.ts index 7e3defaa..75b3f4cb 100644 --- a/napi/__tests__/parse.test.ts +++ b/napi/__tests__/parse.test.ts @@ -508,70 +508,20 @@ This is a paragraph. Another paragraph.`); - expect(sections).toMatchInlineSnapshot(` + expect(stripPositions(sections)).toMatchInlineSnapshot(` [ { - "position": { - "end": { - "column": 14, - "line": 1, - "offset": 13, - }, - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "raw": "# Hello World", + "depth": 1, "type": "heading", }, { - "position": { - "end": { - "column": 21, - "line": 3, - "offset": 35, - }, - "start": { - "column": 1, - "line": 3, - "offset": 15, - }, - }, - "raw": "This is a paragraph.", "type": "paragraph", }, { - "position": { - "end": { - "column": 14, - "line": 5, - "offset": 50, - }, - "start": { - "column": 1, - "line": 5, - "offset": 37, - }, - }, - "raw": "## Subheading", + "depth": 2, "type": "heading", }, { - "position": { - "end": { - "column": 19, - "line": 7, - "offset": 70, - }, - "start": { - "column": 1, - "line": 7, - "offset": 52, - }, - }, - "raw": "Another paragraph.", "type": "paragraph", }, ] @@ -585,22 +535,10 @@ Another paragraph.`); it("works with single element", () => { const sections = splitIntoSections("# Single Heading"); - expect(sections).toMatchInlineSnapshot(` + expect(stripPositions(sections)).toMatchInlineSnapshot(` [ { - "position": { - "end": { - "column": 17, - "line": 1, - "offset": 16, - }, - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "raw": "# Single Heading", + "depth": 1, "type": "heading", }, ] @@ -622,91 +560,28 @@ const code = "block"; \`\`\``; const sections = splitIntoSections(content); - expect(sections).toMatchInlineSnapshot(` + expect(stripPositions(sections)).toMatchInlineSnapshot(` [ { - "position": { - "end": { - "column": 10, - "line": 1, - "offset": 9, - }, - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "raw": "# Heading", + "depth": 1, "type": "heading", }, { - "position": { - "end": { - "column": 30, - "line": 3, - "offset": 40, - }, - "start": { - "column": 1, - "line": 3, - "offset": 11, - }, - }, - "raw": "Paragraph with **bold** text.", "type": "paragraph", }, { - "position": { - "end": { - "column": 18, - "line": 5, - "offset": 59, - }, - "start": { - "column": 1, - "line": 5, - "offset": 42, - }, - }, - "raw": "> Blockquote here", "type": "blockquote", }, { - "position": { - "end": { - "column": 1, - "line": 9, - "offset": 89, - }, - "start": { - "column": 1, - "line": 7, - "offset": 61, - }, - }, - "raw": "- List item 1 - - List item 2 - ", + "ordered": false, + "spread": false, "type": "list", }, { - "position": { - "end": { - "column": 4, - "line": 12, - "offset": 140, - }, - "start": { - "column": 1, - "line": 10, - "offset": 90, - }, - }, - "raw": "\`\`\`javascript metastring - const code = "block"; - \`\`\`", + "lang": "javascript", + "meta": "metastring", "type": "code", + "value": "const code = "block";", }, ] `); @@ -724,56 +599,24 @@ const code = "block"; { mdx: true }, ); - expect(sections).toMatchInlineSnapshot(` + expect(stripPositions(sections)).toMatchInlineSnapshot(` [ { - "position": { - "end": { - "column": 26, - "line": 1, - "offset": 25, - }, - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "raw": "import React from 'react'", "type": "paragraph", }, { - "position": { - "end": { - "column": 15, - "line": 3, - "offset": 41, - }, - "start": { - "column": 1, - "line": 3, - "offset": 27, - }, - }, - "raw": "# MDX Document", + "depth": 1, "type": "heading", }, { - "position": { - "end": { - "column": 13, - "line": 7, - "offset": 90, - }, - "start": { - "column": 1, - "line": 5, - "offset": 43, - }, - }, - "raw": " - Content - ", + "attributes": [ + { + "name": "prop", + "type": "mdxJsxAttribute", + "value": "value", + }, + ], + "name": "Component", "type": "mdxJsxFlowElement", }, ] @@ -793,54 +636,25 @@ const code = "block"; }, ); - expect(sections).toMatchInlineSnapshot(` + expect(stripPositions(sections)).toMatchInlineSnapshot(` [ { - "position": { - "end": { - "column": 16, - "line": 1, - "offset": 15, - }, - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "raw": "# Hello {world}", + "depth": 1, "type": "heading", }, { - "position": { - "end": { - "column": 13, - "line": 3, - "offset": 29, - }, - "start": { - "column": 1, - "line": 3, - "offset": 17, - }, - }, - "raw": "{expression}", + "_markdownRsStops": [ + [ + 0, + 18, + ], + ], "type": "mdxFlowExpression", + "value": "expression", }, { - "position": { - "end": { - "column": 14, - "line": 5, - "offset": 44, - }, - "start": { - "column": 1, - "line": 5, - "offset": 31, - }, - }, - "raw": "", + "attributes": [], + "name": "Component", "type": "mdxJsxFlowElement", }, ] diff --git a/napi/index.d.ts b/napi/index.d.ts index 2056045e..14832b39 100644 --- a/napi/index.d.ts +++ b/napi/index.d.ts @@ -19,13 +19,4 @@ export interface ParseOptions { frontmatter?: boolean } -export interface Section { - /** Raw text content of the section */ - raw: string - /** Type of the section (e.g., "heading", "paragraph", etc.) */ - type: string - /** Position information */ - position?: any -} - -export declare function splitIntoSections(input: string, options?: ParseOptions | undefined | null): Array
+export declare function splitIntoSections(input: string, options?: ParseOptions | undefined | null): Array diff --git a/napi/src/lib.rs b/napi/src/lib.rs index 02d2efef..3af3e874 100644 --- a/napi/src/lib.rs +++ b/napi/src/lib.rs @@ -21,15 +21,7 @@ pub struct ParseOptions { pub frontmatter: Option, } -#[napi(object)] -pub struct Section { - /// Raw text content of the section - pub raw: String, - /// Type of the section (e.g., "heading", "paragraph", etc.) - pub r#type: String, - /// Position information - pub position: Option, -} + impl ParseOptions { fn to_rust_parse_options(&self) -> markdown::ParseOptions { @@ -92,7 +84,7 @@ pub fn parse(input: String, options: Option) -> Result { } #[napi] -pub fn split_into_sections(input: String, options: Option) -> Result> { +pub fn split_into_sections(input: String, options: Option) -> Result> { let parse_options = match options { Some(opts) => opts.to_rust_parse_options(), None => markdown::ParseOptions::default(), @@ -108,43 +100,12 @@ pub fn split_into_sections(input: String, options: Option) -> Resu if let Some(children) = ast_value.get("children").and_then(|c| c.as_array()) { for child in children { - let node_type = child - .get("type") - .and_then(|t| t.as_str()) - .unwrap_or("unknown") - .to_string(); - - let position = child.get("position").cloned(); - - // Extract raw text from position - let raw = if let Some(pos) = &position { - if let (Some(start), Some(end)) = ( - pos.get("start") - .and_then(|s| s.get("offset")) - .and_then(|o| o.as_u64()), - pos.get("end") - .and_then(|e| e.get("offset")) - .and_then(|o| o.as_u64()), - ) { - let start_idx = start as usize; - let end_idx = end as usize; - if start_idx <= input.len() && end_idx <= input.len() && start_idx <= end_idx { - input[start_idx..end_idx].to_string() - } else { - String::new() - } - } else { - String::new() - } - } else { - String::new() - }; - - sections.push(Section { - raw, - r#type: node_type, - position, - }); + let mut node = child.clone(); + // Remove children field if it exists + if let Some(obj) = node.as_object_mut() { + obj.remove("children"); + } + sections.push(node); } } From 845ac344434ebc56c5528a5d1a24fe3c9d9edcc0 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 17:29:32 +0200 Subject: [PATCH 46/61] smaller npm package --- napi/package.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/napi/package.json b/napi/package.json index 67e7aa64..4af5cfcb 100644 --- a/napi/package.json +++ b/napi/package.json @@ -11,6 +11,12 @@ "access": "public" }, "repository": "https://github.com/remorses/markdown-rs", + "files": [ + "index.d.ts", + "index.js", + "browser.js", + "webcontainer-fallback.js" + ], "napi": { "binaryName": "markdown-rs", "packageName": "@xmorse/markdown-rs-binding", From 6beb6b33cef539f528215b76dfe84dbbaf702278 Mon Sep 17 00:00:00 2001 From: remorses Date: Wed, 18 Jun 2025 17:46:34 +0200 Subject: [PATCH 47/61] package --- napi/package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/napi/package.json b/napi/package.json index 4af5cfcb..a6404f1a 100644 --- a/napi/package.json +++ b/napi/package.json @@ -1,6 +1,9 @@ { "name": "@xmorse/markdown-rs", - "version": "0.0.3", + "description": "Fast markdown and mdx parser written in Rust", + "version": "0.0.4", + "main": "index.js", + "browser": "browser.js", "scripts": { "build:debug": "pnpm napi build --platform --manifest-path Cargo.toml", "test": "pnpm vitest", From 6dc1af1217e99100a20802a15a8b3386b150b2b7 Mon Sep 17 00:00:00 2001 From: remorses Date: Fri, 20 Jun 2025 10:23:50 +0200 Subject: [PATCH 48/61] shorter readme --- napi/README.md | 442 +------------------------------------------------ 1 file changed, 1 insertion(+), 441 deletions(-) diff --git a/napi/README.md b/napi/README.md index f3710bab..069647e9 100644 --- a/napi/README.md +++ b/napi/README.md @@ -1,443 +1,3 @@ -

-
- -
-
-
-

- # markdown-rs -[![Build][badge-build-image]][badge-build-url] -[![Coverage][badge-coverage-image]][badge-coverage-url] - -CommonMark compliant markdown parser in Rust with ASTs and extensions. - -## Feature highlights - -* [x] **[compliant][commonmark]** - (100% to CommonMark) -* [x] **[extensions][]** - (100% GFM, 100% MDX, frontmatter, math) -* [x] **[safe][security]** - (100% safe Rust, also 100% safe HTML by default) -* [x] **[robust][test]** - (2300+ tests, 100% coverage, fuzz testing) -* [x] **[ast][mdast]** - (mdast) - -## Links - -* [GitHub: `wooorm/markdown-rs`][repo] -* [`crates.io`: `markdown`][crate] -* [`docs.rs`: `markdown`][docs] - -## When should I use this? - -* if you *just* want to turn markdown into HTML (with maybe a few extensions) -* if you want to do *really complex things* with markdown - -## What is this? - -`markdown-rs` is an open source markdown parser written in Rust. -It’s implemented as a state machine (`#![no_std]` + `alloc`) that emits -concrete tokens, -so that every byte is accounted for, -with positional info. -The API then exposes this information as an AST, -which is easier to work with, -or it compiles directly to HTML. - -While most markdown parsers work towards compliancy with CommonMark (or GFM), -this project goes further by following how the reference parsers (`cmark`, -`cmark-gfm`) work, -which is confirmed with thousands of extra tests. - -Other than CommonMark and GFM, -this project also supports common extensions to markdown such as -MDX, math, and frontmatter. - -This Rust crate has a sibling project in JavaScript: -[`micromark`][micromark] -(and [`mdast-util-from-markdown`][mdast-util-from-markdown] for the AST). - -P.S. if you want to *compile* MDX, -use [`mdxjs-rs`][mdxjs-rs]. - -## Questions - -* to learn markdown, - see this [cheatsheet and tutorial][cheat] -* for the API, - see the [crate docs][docs] -* for questions, - see [Discussions][] -* to help, - see [contribute][] or [sponsor][] below - -## Contents - -* [Install](#install) -* [Use](#use) -* [API](#api) -* [Extensions](#extensions) -* [Project](#project) - * [Overview](#overview) - * [File structure](#file-structure) - * [Test](#test) - * [Version](#version) - * [Security](#security) - * [Contribute](#contribute) - * [Sponsor](#sponsor) - * [Thanks](#thanks) -* [Related](#related) -* [License](#license) - -## Install - -With [Rust][] -(rust edition 2018+, ±version 1.56+), -install with `cargo`: - -```sh -cargo add markdown -``` - -## Use - -```rs -fn main() { - println!("{}", markdown::to_html("## Hi, *Saturn*! 🪐")); -} -``` - -Yields: - -```html -

Hi, Saturn! 🪐

-``` - -Extensions (in this case GFM): - -```rs -fn main() -> Result<(), markdown::message::Message> { - println!( - "{}", - markdown::to_html_with_options( - "* [x] contact ~Mercury~Venus at hi@venus.com!", - &markdown::Options::gfm() - )? - ); - - Ok(()) -} -``` - -Yields: - -```html - -``` - -Syntax tree ([mdast][]): - -```rs -fn main() -> Result<(), markdown::message::Message> { - println!( - "{:?}", - markdown::to_mdast("# Hi *Earth*!", &markdown::ParseOptions::default())? - ); - - Ok(()) -} -``` - -Yields: - -```text -Root { children: [Heading { children: [Text { value: "Hi ", position: Some(1:3-1:6 (2-5)) }, Emphasis { children: [Text { value: "Earth", position: Some(1:7-1:12 (6-11)) }], position: Some(1:6-1:13 (5-12)) }, Text { value: "!", position: Some(1:13-1:14 (12-13)) }], position: Some(1:1-1:14 (0-13)), depth: 1 }], position: Some(1:1-1:14 (0-13)) } -``` - -## API - -`markdown-rs` exposes -[`to_html`](https://docs.rs/markdown/latest/markdown/fn.to_html.html), -[`to_html_with_options`](https://docs.rs/markdown/latest/markdown/fn.to_html_with_options.html), -[`to_mdast`](https://docs.rs/markdown/latest/markdown/fn.to_mdast.html), -[`Options`](https://docs.rs/markdown/latest/markdown/struct.Options.html), -and a few other structs and enums. - -See the [crate docs][docs] for more info. - -## Extensions - -`markdown-rs` supports extensions to `CommonMark`. -These extensions are maintained in this project. -They are not enabled by default but can be turned on with options. - -* GFM - * autolink literal - * footnote - * strikethrough - * table - * tagfilter - * task list item -* MDX - * ESM - * expressions - * JSX -* frontmatter -* math - -It is not a goal of this project to support lots of different extensions. -It’s instead a goal to support very common and mostly standardized extensions. - -## Project - -`markdown-rs` is maintained as a single monolithic crate. - -### Overview - -The process to parse markdown looks like this: - -```txt - markdown-rs -+-------------------------------------------------+ -| +-------+ +---------+--html- | -| -markdown->+ parse +-events->+ compile + | -| +-------+ +---------+-mdast- | -+-------------------------------------------------+ -``` - -### File structure - -The files in `src/` are as follows: - -* `construct/*.rs` - — CommonMark, GFM, and other extension constructs used in markdown -* `util/*.rs` - — helpers often needed when parsing markdown -* `event.rs` - — things with meaning happening somewhere -* `lib.rs` - — public API -* `mdast.rs` - — syntax tree -* `parser.rs` - — turn a string of markdown into events -* `resolve.rs` - — steps to process events -* `state.rs` - — steps of the state machine -* `subtokenize.rs` - — handle content in other content -* `to_html.rs` - — turns events into a string of HTML -* `to_mdast.rs` - — turns events into a syntax tree -* `tokenizer.rs` - — glue the states of the state machine together -* `unist.rs` - — point and position, used in mdast - -### Test - -`markdown-rs` is tested with the \~650 CommonMark tests and more than 1k extra -tests confirmed with CM reference parsers. -Then there’s even more tests for GFM and other extensions. -These tests reach all branches in the code, -which means that this project has 100% code coverage. -Fuzz testing is used to check for things that might fall through coverage. - -The following bash scripts are useful when working on this project: - -* generate code (latest CM tests and Unicode info): - ```sh - cargo run --manifest-path generate/Cargo.toml - ``` -* run examples: - ```sh - RUST_BACKTRACE=1 RUST_LOG=trace cargo run --example lib --features log - ``` -* format: - ```sh - cargo fmt && cargo fix --all-features --all-targets --workspace - ``` -* lint: - ```sh - cargo fmt --check && cargo clippy --all-features --all-targets --workspace - ``` -* test: - ```sh - RUST_BACKTRACE=1 cargo test --all-features --workspace - ``` -* docs: - ```sh - cargo doc --document-private-items --examples --workspace - ``` -* fuzz: - ```sh - cargo install cargo-fuzz - cargo install honggfuzz - cargo +nightly fuzz run markdown_libfuzz - cargo hfuzz run markdown_honggfuzz - ``` - -### Version - -`markdown-rs` follows [SemVer](https://semver.org). - -### Security - -The typical security aspect discussed for markdown is [cross-site scripting -(XSS)][xss] attacks. -Markdown itself is safe if it does not include embedded HTML or dangerous -protocols in links/images (such as `javascript:`). -`markdown-rs` makes any markdown safe by default, -even if HTML is embedded or dangerous protocols are used, -as it encodes or drops them. - -Turning on the `allow_dangerous_html` or `allow_dangerous_protocol` options for -user-provided markdown opens you up to XSS attacks. - -Additionnally, -you should be able to set `allow_any_img_src` safely. -The default is to allow only `http:`, `https:`, and relative images, -which is what GitHub does. -But it should be safe to allow any value on `src`. - -The [HTML specification][whatwg-html-image] prohibits dangerous scripts in -images and all modern browsers respect this and are thus safe. -Opera 12 (from 2012) is a notable browser that did not respect this. - -An aspect related to XSS for security is syntax errors: -markdown itself has no syntax errors. -Some syntax extensions -(specifically, only MDX) -do include syntax errors. -For that reason, -`to_html_with_options` returns `Result`, -of which the error is a struct indicating where the problem happened, -what occurred, -and what was expected instead. -Make sure to handle your errors when using MDX. - -Another security aspect is DDoS attacks. -For example, -an attacker could throw a 100mb file at `markdown-rs`, -in which case it’s going to take a long while to finish. -It is also possible to crash `markdown-rs` with smaller payloads, -notably when thousands of -links, images, emphasis, or strong -are opened but not closed. -It is wise to cap the accepted size of input (500kb can hold a big book) and to -process content in a different thread so that it can be stopped when needed. - -For more information on markdown sanitation, -see -[`improper-markup-sanitization.md`][improper] by [**@chalker**][chalker]. - -### Contribute - -See [`contributing.md`][contributing] for ways to help. -See [`support.md`][support] for ways to get help. -See [`code-of-conduct.md`][coc] for how to communicate in and around this -project. - -### Sponsor - -Support this effort and give back by sponsoring: - -* [GitHub Sponsors](https://github.com/sponsors/wooorm) - (personal; monthly or one-time) -* [OpenCollective](https://opencollective.com/unified) or - [GitHub Sponsors](https://github.com/sponsors/unifiedjs) - (unified; monthly or one-time) - -### Thanks - -Special thanks go out to: - -* [Vercel][] for funding the initial development -* [**@Murderlon**][murderlon] for the design of the logo -* [**@johannhof**][johannhof] for the crate name - -## Related - -* [`micromark`][micromark] - — same as `markdown-rs` but in JavaScript -* [`mdxjs-rs`][mdxjs-rs] - — wraps `markdown-rs` to *compile* MDX to JavaScript - -## License - -[MIT][license] © [Titus Wormer][author] - -[badge-build-image]: https://github.com/wooorm/markdown-rs/workflows/main/badge.svg - -[badge-build-url]: https://github.com/wooorm/markdown-rs/actions - -[badge-coverage-image]: https://img.shields.io/codecov/c/github/wooorm/markdown-rs.svg - -[badge-coverage-url]: https://codecov.io/github/wooorm/markdown-rs - -[docs]: https://docs.rs/markdown/latest/markdown/ - -[crate]: https://crates.io/crates/markdown - -[repo]: https://github.com/wooorm/markdown-rs - -[discussions]: https://github.com/wooorm/markdown-rs/discussions - -[commonmark]: https://spec.commonmark.org - -[cheat]: https://commonmark.org/help/ - -[rust]: https://www.rust-lang.org - -[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting - -[improper]: https://github.com/ChALkeR/notes/blob/master/Improper-markup-sanitization.md - -[chalker]: https://github.com/ChALkeR - -[license]: license - -[author]: https://wooorm.com - -[mdast]: https://github.com/syntax-tree/mdast - -[micromark]: https://github.com/micromark/micromark - -[mdxjs-rs]: https://github.com/wooorm/mdxjs-rs - -[mdast-util-from-markdown]: https://github.com/syntax-tree/mdast-util-from-markdown - -[vercel]: https://vercel.com - -[murderlon]: https://github.com/murderlon - -[johannhof]: https://github.com/johannhof - -[contribute]: #contribute - -[sponsor]: #sponsor - -[extensions]: #extensions - -[security]: #security - -[test]: #test - -[contributing]: .github/contribute.md - -[support]: .github/support.md - -[coc]: .github/code-of-conduct.md - -[whatwg-html-image]: https://html.spec.whatwg.org/multipage/images.html#images-processing-model +CommonMark compliant markdown parser in Rust with ASTs and extensions. Packaged for npm with full WASM support. From 27b14ef3d3406d0c862c43e564c1bd4d83902a75 Mon Sep 17 00:00:00 2001 From: remorses Date: Fri, 20 Jun 2025 10:28:33 +0200 Subject: [PATCH 49/61] remoe splitIntoSections function --- .github/contribute.md | 8 ++ napi/.gitignore | 4 - napi/AGENTS.md | 8 -- napi/__tests__/parse.bench.ts | 10 +- napi/__tests__/parse.test.ts | 213 +--------------------------------- napi/index.d.ts | 2 - napi/index.js | 1 - napi/src/lib.rs | 28 ----- package.json | 3 +- 9 files changed, 11 insertions(+), 266 deletions(-) delete mode 100644 napi/.gitignore delete mode 100644 napi/AGENTS.md diff --git a/.github/contribute.md b/.github/contribute.md index 3290ff95..a67061c9 100644 --- a/.github/contribute.md +++ b/.github/contribute.md @@ -36,6 +36,14 @@ It’s probably a good idea to first post a question or open an issue to report bug or suggest a new feature before creating a pull request. See [Project][] for more info. +## `napi` folder + +This is the package that handles NAPI bindings for markdown-rs. It also supports WASM. It uses napi-rs to generate the npm packages published on npm. + +Tests use vitest, expect().toMatchInlineSnapshot() mostly. Most tests should be run with `pnpm vitest --run -u` to update snapshots, then read the test file again and make sure they have the expected result. + +When making changes in rust run `pnpm build:debug` to make sure the Rust code compiles. + ## Submitting an issue * the issue tracker is for issues, discussions are for questions diff --git a/napi/.gitignore b/napi/.gitignore deleted file mode 100644 index 8fc295e3..00000000 --- a/napi/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -index.*.node -package-lock.json -out diff --git a/napi/AGENTS.md b/napi/AGENTS.md deleted file mode 100644 index b9170a68..00000000 --- a/napi/AGENTS.md +++ /dev/null @@ -1,8 +0,0 @@ - -This is the package that handles NAPI bindings for markdown-rs. It also supports wasm. - -## Testing - -Tests use vitest, use expect().toMatchInlineSnapshot() mostly. Never pass the snapshot yourself, instead leave it empty and then run the test with `pnpm vitest --run -u` to update snapshots, then read the test file again and make sure it has the expected result. - -When making changes in rust run `pnpm build:debug` to make sure the Rust compiles. If not fix all the errors. Try to not change other crates source code, which are unrelated to the npm package diff --git a/napi/__tests__/parse.bench.ts b/napi/__tests__/parse.bench.ts index 578c3c2e..da256a4d 100644 --- a/napi/__tests__/parse.bench.ts +++ b/napi/__tests__/parse.bench.ts @@ -1,5 +1,5 @@ import { bench, describe } from "vitest"; -import { parse, splitIntoSections } from "../"; +import { parse } from "../"; import { remark } from "remark"; import remarkMdx from "remark-mdx"; @@ -271,14 +271,6 @@ describe("MDX Parsing Performance Comparison", () => { console.log(res); }); - bench("markdown-rs splitIntoSections", () => { - splitIntoSections(longMdxContent, { - mdx: true, - mdxExpressionParse: true, - mdxEsmParse: true, - }); - }); - bench("remark + remark-mdx parse", () => { remarkProcessor.runSync(remarkProcessor.parse(longMdxContent)); }); diff --git a/napi/__tests__/parse.test.ts b/napi/__tests__/parse.test.ts index 75b3f4cb..b9a438ae 100644 --- a/napi/__tests__/parse.test.ts +++ b/napi/__tests__/parse.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { parse, splitIntoSections } from "../"; +import { parse } from "../"; describe("parse", () => { it("parse accepts options parameter", () => { @@ -498,217 +498,6 @@ this is a callout }); }); -describe("split_into_sections", () => { - it("splits basic markdown into sections", () => { - const sections = splitIntoSections(`# Hello World - -This is a paragraph. - -## Subheading - -Another paragraph.`); - - expect(stripPositions(sections)).toMatchInlineSnapshot(` - [ - { - "depth": 1, - "type": "heading", - }, - { - "type": "paragraph", - }, - { - "depth": 2, - "type": "heading", - }, - { - "type": "paragraph", - }, - ] - `); - }); - - it("handles empty content", () => { - const sections = splitIntoSections(""); - expect(sections).toMatchInlineSnapshot(`[]`); - }); - - it("works with single element", () => { - const sections = splitIntoSections("# Single Heading"); - expect(stripPositions(sections)).toMatchInlineSnapshot(` - [ - { - "depth": 1, - "type": "heading", - }, - ] - `); - }); - - it("works with different markdown elements", () => { - const content = `# Heading - -Paragraph with **bold** text. - -> Blockquote here - -- List item 1 -- List item 2 - -\`\`\`javascript metastring -const code = "block"; -\`\`\``; - - const sections = splitIntoSections(content); - expect(stripPositions(sections)).toMatchInlineSnapshot(` - [ - { - "depth": 1, - "type": "heading", - }, - { - "type": "paragraph", - }, - { - "type": "blockquote", - }, - { - "ordered": false, - "spread": false, - "type": "list", - }, - { - "lang": "javascript", - "meta": "metastring", - "type": "code", - "value": "const code = "block";", - }, - ] - `); - }); - - it("works with MDX content", () => { - const sections = splitIntoSections( - `import React from 'react' - -# MDX Document - - - Content -`, - { mdx: true }, - ); - - expect(stripPositions(sections)).toMatchInlineSnapshot(` - [ - { - "type": "paragraph", - }, - { - "depth": 1, - "type": "heading", - }, - { - "attributes": [ - { - "name": "prop", - "type": "mdxJsxAttribute", - "value": "value", - }, - ], - "name": "Component", - "type": "mdxJsxFlowElement", - }, - ] - `); - }); - - it("works with MDX and expression parsing enabled", () => { - const sections = splitIntoSections( - `# Hello {world} - -{expression} - -`, - { - mdx: true, - mdxExpressionParse: true, - }, - ); - - expect(stripPositions(sections)).toMatchInlineSnapshot(` - [ - { - "depth": 1, - "type": "heading", - }, - { - "_markdownRsStops": [ - [ - 0, - 18, - ], - ], - "type": "mdxFlowExpression", - "value": "expression", - }, - { - "attributes": [], - "name": "Component", - "type": "mdxJsxFlowElement", - }, - ] - `); - }); - - it("extracts frontmatter section", () => { - const content = `--- -title: Hello World -tags: - - test - - doc ---- - -# Heading - -Content goes here. -`; - const sections = splitIntoSections(content, { - mdx: true, - frontmatter: true, - }); - - expect(sections[0].type).toBe("yaml"); - expect(sections[0].raw).toBe(`--- -title: Hello World -tags: - - test - - doc ----`); - }); - - it("preserves exact raw text with complex formatting", () => { - const content = "# Title\n\nParagraph with *emphasis* and `code`."; - const sections = splitIntoSections(content); - - expect(sections[0].raw).toBe("# Title"); - expect(sections[1].raw).toBe("Paragraph with *emphasis* and `code`."); - expect(sections[0].type).toBe("heading"); - expect(sections[1].type).toBe("paragraph"); - }); - - it("accepts parse options", () => { - const sections = splitIntoSections("# Title\n\nSome content", { - gfmStrikethroughSingleTilde: false, - mathTextSingleDollar: true, - }); - - expect(sections).toHaveLength(2); - expect(sections[0].type).toBe("heading"); - expect(sections[1].type).toBe("paragraph"); - }); -}); - /** * Removes all "position" fields from an mdast/unist tree node (in-place). * @param node - The tree node to clean. diff --git a/napi/index.d.ts b/napi/index.d.ts index 14832b39..97187c5a 100644 --- a/napi/index.d.ts +++ b/napi/index.d.ts @@ -18,5 +18,3 @@ export interface ParseOptions { /** Whether to support frontmatter */ frontmatter?: boolean } - -export declare function splitIntoSections(input: string, options?: ParseOptions | undefined | null): Array diff --git a/napi/index.js b/napi/index.js index 7e13ed3f..a183e857 100644 --- a/napi/index.js +++ b/napi/index.js @@ -377,4 +377,3 @@ if (!nativeBinding) { module.exports = nativeBinding module.exports.parse = nativeBinding.parse -module.exports.splitIntoSections = nativeBinding.splitIntoSections diff --git a/napi/src/lib.rs b/napi/src/lib.rs index 3af3e874..1ef6442e 100644 --- a/napi/src/lib.rs +++ b/napi/src/lib.rs @@ -83,34 +83,6 @@ pub fn parse(input: String, options: Option) -> Result { serde_json::to_value(&tree).map_err(|e| Error::from_reason(e.to_string())) } -#[napi] -pub fn split_into_sections(input: String, options: Option) -> Result> { - let parse_options = match options { - Some(opts) => opts.to_rust_parse_options(), - None => markdown::ParseOptions::default(), - }; - - let tree = markdown::to_mdast(&input, &parse_options) - .map_err(|e| Error::from_reason(format!("{:?}", e)))?; - - // Convert AST to JSON to extract children - let ast_value = serde_json::to_value(&tree).map_err(|e| Error::from_reason(e.to_string()))?; - - let mut sections = Vec::new(); - - if let Some(children) = ast_value.get("children").and_then(|c| c.as_array()) { - for child in children { - let mut node = child.clone(); - // Remove children field if it exists - if let Some(obj) = node.as_object_mut() { - obj.remove("children"); - } - sections.push(node); - } - } - - Ok(sections) -} // #[napi] // pub fn to_html(mdx: String) -> Value { diff --git a/package.json b/package.json index 6cb1bf6b..301705f0 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,7 @@ "name": "root", "scripts": { "build:debug": "pnpm napi build --platform --manifest-path napi/Cargo.toml", - "build": "pnpm run build:debug --release", - "npm-dirs": "pnpm napi create-npm-dirs --package-json-path package.json" + "build": "pnpm run build:debug --release" }, "dependencies": { "@napi-rs/cli": "3.0.0-alpha.89" From e78532f5e6ef2f40d24b66aa688e52966b81510d Mon Sep 17 00:00:00 2001 From: remorses Date: Fri, 20 Jun 2025 10:37:58 +0200 Subject: [PATCH 50/61] re enable windows --- .github/workflows/release-napi.yml | 70 +++++++++++++++--------------- napi/package.json | 4 +- 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/.github/workflows/release-napi.yml b/.github/workflows/release-napi.yml index 34c5e03b..cdbe1ff0 100644 --- a/.github/workflows/release-napi.yml +++ b/.github/workflows/release-napi.yml @@ -5,10 +5,11 @@ permissions: {} on: workflow_dispatch: push: + paths: + - package.json + # TODO enable the release napi workflow only on main # branches: # - main - # paths: - # - package.json concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -18,45 +19,44 @@ env: DEBUG: "napi:*" jobs: - # check: - # name: Check version - # runs-on: ubuntu-latest - # outputs: - # version_changed: ${{ steps.version.outputs.changed }} - # steps: - # - uses: taiki-e/checkout-action@b13d20b7cda4e2f325ef19895128f7ff735c0b3d # v1.3.1 - - # - name: Check version changes - # uses: EndBug/version-check@36ff30f37c7deabe56a30caa043d127be658c425 # v2.1.5 - # id: version - # with: - # static-checking: localIsNew - # file-url: https://unpkg.com/oxc-resolver@latest/package.json - # file-name: package.json - - # - name: Set version name - # if: steps.version.outputs.changed == 'true' - # env: - # version: ${{ steps.version.outputs.version }} - # run: echo "version=${version}" + check: + name: Check version + runs-on: ubuntu-latest + outputs: + version_changed: ${{ steps.version.outputs.changed }} + steps: + - uses: taiki-e/checkout-action@b13d20b7cda4e2f325ef19895128f7ff735c0b3d # v1.3.1 + + - name: Check version changes + uses: EndBug/version-check@36ff30f37c7deabe56a30caa043d127be658c425 # v2.1.5 + id: version + with: + static-checking: localIsNew + file-url: https://unpkg.com/@xmorse/markdown-rs@latest/package.json + file-name: package.json + + - name: Set version name + if: steps.version.outputs.changed == 'true' + env: + version: ${{ steps.version.outputs.version }} + run: echo "version=${version}" build: - # needs: check - # if: needs.check.outputs.version_changed == 'true' + needs: check + if: needs.check.outputs.version_changed == 'true' strategy: fail-fast: false matrix: include: - # TODO add in package.json "x86_64-pc-windows-msvc","aarch64-pc-windows-msvc", - # - os: windows-latest - # target: x86_64-pc-windows-msvc - # build: | - # pnpm build --target x86_64-pc-windows-msvc - - # - os: windows-latest - # target: aarch64-pc-windows-msvc - # build: | - # pnpm build --target aarch64-pc-windows-msvc + - os: windows-latest + target: x86_64-pc-windows-msvc + build: | + pnpm build --target x86_64-pc-windows-msvc + + - os: windows-latest + target: aarch64-pc-windows-msvc + build: | + pnpm build --target aarch64-pc-windows-msvc - os: ubuntu-latest target: x86_64-unknown-linux-gnu diff --git a/napi/package.json b/napi/package.json index a6404f1a..5b03b71d 100644 --- a/napi/package.json +++ b/napi/package.json @@ -24,6 +24,8 @@ "binaryName": "markdown-rs", "packageName": "@xmorse/markdown-rs-binding", "targets": [ + "x86_64-pc-windows-msvc", + "aarch64-pc-windows-msvc", "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl", "aarch64-unknown-linux-gnu", @@ -36,7 +38,7 @@ "wasm32-wasip1-threads" ], "wasm": { - "initialMemory": 16384 + "initialMemory": 4000 } }, "devDependencies": { From d02b6ade2ee349a7f1e5f587062c9619408e0923 Mon Sep 17 00:00:00 2001 From: remorses Date: Fri, 20 Jun 2025 10:38:34 +0200 Subject: [PATCH 51/61] rename to tests --- napi/{__tests__ => tests}/parse.bench.ts | 0 napi/{__tests__ => tests}/parse.test.ts | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename napi/{__tests__ => tests}/parse.bench.ts (100%) rename napi/{__tests__ => tests}/parse.test.ts (100%) diff --git a/napi/__tests__/parse.bench.ts b/napi/tests/parse.bench.ts similarity index 100% rename from napi/__tests__/parse.bench.ts rename to napi/tests/parse.bench.ts diff --git a/napi/__tests__/parse.test.ts b/napi/tests/parse.test.ts similarity index 100% rename from napi/__tests__/parse.test.ts rename to napi/tests/parse.test.ts From b30edd9e9e6943bfad69166e6682668c2dfe60cb Mon Sep 17 00:00:00 2001 From: remorses Date: Fri, 20 Jun 2025 10:59:44 +0200 Subject: [PATCH 52/61] add benchmark, add toHtml function --- napi/index.d.ts | 34 +++ napi/index.js | 1 + napi/package.json | 7 +- napi/src/lib.rs | 109 ++++++++- napi/tests/benchmark.ts | 34 +++ napi/tests/parse.bench.ts | 277 --------------------- napi/tests/to-html.test.ts | 224 +++++++++++++++++ pnpm-lock.yaml | 485 +++++++++++++++++++++++++++++++++++++ 8 files changed, 887 insertions(+), 284 deletions(-) create mode 100644 napi/tests/benchmark.ts delete mode 100644 napi/tests/parse.bench.ts create mode 100644 napi/tests/to-html.test.ts diff --git a/napi/index.d.ts b/napi/index.d.ts index 97187c5a..b1254b92 100644 --- a/napi/index.d.ts +++ b/napi/index.d.ts @@ -1,5 +1,37 @@ /* auto-generated by NAPI-RS */ /* eslint-disable */ +export interface CompileOptions { + /** Whether to allow (dangerous) HTML */ + allowDangerousHtml?: boolean + /** Whether to allow dangerous protocols in links and images */ + allowDangerousProtocol?: boolean + /** Whether to allow all values in images */ + allowAnyImgSrc?: boolean + /** Default line ending to use when compiling to HTML */ + defaultLineEnding?: string + /** Textual label to describe the backreference back to footnote calls */ + gfmFootnoteBackLabel?: string + /** Prefix to use before the `id` attribute on footnotes */ + gfmFootnoteClobberPrefix?: string + /** Textual label to use for the footnotes section */ + gfmFootnoteLabel?: string + /** Attributes to use on the footnote label */ + gfmFootnoteLabelAttributes?: string + /** HTML tag name to use for the footnote label element */ + gfmFootnoteLabelTagName?: string + /** Whether or not GFM task list html `` items are enabled */ + gfmTaskListItemCheckable?: boolean + /** Whether to support the GFM tagfilter */ + gfmTagfilter?: boolean +} + +export interface HtmlOptions { + /** Configuration that describes how to parse from markdown */ + parse?: ParseOptions + /** Configuration that describes how to compile to HTML */ + compile?: CompileOptions +} + export declare function parse(input: string, options?: ParseOptions | undefined | null): any export interface ParseOptions { @@ -18,3 +50,5 @@ export interface ParseOptions { /** Whether to support frontmatter */ frontmatter?: boolean } + +export declare function toHtml(input: string, options?: HtmlOptions | undefined | null): string diff --git a/napi/index.js b/napi/index.js index a183e857..57eff852 100644 --- a/napi/index.js +++ b/napi/index.js @@ -377,3 +377,4 @@ if (!nativeBinding) { module.exports = nativeBinding module.exports.parse = nativeBinding.parse +module.exports.toHtml = nativeBinding.toHtml diff --git a/napi/package.json b/napi/package.json index 5b03b71d..9cf2c497 100644 --- a/napi/package.json +++ b/napi/package.json @@ -7,7 +7,7 @@ "scripts": { "build:debug": "pnpm napi build --platform --manifest-path Cargo.toml", "test": "pnpm vitest", - "bench": "pnpm vitest bench", + "benchmark": "pnpm tsx tests/benchmark.ts", "build": "pnpm run build:debug --release" }, "publishConfig": { @@ -43,11 +43,14 @@ }, "devDependencies": { "@emnapi/runtime": "^1.4.3", - "@napi-rs/wasm-runtime": "^0.2.7", "@napi-rs/cli": "3.0.0-alpha.89", + "@napi-rs/wasm-runtime": "^0.2.7", "emnapi": "^1.4.3", + "mitata": "^1.0.34", "remark": "^15.0.1", + "remark-gfm": "^4.0.1", "remark-mdx": "^3.0.1", + "tsx": "^4.20.3", "vitest": "^1.5.0" } } diff --git a/napi/src/lib.rs b/napi/src/lib.rs index 1ef6442e..7c2849f4 100644 --- a/napi/src/lib.rs +++ b/napi/src/lib.rs @@ -21,7 +21,39 @@ pub struct ParseOptions { pub frontmatter: Option, } +#[napi(object)] +pub struct CompileOptions { + /// Whether to allow (dangerous) HTML + pub allow_dangerous_html: Option, + /// Whether to allow dangerous protocols in links and images + pub allow_dangerous_protocol: Option, + /// Whether to allow all values in images + pub allow_any_img_src: Option, + /// Default line ending to use when compiling to HTML + pub default_line_ending: Option, + /// Textual label to describe the backreference back to footnote calls + pub gfm_footnote_back_label: Option, + /// Prefix to use before the `id` attribute on footnotes + pub gfm_footnote_clobber_prefix: Option, + /// Textual label to use for the footnotes section + pub gfm_footnote_label: Option, + /// Attributes to use on the footnote label + pub gfm_footnote_label_attributes: Option, + /// HTML tag name to use for the footnote label element + pub gfm_footnote_label_tag_name: Option, + /// Whether or not GFM task list html `` items are enabled + pub gfm_task_list_item_checkable: Option, + /// Whether to support the GFM tagfilter + pub gfm_tagfilter: Option, +} +#[napi(object)] +pub struct HtmlOptions { + /// Configuration that describes how to parse from markdown + pub parse: Option, + /// Configuration that describes how to compile to HTML + pub compile: Option, +} impl ParseOptions { fn to_rust_parse_options(&self) -> markdown::ParseOptions { @@ -71,6 +103,69 @@ impl ParseOptions { } } +impl CompileOptions { + fn to_rust_compile_options(&self) -> markdown::CompileOptions { + let mut opts = markdown::CompileOptions::default(); + + if let Some(val) = self.allow_dangerous_html { + opts.allow_dangerous_html = val; + } + if let Some(val) = self.allow_dangerous_protocol { + opts.allow_dangerous_protocol = val; + } + if let Some(val) = self.allow_any_img_src { + opts.allow_any_img_src = val; + } + if let Some(ref val) = self.default_line_ending { + opts.default_line_ending = match val.as_str() { + "lf" | "\n" => markdown::LineEnding::LineFeed, + "cr" | "\r" => markdown::LineEnding::CarriageReturn, + "crlf" | "\r\n" => markdown::LineEnding::CarriageReturnLineFeed, + _ => markdown::LineEnding::LineFeed, + }; + } + if let Some(ref val) = self.gfm_footnote_back_label { + opts.gfm_footnote_back_label = Some(val.clone()); + } + if let Some(ref val) = self.gfm_footnote_clobber_prefix { + opts.gfm_footnote_clobber_prefix = Some(val.clone()); + } + if let Some(ref val) = self.gfm_footnote_label { + opts.gfm_footnote_label = Some(val.clone()); + } + if let Some(ref val) = self.gfm_footnote_label_attributes { + opts.gfm_footnote_label_attributes = Some(val.clone()); + } + if let Some(ref val) = self.gfm_footnote_label_tag_name { + opts.gfm_footnote_label_tag_name = Some(val.clone()); + } + if let Some(val) = self.gfm_task_list_item_checkable { + opts.gfm_task_list_item_checkable = val; + } + if let Some(val) = self.gfm_tagfilter { + opts.gfm_tagfilter = val; + } + + opts + } +} + +impl HtmlOptions { + fn to_rust_options(&self) -> markdown::Options { + let parse = match &self.parse { + Some(opts) => opts.to_rust_parse_options(), + None => markdown::ParseOptions::default(), + }; + + let compile = match &self.compile { + Some(opts) => opts.to_rust_compile_options(), + None => markdown::CompileOptions::default(), + }; + + markdown::Options { parse, compile } + } +} + #[napi] pub fn parse(input: String, options: Option) -> Result { let parse_options = match options { @@ -83,9 +178,13 @@ pub fn parse(input: String, options: Option) -> Result { serde_json::to_value(&tree).map_err(|e| Error::from_reason(e.to_string())) } +#[napi] +pub fn to_html(input: String, options: Option) -> Result { + let opts = match options { + Some(opts) => opts.to_rust_options(), + None => markdown::Options::default(), + }; -// #[napi] -// pub fn to_html(mdx: String) -> Value { -// let html = markdown::to_html(&mdx); -// html.into() -// } + markdown::to_html_with_options(&input, &opts) + .map_err(|e| Error::from_reason(format!("{:?}", e))) +} \ No newline at end of file diff --git a/napi/tests/benchmark.ts b/napi/tests/benchmark.ts new file mode 100644 index 00000000..55ceffa1 --- /dev/null +++ b/napi/tests/benchmark.ts @@ -0,0 +1,34 @@ +import { run, bench, boxplot, summary } from "mitata"; +import { parse } from "../"; +import { remark } from "remark"; +import remarkMdx from "remark-mdx"; +import remarkGfm from "remark-gfm"; + + +const remarkProcessor = remark().use(remarkMdx).use(remarkGfm); + +async function main() { + const longMdxContent = await fetch( + "https://raw.githubusercontent.com/colinhacks/zod/0a49fa39348b7c72b19ddedc3b0f879bd395304b/packages/docs/content/packages/v3.mdx", + ).then((x) => x.text()); + + boxplot(async () => { + summary(() => { + bench("markdown-rs parse", () => { + const res = parse(longMdxContent, { + mdx: true, + mdxExpressionParse: true, + mdxEsmParse: true, + gfm: true, + }); + }); + + bench("remark + remark-mdx parse", () => { + remarkProcessor.processSync(longMdxContent); + }); + }); + }); + await run(); +} + +main(); diff --git a/napi/tests/parse.bench.ts b/napi/tests/parse.bench.ts deleted file mode 100644 index da256a4d..00000000 --- a/napi/tests/parse.bench.ts +++ /dev/null @@ -1,277 +0,0 @@ -import { bench, describe } from "vitest"; -import { parse } from "../"; -import { remark } from "remark"; -import remarkMdx from "remark-mdx"; - -// Create remark processor -const remarkProcessor = remark().use(remarkMdx); - -// Long MDX content for benchmarking -let longMdxContent = `import React from 'react' -import { Button, Card, Chart } from './components' -import { useEffect, useState } from 'react' - -export const metadata = { - title: 'Performance Benchmark Document', - author: 'Benchmark Suite', - date: '2024-01-01' -} - -# Performance Test Document - -This is a comprehensive MDX document designed to test parsing performance across different implementations. - -## Introduction - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. - -### Interactive Components - - -

This document contains various MDX elements to stress-test the parser:

- -
    -
  • **JSX Components** with props
  • -
  • *JavaScript expressions* in {new Date().getFullYear()}
  • -
  • \`Inline code\` and code blocks
  • -
  • Tables, lists, and blockquotes
  • -
- - -
- -## Data Visualization - - - -## Code Examples - -Here's a TypeScript example: - -\`\`\`typescript -interface PerformanceMetrics { - parseTime: number; - memoryUsage: number; - operationsPerSecond: number; -} - -class BenchmarkRunner { - private metrics: PerformanceMetrics[] = []; - - async runBenchmark(iterations: number): Promise { - const startTime = performance.now(); - const startMemory = process.memoryUsage().heapUsed; - - for (let i = 0; i < iterations; i++) { - await this.executeOperation(); - } - - const endTime = performance.now(); - const endMemory = process.memoryUsage().heapUsed; - - return { - parseTime: endTime - startTime, - memoryUsage: endMemory - startMemory, - operationsPerSecond: iterations / ((endTime - startTime) / 1000) - }; - } -} -\`\`\` - -### JavaScript Example - -\`\`\`javascript -function calculatePerformance(data) { - return data - .filter(item => item.value > 0) - .map(item => ({ - ...item, - normalized: item.value / Math.max(...data.map(d => d.value)) - })) - .sort((a, b) => b.normalized - a.normalized); -} - -const results = calculatePerformance([ - { name: 'Parser A', value: 1200 }, - { name: 'Parser B', value: 800 }, - { name: 'Parser C', value: 1500 } -]); -\`\`\` - -## Mathematical Expressions - -Performance can be measured using various metrics: $T = \\frac{n}{ops/sec}$ - -Where: -- $T$ is total time -- $n$ is number of operations -- $ops/sec$ is operations per second - -Complex equation: $$\\sum_{i=1}^{n} \\frac{1}{T_i} = \\frac{n}{\\bar{T}}$$ - -## Tables and Data - -| Parser | Speed (ops/sec) | Memory (MB) | Bundle Size (KB) | -|--------|-----------------|-------------|------------------| -| markdown-rs | {1000 + Math.floor(Math.random() * 500)} | 12.4 | 89.2 | -| remark | {800 + Math.floor(Math.random() * 300)} | 18.7 | 156.8 | -| marked | {900 + Math.floor(Math.random() * 400)} | 15.2 | 45.6 | - -## Lists and Formatting - -### Features Comparison - -1. **Parsing Speed** - - Raw text processing - - AST generation time - - Memory allocation efficiency - -2. **Bundle Size** - - Core library size - - Plugin ecosystem impact - - Tree-shaking effectiveness - -3. **Developer Experience** - - API simplicity - - TypeScript support - - Error handling - -### Pros and Cons - -- ✅ Fast parsing performance -- ✅ Low memory footprint -- ✅ Rust-based reliability -- ❌ Smaller ecosystem -- ❌ Learning curve for Rust integration - -> **Important Note**: Performance benchmarks can vary significantly based on: -> - Hardware specifications -> - Node.js version -> - System load -> - Input document complexity - -## Complex Nested Components - - -
-

Nested Component Example

- Performance: {(Math.random() * 100).toFixed(2)}% -
- -
-

This tests deeply nested JSX parsing with multiple levels:

- -
-
- Parse Time: - {(Math.random() * 50).toFixed(2)}ms -
-
- Memory: - {(Math.random() * 20).toFixed(1)}MB -
-
- - -
-
- -## Multiple Sections for Load Testing - -${Array(5) - .fill( - ` -### Section {index} - -This is section number {index} with various content types: - -- Regular **bold** and *italic* text -- \`Inline code snippets\` -- [External links](https://example.com) - -#### Subsection Code - -\`\`\`json -{ - "benchmark": "section-{index}", - "timestamp": {Date.now()}, - "data": [1, 2, 3, 4, 5] -} -\`\`\` - -
-

JSX content in section {index}

- -
- -> Blockquote in section {index} with **formatting** and \`code\` - -| Item | Value | -|------|-------| -| A{index} | {Math.random()} | -| B{index} | {Math.random()} | -`, - ) - .join("\n\n")} - -## Final Performance Summary - - - - -

- Based on our comprehensive testing, markdown-rs shows significant - performance advantages in parsing speed and memory efficiency. - Current timestamp: {new Date().toISOString()} -

-
- ---- - -*End of benchmark document. This is a comprehensive MDX performance test.* - -`; - -longMdxContent = longMdxContent.repeat(10); - -describe("MDX Parsing Performance Comparison", () => { - bench("markdown-rs parse", () => { - const res = parse(longMdxContent, { - mdx: true, - mdxExpressionParse: true, - mdxEsmParse: true, - }); - console.log(res); - }); - - bench("remark + remark-mdx parse", () => { - remarkProcessor.runSync(remarkProcessor.parse(longMdxContent)); - }); -}); diff --git a/napi/tests/to-html.test.ts b/napi/tests/to-html.test.ts new file mode 100644 index 00000000..49dc9acf --- /dev/null +++ b/napi/tests/to-html.test.ts @@ -0,0 +1,224 @@ +import { describe, expect, it } from "vitest"; +import { toHtml } from "../"; + +describe("toHtml", () => { + it("converts basic markdown to HTML", () => { + const html = toHtml("# Hello world"); + expect(html).toMatchInlineSnapshot(`"

Hello world

"`); + }); + + it("works without options parameter", () => { + const html = toHtml("**bold** and *italic*"); + expect(html).toMatchInlineSnapshot(`"

bold and italic

"`); + }); + + it("handles GFM strikethrough with parse options", () => { + const html = toHtml("~~strikethrough~~", { + parse: { gfm: true } + }); + expect(html).toMatchInlineSnapshot(`"

strikethrough

"`); + }); + + it("handles GFM table with parse options", () => { + const html = toHtml(`| Name | Age | +|------|-----| +| John | 30 | +| Jane | 25 |`, { + parse: { gfm: true } + }); + expect(html).toMatchInlineSnapshot(` + " + + + + + + + + + + + + + + + + +
NameAge
John30
Jane25
" + `); + }); + + it("allows dangerous HTML when enabled", () => { + const html = toHtml('', { + compile: { allowDangerousHtml: true } + }); + expect(html).toMatchInlineSnapshot(`""`); + }); + + it("escapes dangerous HTML by default", () => { + const html = toHtml(''); + expect(html).toMatchInlineSnapshot(`"<script>alert("xss")</script>"`); + }); + + it("allows dangerous protocols when enabled", () => { + const html = toHtml('', { + compile: { allowDangerousProtocol: true } + }); + expect(html).toMatchInlineSnapshot(`"

javascript:alert(1)

"`); + }); + + it("blocks dangerous protocols by default", () => { + const html = toHtml(''); + expect(html).toMatchInlineSnapshot(`"

javascript:alert(1)

"`); + }); + + it("handles GFM footnotes with custom back label", () => { + const html = toHtml(`Here is a footnote[^1]. + +[^1]: This is the footnote.`, { + parse: { gfm: true }, + compile: { gfmFootnoteBackLabel: "Return to text" } + }); + expect(html).toContain('aria-label="Return to text"'); + }); + + it("handles GFM task lists", () => { + const html = toHtml(`- [x] Task 1 +- [ ] Task 2`, { + parse: { gfm: true } + }); + expect(html).toMatchInlineSnapshot(` + "
    +
  • Task 1
  • +
  • Task 2
  • +
" + `); + }); + + it("makes task list checkboxes checkable when enabled", () => { + const html = toHtml(`- [x] Task 1 +- [ ] Task 2`, { + parse: { gfm: true }, + compile: { gfmTaskListItemCheckable: true } + }); + expect(html).toMatchInlineSnapshot(` + "
    +
  • Task 1
  • +
  • Task 2
  • +
" + `); + }); + + it("handles different line endings", () => { + const html = toHtml("> quote", { + compile: { defaultLineEnding: "crlf" } + }); + expect(html).toMatchInlineSnapshot(` + "
+

quote

+
" + `); + }); + + it("handles MDX with parse options", () => { + const html = toHtml("# Hello {name}", { + parse: { mdx: true } + }); + expect(html).toMatchInlineSnapshot(`"

Hello

"`); + }); + + it("handles frontmatter when enabled", () => { + const html = toHtml(`--- +title: Test +--- + +# Content`, { + parse: { frontmatter: true } + }); + expect(html).toMatchInlineSnapshot(`"

Content

"`); + }); + + it("treats frontmatter as content when disabled", () => { + const html = toHtml(`--- +title: Test +--- + +# Content`); + expect(html).toMatchInlineSnapshot(` + "
+

title: Test

+

Content

" + `); + }); + + it("combines parse and compile options", () => { + const html = toHtml(`
+ +~~strikethrough~~ + +
`, { + parse: { gfm: true }, + compile: { allowDangerousHtml: true } + }); + expect(html).toMatchInlineSnapshot(` + "
+

strikethrough

+
" + `); + }); + + it("handles GFM tagfilter", () => { + const html = toHtml('', { + parse: { gfm: true }, + compile: { + allowDangerousHtml: true, + gfmTagfilter: true + } + }); + expect(html).toMatchInlineSnapshot(`"<iframe>test</iframe>"`); + }); + + it("allows iframe without tagfilter", () => { + const html = toHtml('', { + parse: { gfm: true }, + compile: { + allowDangerousHtml: true, + gfmTagfilter: false + } + }); + expect(html).toMatchInlineSnapshot(`""`); + }); + + it("handles custom footnote settings", () => { + const html = toHtml(`Here is a footnote[^1]. + +[^1]: This is the footnote.`, { + parse: { gfm: true }, + compile: { + gfmFootnoteLabel: "Notes", + gfmFootnoteLabelTagName: "h3", + gfmFootnoteLabelAttributes: 'class="footnote-title"', + gfmFootnoteClobberPrefix: "" + } + }); + expect(html).toContain('

Notes

'); + expect(html).toContain('href="#fn-'); // no prefix + }); + + it("handles math text with single dollar disabled", () => { + const html = toHtml("$math$", { + parse: { mathTextSingleDollar: false } + }); + expect(html).toMatchInlineSnapshot(`"

$math$

"`); + }); + + it("handles strikethrough with single tilde disabled", () => { + const html = toHtml("~strikethrough~", { + parse: { + gfm: true, + gfmStrikethroughSingleTilde: false + } + }); + expect(html).toMatchInlineSnapshot(`"

~strikethrough~

"`); + }); +}); \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 38941f46..7c3f2be9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,12 +26,21 @@ importers: emnapi: specifier: ^1.4.3 version: 1.4.3 + mitata: + specifier: ^1.0.34 + version: 1.0.34 remark: specifier: ^15.0.1 version: 15.0.1 + remark-gfm: + specifier: ^4.0.1 + version: 4.0.1 remark-mdx: specifier: ^3.0.1 version: 3.1.0 + tsx: + specifier: ^4.20.3 + version: 4.20.3 vitest: specifier: ^1.5.0 version: 1.6.1 @@ -53,138 +62,288 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.25.5': + resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.21.5': resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} engines: {node: '>=12'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.25.5': + resolution: {integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.21.5': resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} engines: {node: '>=12'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.25.5': + resolution: {integrity: sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.21.5': resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} engines: {node: '>=12'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.25.5': + resolution: {integrity: sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.21.5': resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.25.5': + resolution: {integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.21.5': resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} engines: {node: '>=12'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.25.5': + resolution: {integrity: sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.21.5': resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.25.5': + resolution: {integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.21.5': resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.25.5': + resolution: {integrity: sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.21.5': resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} engines: {node: '>=12'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.25.5': + resolution: {integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.21.5': resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} engines: {node: '>=12'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.25.5': + resolution: {integrity: sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.21.5': resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} engines: {node: '>=12'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.25.5': + resolution: {integrity: sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.21.5': resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} engines: {node: '>=12'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.25.5': + resolution: {integrity: sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.21.5': resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.25.5': + resolution: {integrity: sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.21.5': resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.25.5': + resolution: {integrity: sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.21.5': resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.25.5': + resolution: {integrity: sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.21.5': resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} engines: {node: '>=12'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.25.5': + resolution: {integrity: sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.21.5': resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} engines: {node: '>=12'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.25.5': + resolution: {integrity: sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.5': + resolution: {integrity: sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.21.5': resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.25.5': + resolution: {integrity: sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.5': + resolution: {integrity: sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.21.5': resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.25.5': + resolution: {integrity: sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/sunos-x64@0.21.5': resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} engines: {node: '>=12'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.25.5': + resolution: {integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.21.5': resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.25.5': + resolution: {integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.21.5': resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} engines: {node: '>=12'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.25.5': + resolution: {integrity: sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.21.5': resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} engines: {node: '>=12'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.25.5': + resolution: {integrity: sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@inquirer/checkbox@4.1.8': resolution: {integrity: sha512-d/QAsnwuHX2OPolxvYcgSj7A9DO9H6gVOy2DvBTx+P2LH2iRTo/RSGV3iwCzW024nP9hw98KIuDmdyhZQj1UQg==} engines: {node: '>=18'} @@ -977,6 +1136,15 @@ packages: engines: {node: '>=12'} hasBin: true + esbuild@0.25.5: + resolution: {integrity: sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==} + engines: {node: '>=18'} + hasBin: true + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + estree-util-is-identifier-name@3.0.0: resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} @@ -1012,6 +1180,9 @@ packages: resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} engines: {node: '>=16'} + get-tsconfig@4.10.1: + resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} + human-signals@5.0.0: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} @@ -1070,9 +1241,33 @@ packages: magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + mdast-util-from-markdown@2.0.2: resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + mdast-util-mdx-expression@2.0.1: resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} @@ -1100,6 +1295,27 @@ packages: micromark-core-commonmark@2.0.3: resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + micromark-extension-mdx-expression@3.0.1: resolution: {integrity: sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==} @@ -1185,6 +1401,9 @@ packages: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} + mitata@1.0.34: + resolution: {integrity: sha512-Mc3zrtNBKIMeHSCQ0XqRLo1vbdIx1wvFV9c8NJAiyho6AjNfMY8bVhbS12bwciUdd1t4rj8099CH3N3NFahaUA==} + mlly@1.7.4: resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} @@ -1253,6 +1472,9 @@ packages: react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + remark-mdx@3.1.0: resolution: {integrity: sha512-Ngl/H3YXyBV9RcRNdlYsZujAmhsxwzxpDzpDEhFBVAGthS4GDgnctpDjgFl/ULx5UEDzqtW1cyBSNKqYYrqLBA==} @@ -1265,6 +1487,9 @@ packages: remark@15.0.1: resolution: {integrity: sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==} + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + rollup@4.43.0: resolution: {integrity: sha512-wdN2Kd3Twh8MAEOEJZsuxuLKCsBEo4PVNLK6tQWAn10VhsVewQLzcucMgLolRlhFybGxfclbPeEYBaP6RvUFGg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -1345,6 +1570,11 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsx@4.20.3: + resolution: {integrity: sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==} + engines: {node: '>=18.0.0'} + hasBin: true + typanion@3.14.0: resolution: {integrity: sha512-ZW/lVMRabETuYCd9O9ZvMhAh8GslSqaUjxmK/JLPCh6l73CvLBiuXswj/+7LdnWOgYsQ130FqLzFz5aGT4I3Ug==} @@ -1493,72 +1723,147 @@ snapshots: '@esbuild/aix-ppc64@0.21.5': optional: true + '@esbuild/aix-ppc64@0.25.5': + optional: true + '@esbuild/android-arm64@0.21.5': optional: true + '@esbuild/android-arm64@0.25.5': + optional: true + '@esbuild/android-arm@0.21.5': optional: true + '@esbuild/android-arm@0.25.5': + optional: true + '@esbuild/android-x64@0.21.5': optional: true + '@esbuild/android-x64@0.25.5': + optional: true + '@esbuild/darwin-arm64@0.21.5': optional: true + '@esbuild/darwin-arm64@0.25.5': + optional: true + '@esbuild/darwin-x64@0.21.5': optional: true + '@esbuild/darwin-x64@0.25.5': + optional: true + '@esbuild/freebsd-arm64@0.21.5': optional: true + '@esbuild/freebsd-arm64@0.25.5': + optional: true + '@esbuild/freebsd-x64@0.21.5': optional: true + '@esbuild/freebsd-x64@0.25.5': + optional: true + '@esbuild/linux-arm64@0.21.5': optional: true + '@esbuild/linux-arm64@0.25.5': + optional: true + '@esbuild/linux-arm@0.21.5': optional: true + '@esbuild/linux-arm@0.25.5': + optional: true + '@esbuild/linux-ia32@0.21.5': optional: true + '@esbuild/linux-ia32@0.25.5': + optional: true + '@esbuild/linux-loong64@0.21.5': optional: true + '@esbuild/linux-loong64@0.25.5': + optional: true + '@esbuild/linux-mips64el@0.21.5': optional: true + '@esbuild/linux-mips64el@0.25.5': + optional: true + '@esbuild/linux-ppc64@0.21.5': optional: true + '@esbuild/linux-ppc64@0.25.5': + optional: true + '@esbuild/linux-riscv64@0.21.5': optional: true + '@esbuild/linux-riscv64@0.25.5': + optional: true + '@esbuild/linux-s390x@0.21.5': optional: true + '@esbuild/linux-s390x@0.25.5': + optional: true + '@esbuild/linux-x64@0.21.5': optional: true + '@esbuild/linux-x64@0.25.5': + optional: true + + '@esbuild/netbsd-arm64@0.25.5': + optional: true + '@esbuild/netbsd-x64@0.21.5': optional: true + '@esbuild/netbsd-x64@0.25.5': + optional: true + + '@esbuild/openbsd-arm64@0.25.5': + optional: true + '@esbuild/openbsd-x64@0.21.5': optional: true + '@esbuild/openbsd-x64@0.25.5': + optional: true + '@esbuild/sunos-x64@0.21.5': optional: true + '@esbuild/sunos-x64@0.25.5': + optional: true + '@esbuild/win32-arm64@0.21.5': optional: true + '@esbuild/win32-arm64@0.25.5': + optional: true + '@esbuild/win32-ia32@0.21.5': optional: true + '@esbuild/win32-ia32@0.25.5': + optional: true + '@esbuild/win32-x64@0.21.5': optional: true + '@esbuild/win32-x64@0.25.5': + optional: true + '@inquirer/checkbox@4.1.8': dependencies: '@inquirer/core': 10.1.13 @@ -2209,6 +2514,36 @@ snapshots: '@esbuild/win32-ia32': 0.21.5 '@esbuild/win32-x64': 0.21.5 + esbuild@0.25.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.5 + '@esbuild/android-arm': 0.25.5 + '@esbuild/android-arm64': 0.25.5 + '@esbuild/android-x64': 0.25.5 + '@esbuild/darwin-arm64': 0.25.5 + '@esbuild/darwin-x64': 0.25.5 + '@esbuild/freebsd-arm64': 0.25.5 + '@esbuild/freebsd-x64': 0.25.5 + '@esbuild/linux-arm': 0.25.5 + '@esbuild/linux-arm64': 0.25.5 + '@esbuild/linux-ia32': 0.25.5 + '@esbuild/linux-loong64': 0.25.5 + '@esbuild/linux-mips64el': 0.25.5 + '@esbuild/linux-ppc64': 0.25.5 + '@esbuild/linux-riscv64': 0.25.5 + '@esbuild/linux-s390x': 0.25.5 + '@esbuild/linux-x64': 0.25.5 + '@esbuild/netbsd-arm64': 0.25.5 + '@esbuild/netbsd-x64': 0.25.5 + '@esbuild/openbsd-arm64': 0.25.5 + '@esbuild/openbsd-x64': 0.25.5 + '@esbuild/sunos-x64': 0.25.5 + '@esbuild/win32-arm64': 0.25.5 + '@esbuild/win32-ia32': 0.25.5 + '@esbuild/win32-x64': 0.25.5 + + escape-string-regexp@5.0.0: {} + estree-util-is-identifier-name@3.0.0: {} estree-util-visit@2.0.0: @@ -2249,6 +2584,10 @@ snapshots: get-stream@8.0.1: {} + get-tsconfig@4.10.1: + dependencies: + resolve-pkg-maps: 1.0.0 + human-signals@5.0.0: {} iconv-lite@0.4.24: @@ -2297,6 +2636,15 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 + markdown-table@3.0.4: {} + + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.0 + unist-util-visit-parents: 6.0.1 + mdast-util-from-markdown@2.0.2: dependencies: '@types/mdast': 4.0.4 @@ -2314,6 +2662,63 @@ snapshots: transitivePeerDependencies: - supports-color + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.2 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + mdast-util-mdx-expression@2.0.1: dependencies: '@types/estree-jsx': 1.0.5 @@ -2405,6 +2810,64 @@ snapshots: micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + micromark-extension-mdx-expression@3.0.1: dependencies: '@types/estree': 1.0.8 @@ -2594,6 +3057,8 @@ snapshots: mimic-fn@4.0.0: {} + mitata@1.0.34: {} + mlly@1.7.4: dependencies: acorn: 8.15.0 @@ -2663,6 +3128,17 @@ snapshots: react-is@18.3.1: {} + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + remark-mdx@3.1.0: dependencies: mdast-util-mdx: 3.0.0 @@ -2694,6 +3170,8 @@ snapshots: transitivePeerDependencies: - supports-color + resolve-pkg-maps@1.0.0: {} + rollup@4.43.0: dependencies: '@types/estree': 1.0.7 @@ -2777,6 +3255,13 @@ snapshots: tslib@2.8.1: {} + tsx@4.20.3: + dependencies: + esbuild: 0.25.5 + get-tsconfig: 4.10.1 + optionalDependencies: + fsevents: 2.3.3 + typanion@3.14.0: {} type-detect@4.1.0: {} From 871037f974acc1086a6a12b4f2158d781021c90a Mon Sep 17 00:00:00 2001 From: remorses Date: Fri, 20 Jun 2025 11:07:48 +0200 Subject: [PATCH 53/61] better benchmark, use the zod markdown long doc --- napi/package.json | 1 + napi/tests/benchmark.ts | 54 +++++++++++++++++----- pnpm-lock.yaml | 99 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+), 12 deletions(-) diff --git a/napi/package.json b/napi/package.json index 9cf2c497..3d77958c 100644 --- a/napi/package.json +++ b/napi/package.json @@ -49,6 +49,7 @@ "mitata": "^1.0.34", "remark": "^15.0.1", "remark-gfm": "^4.0.1", + "remark-html": "^16.0.1", "remark-mdx": "^3.0.1", "tsx": "^4.20.3", "vitest": "^1.5.0" diff --git a/napi/tests/benchmark.ts b/napi/tests/benchmark.ts index 55ceffa1..dcfbe424 100644 --- a/napi/tests/benchmark.ts +++ b/napi/tests/benchmark.ts @@ -1,33 +1,63 @@ import { run, bench, boxplot, summary } from "mitata"; -import { parse } from "../"; +import { parse, toHtml } from "../"; import { remark } from "remark"; import remarkMdx from "remark-mdx"; import remarkGfm from "remark-gfm"; +import remarkHtml from "remark-html"; - -const remarkProcessor = remark().use(remarkMdx).use(remarkGfm); +const remarkProcessor = remark().use(remarkMdx).use(remarkGfm).use(remarkHtml); async function main() { - const longMdxContent = await fetch( + let longMdxContent = await fetch( "https://raw.githubusercontent.com/colinhacks/zod/0a49fa39348b7c72b19ddedc3b0f879bd395304b/packages/docs/content/packages/v3.mdx", ).then((x) => x.text()); - boxplot(async () => { - summary(() => { - bench("markdown-rs parse", () => { - const res = parse(longMdxContent, { + summary(() => { + bench("markdown-rs parse", () => { + const res = parse(longMdxContent, { + mdx: true, + mdxExpressionParse: true, + mdxEsmParse: true, + gfm: true, + }); + }); + + bench("remark parse", () => { + remarkProcessor.processSync(longMdxContent); + }); + }); + summary(() => { + bench("markdown-rs parse without parsing js", () => { + const res = parse(longMdxContent, { + mdx: true, + mdxExpressionParse: false, + mdxEsmParse: false, + gfm: true, + }); + }); + + bench("remark parse", () => { + remarkProcessor.processSync(longMdxContent); + }); + }); + summary(() => { + bench("markdown-rs html", () => { + const res = toHtml(longMdxContent, { + parse: { mdx: true, mdxExpressionParse: true, mdxEsmParse: true, gfm: true, - }); + }, }); + }); - bench("remark + remark-mdx parse", () => { - remarkProcessor.processSync(longMdxContent); - }); + bench("remark html", () => { + const file = remarkProcessor.processSync(longMdxContent); + const res = String(file); }); }); + await run(); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7c3f2be9..5c534d1f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,6 +35,9 @@ importers: remark-gfm: specifier: ^4.0.1 version: 4.0.1 + remark-html: + specifier: ^16.0.1 + version: 16.0.1 remark-mdx: specifier: ^3.0.1 version: 3.1.0 @@ -981,6 +984,9 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + '@vitest/expect@1.6.1': resolution: {integrity: sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==} @@ -1086,6 +1092,9 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} @@ -1183,6 +1192,18 @@ packages: get-tsconfig@4.10.1: resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} + hast-util-sanitize@5.0.2: + resolution: {integrity: sha512-3yTWghByc50aGS7JlGhk61SPenfE/p1oaFeNwkOOyrscaOkMGrcW9+Cy/QAIOBpZxP1yqDIzFMR0+Np0i0+usg==} + + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + human-signals@5.0.0: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} @@ -1283,6 +1304,9 @@ packages: mdast-util-phrasing@4.1.0: resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + mdast-util-to-hast@13.2.0: + resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==} + mdast-util-to-markdown@2.1.2: resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} @@ -1469,12 +1493,18 @@ packages: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + property-information@7.1.0: + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} remark-gfm@4.0.1: resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + remark-html@16.0.1: + resolution: {integrity: sha512-B9JqA5i0qZe0Nsf49q3OXyGvyXuZFDzAP2iOFLEumymuYJITVpiH1IgsTEwTpdptDmZlMDMWeDmSawdaJIGCXQ==} + remark-mdx@3.1.0: resolution: {integrity: sha512-Ngl/H3YXyBV9RcRNdlYsZujAmhsxwzxpDzpDEhFBVAGthS4GDgnctpDjgFl/ULx5UEDzqtW1cyBSNKqYYrqLBA==} @@ -1522,6 +1552,9 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -1564,6 +1597,9 @@ packages: toml@3.0.0: resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} @@ -1598,6 +1634,9 @@ packages: unist-util-position-from-estree@2.0.0: resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + unist-util-stringify-position@4.0.0: resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} @@ -2355,6 +2394,8 @@ snapshots: '@types/unist@3.0.3': {} + '@ungap/structured-clone@1.3.0': {} + '@vitest/expect@1.6.1': dependencies: '@vitest/spy': 1.6.1 @@ -2456,6 +2497,8 @@ snapshots: colorette@2.0.20: {} + comma-separated-tokens@2.0.3: {} + confbox@0.1.8: {} cross-spawn@7.0.6: @@ -2588,6 +2631,32 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + hast-util-sanitize@5.0.2: + dependencies: + '@types/hast': 3.0.4 + '@ungap/structured-clone': 1.3.0 + unist-util-position: 5.0.0 + + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + html-void-elements@3.0.0: {} + human-signals@5.0.0: {} iconv-lite@0.4.24: @@ -2773,6 +2842,18 @@ snapshots: '@types/mdast': 4.0.4 unist-util-is: 6.0.0 + mdast-util-to-hast@13.2.0: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + mdast-util-to-markdown@2.1.2: dependencies: '@types/mdast': 4.0.4 @@ -3126,6 +3207,8 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 + property-information@7.1.0: {} + react-is@18.3.1: {} remark-gfm@4.0.1: @@ -3139,6 +3222,14 @@ snapshots: transitivePeerDependencies: - supports-color + remark-html@16.0.1: + dependencies: + '@types/mdast': 4.0.4 + hast-util-sanitize: 5.0.2 + hast-util-to-html: 9.0.5 + mdast-util-to-hast: 13.2.0 + unified: 11.0.5 + remark-mdx@3.1.0: dependencies: mdast-util-mdx: 3.0.0 @@ -3214,6 +3305,8 @@ snapshots: source-map-js@1.2.1: {} + space-separated-tokens@2.0.2: {} + stackback@0.0.2: {} std-env@3.9.0: {} @@ -3251,6 +3344,8 @@ snapshots: toml@3.0.0: {} + trim-lines@3.0.1: {} + trough@2.2.0: {} tslib@2.8.1: {} @@ -3288,6 +3383,10 @@ snapshots: dependencies: '@types/unist': 3.0.3 + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position@4.0.0: dependencies: '@types/unist': 3.0.3 From af708cae6f7dba0e101ce0bb4f8a74a2079f01bd Mon Sep 17 00:00:00 2001 From: remorses Date: Fri, 20 Jun 2025 11:08:08 +0200 Subject: [PATCH 54/61] Update package.json --- napi/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/napi/package.json b/napi/package.json index 3d77958c..5e865305 100644 --- a/napi/package.json +++ b/napi/package.json @@ -1,7 +1,7 @@ { "name": "@xmorse/markdown-rs", "description": "Fast markdown and mdx parser written in Rust", - "version": "0.0.4", + "version": "0.0.5", "main": "index.js", "browser": "browser.js", "scripts": { From 758f9447d309ab987b71ae4c21b5a975a64c106a Mon Sep 17 00:00:00 2001 From: remorses Date: Fri, 20 Jun 2025 11:12:45 +0200 Subject: [PATCH 55/61] fix version check --- .github/workflows/release-napi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-napi.yml b/.github/workflows/release-napi.yml index cdbe1ff0..7970ac96 100644 --- a/.github/workflows/release-napi.yml +++ b/.github/workflows/release-napi.yml @@ -33,7 +33,7 @@ jobs: with: static-checking: localIsNew file-url: https://unpkg.com/@xmorse/markdown-rs@latest/package.json - file-name: package.json + file-name: napi/package.json - name: Set version name if: steps.version.outputs.changed == 'true' From e5a6bb6c181c4bda91fb80cb54971786a3ec041e Mon Sep 17 00:00:00 2001 From: remorses Date: Fri, 20 Jun 2025 12:56:29 +0200 Subject: [PATCH 56/61] Update release-napi.yml --- .github/workflows/release-napi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-napi.yml b/.github/workflows/release-napi.yml index 7970ac96..52bdcbb9 100644 --- a/.github/workflows/release-napi.yml +++ b/.github/workflows/release-napi.yml @@ -6,7 +6,7 @@ on: workflow_dispatch: push: paths: - - package.json + - napi/package.json # make new release on version change of napi package # TODO enable the release napi workflow only on main # branches: # - main From b72e973202a9e69ee9532d87f9824216eb7d7556 Mon Sep 17 00:00:00 2001 From: remorses Date: Fri, 20 Jun 2025 12:57:04 +0200 Subject: [PATCH 57/61] Update package.json --- napi/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/napi/package.json b/napi/package.json index 5e865305..df6f3ff7 100644 --- a/napi/package.json +++ b/napi/package.json @@ -1,6 +1,6 @@ { "name": "@xmorse/markdown-rs", - "description": "Fast markdown and mdx parser written in Rust", + "description": "Fast markdown and mdx parser written in Rust. Supports WASM", "version": "0.0.5", "main": "index.js", "browser": "browser.js", From 53000fe946e5b131035ea659d5e43be6ce2cdc23 Mon Sep 17 00:00:00 2001 From: remorses Date: Fri, 20 Jun 2025 13:16:57 +0200 Subject: [PATCH 58/61] add missing generated files --- napi/markdown-rs.wasi-browser.js | 58 +++++++++++++++++++++ napi/markdown-rs.wasi.cjs | 89 ++++++++++++++++++++++++++++++++ napi/wasi-worker-browser.mjs | 32 ++++++++++++ napi/wasi-worker.mjs | 63 ++++++++++++++++++++++ 4 files changed, 242 insertions(+) create mode 100644 napi/markdown-rs.wasi-browser.js create mode 100644 napi/markdown-rs.wasi.cjs create mode 100644 napi/wasi-worker-browser.mjs create mode 100644 napi/wasi-worker.mjs diff --git a/napi/markdown-rs.wasi-browser.js b/napi/markdown-rs.wasi-browser.js new file mode 100644 index 00000000..a6d48ef2 --- /dev/null +++ b/napi/markdown-rs.wasi-browser.js @@ -0,0 +1,58 @@ +import { + createOnMessage as __wasmCreateOnMessageForFsProxy, + getDefaultContext as __emnapiGetDefaultContext, + instantiateNapiModuleSync as __emnapiInstantiateNapiModuleSync, + WASI as __WASI, +} from '@napi-rs/wasm-runtime' + + +const __wasi = new __WASI({ + version: 'preview1', +}) + +const __wasmUrl = new URL('./markdown-rs.wasm32-wasi.wasm', import.meta.url).href +const __emnapiContext = __emnapiGetDefaultContext() + +const __sharedMemory = new WebAssembly.Memory({ + initial: 4000, + maximum: 65536, + shared: true, +}) + +const __wasmFile = await fetch(__wasmUrl).then((res) => res.arrayBuffer()) + +const { + instance: __napiInstance, + module: __wasiModule, + napiModule: __napiModule, +} = __emnapiInstantiateNapiModuleSync(__wasmFile, { + context: __emnapiContext, + asyncWorkPoolSize: 4, + wasi: __wasi, + onCreateWorker() { + const worker = new Worker(new URL('./wasi-worker-browser.mjs', import.meta.url), { + type: 'module', + }) + + return worker + }, + overwriteImports(importObject) { + importObject.env = { + ...importObject.env, + ...importObject.napi, + ...importObject.emnapi, + memory: __sharedMemory, + } + return importObject + }, + beforeInit({ instance }) { + for (const name of Object.keys(instance.exports)) { + if (name.startsWith('__napi_register__')) { + instance.exports[name]() + } + } + }, +}) +export default __napiModule.exports +export const parse = __napiModule.exports.parse +export const toHtml = __napiModule.exports.toHtml diff --git a/napi/markdown-rs.wasi.cjs b/napi/markdown-rs.wasi.cjs new file mode 100644 index 00000000..efa5e76f --- /dev/null +++ b/napi/markdown-rs.wasi.cjs @@ -0,0 +1,89 @@ +/* eslint-disable */ +/* prettier-ignore */ + +/* auto-generated by NAPI-RS */ + +const __nodeFs = require('node:fs') +const __nodePath = require('node:path') +const { WASI: __nodeWASI } = require('node:wasi') +const { Worker } = require('node:worker_threads') + +const { + createOnMessage: __wasmCreateOnMessageForFsProxy, + getDefaultContext: __emnapiGetDefaultContext, + instantiateNapiModuleSync: __emnapiInstantiateNapiModuleSync, +} = require('@napi-rs/wasm-runtime') + +const __rootDir = __nodePath.parse(process.cwd()).root + +const __wasi = new __nodeWASI({ + version: 'preview1', + env: process.env, + preopens: { + [__rootDir]: __rootDir, + } +}) + +const __emnapiContext = __emnapiGetDefaultContext() + +const __sharedMemory = new WebAssembly.Memory({ + initial: 4000, + maximum: 65536, + shared: true, +}) + +let __wasmFilePath = __nodePath.join(__dirname, 'markdown-rs.wasm32-wasi.wasm') +const __wasmDebugFilePath = __nodePath.join(__dirname, 'markdown-rs.wasm32-wasi.debug.wasm') + +if (__nodeFs.existsSync(__wasmDebugFilePath)) { + __wasmFilePath = __wasmDebugFilePath +} else if (!__nodeFs.existsSync(__wasmFilePath)) { + try { + __wasmFilePath = __nodePath.resolve('@xmorse/markdown-rs-binding-wasm32-wasi') + } catch { + throw new Error('Cannot find markdown-rs.wasm32-wasi.wasm file, and @xmorse/markdown-rs-binding-wasm32-wasi package is not installed.') + } +} + +const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule } = __emnapiInstantiateNapiModuleSync(__nodeFs.readFileSync(__wasmFilePath), { + context: __emnapiContext, + asyncWorkPoolSize: (function() { + const threadsSizeFromEnv = Number(process.env.NAPI_RS_ASYNC_WORK_POOL_SIZE ?? process.env.UV_THREADPOOL_SIZE) + // NaN > 0 is false + if (threadsSizeFromEnv > 0) { + return threadsSizeFromEnv + } else { + return 4 + } + })(), + reuseWorker: true, + wasi: __wasi, + onCreateWorker() { + const worker = new Worker(__nodePath.join(__dirname, 'wasi-worker.mjs'), { + env: process.env, + }) + worker.onmessage = ({ data }) => { + __wasmCreateOnMessageForFsProxy(__nodeFs)(data) + } + return worker + }, + overwriteImports(importObject) { + importObject.env = { + ...importObject.env, + ...importObject.napi, + ...importObject.emnapi, + memory: __sharedMemory, + } + return importObject + }, + beforeInit({ instance }) { + for (const name of Object.keys(instance.exports)) { + if (name.startsWith('__napi_register__')) { + instance.exports[name]() + } + } + }, +}) +module.exports = __napiModule.exports +module.exports.parse = __napiModule.exports.parse +module.exports.toHtml = __napiModule.exports.toHtml diff --git a/napi/wasi-worker-browser.mjs b/napi/wasi-worker-browser.mjs new file mode 100644 index 00000000..8b1b1722 --- /dev/null +++ b/napi/wasi-worker-browser.mjs @@ -0,0 +1,32 @@ +import { instantiateNapiModuleSync, MessageHandler, WASI } from '@napi-rs/wasm-runtime' + +const handler = new MessageHandler({ + onLoad({ wasmModule, wasmMemory }) { + const wasi = new WASI({ + print: function () { + // eslint-disable-next-line no-console + console.log.apply(console, arguments) + }, + printErr: function() { + // eslint-disable-next-line no-console + console.error.apply(console, arguments) + }, + }) + return instantiateNapiModuleSync(wasmModule, { + childThread: true, + wasi, + overwriteImports(importObject) { + importObject.env = { + ...importObject.env, + ...importObject.napi, + ...importObject.emnapi, + memory: wasmMemory, + } + }, + }) + }, +}) + +globalThis.onmessage = function (e) { + handler.handle(e) +} diff --git a/napi/wasi-worker.mjs b/napi/wasi-worker.mjs new file mode 100644 index 00000000..84b448fc --- /dev/null +++ b/napi/wasi-worker.mjs @@ -0,0 +1,63 @@ +import fs from "node:fs"; +import { createRequire } from "node:module"; +import { parse } from "node:path"; +import { WASI } from "node:wasi"; +import { parentPort, Worker } from "node:worker_threads"; + +const require = createRequire(import.meta.url); + +const { instantiateNapiModuleSync, MessageHandler, getDefaultContext } = require("@napi-rs/wasm-runtime"); + +if (parentPort) { + parentPort.on("message", (data) => { + globalThis.onmessage({ data }); + }); +} + +Object.assign(globalThis, { + self: globalThis, + require, + Worker, + importScripts: function (f) { + ;(0, eval)(fs.readFileSync(f, "utf8") + "//# sourceURL=" + f); + }, + postMessage: function (msg) { + if (parentPort) { + parentPort.postMessage(msg); + } + }, +}); + +const emnapiContext = getDefaultContext(); + +const __rootDir = parse(process.cwd()).root; + +const handler = new MessageHandler({ + onLoad({ wasmModule, wasmMemory }) { + const wasi = new WASI({ + version: 'preview1', + env: process.env, + preopens: { + [__rootDir]: __rootDir, + }, + }); + + return instantiateNapiModuleSync(wasmModule, { + childThread: true, + wasi, + context: emnapiContext, + overwriteImports(importObject) { + importObject.env = { + ...importObject.env, + ...importObject.napi, + ...importObject.emnapi, + memory: wasmMemory + }; + }, + }); + }, +}); + +globalThis.onmessage = function (e) { + handler.handle(e); +}; From 61aeda760d851eae919c2d9c8ef5c487113ccc95 Mon Sep 17 00:00:00 2001 From: remorses Date: Fri, 20 Jun 2025 13:18:05 +0200 Subject: [PATCH 59/61] update generated files --- napi/index.js | 84 +++++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/napi/index.js b/napi/index.js index 57eff852..acd1ba3c 100644 --- a/napi/index.js +++ b/napi/index.js @@ -73,24 +73,24 @@ function requireNative() { } else if (process.platform === 'android') { if (process.arch === 'arm64') { try { - return require('./index.android-arm64.node') + return require('./markdown-rs.android-arm64.node') } catch (e) { loadErrors.push(e) } try { - return require('root-android-arm64') + return require('@xmorse/markdown-rs-binding-android-arm64') } catch (e) { loadErrors.push(e) } } else if (process.arch === 'arm') { try { - return require('./index.android-arm-eabi.node') + return require('./markdown-rs.android-arm-eabi.node') } catch (e) { loadErrors.push(e) } try { - return require('root-android-arm-eabi') + return require('@xmorse/markdown-rs-binding-android-arm-eabi') } catch (e) { loadErrors.push(e) } @@ -101,36 +101,36 @@ function requireNative() { } else if (process.platform === 'win32') { if (process.arch === 'x64') { try { - return require('./index.win32-x64-msvc.node') + return require('./markdown-rs.win32-x64-msvc.node') } catch (e) { loadErrors.push(e) } try { - return require('root-win32-x64-msvc') + return require('@xmorse/markdown-rs-binding-win32-x64-msvc') } catch (e) { loadErrors.push(e) } } else if (process.arch === 'ia32') { try { - return require('./index.win32-ia32-msvc.node') + return require('./markdown-rs.win32-ia32-msvc.node') } catch (e) { loadErrors.push(e) } try { - return require('root-win32-ia32-msvc') + return require('@xmorse/markdown-rs-binding-win32-ia32-msvc') } catch (e) { loadErrors.push(e) } } else if (process.arch === 'arm64') { try { - return require('./index.win32-arm64-msvc.node') + return require('./markdown-rs.win32-arm64-msvc.node') } catch (e) { loadErrors.push(e) } try { - return require('root-win32-arm64-msvc') + return require('@xmorse/markdown-rs-binding-win32-arm64-msvc') } catch (e) { loadErrors.push(e) } @@ -140,36 +140,36 @@ function requireNative() { } } else if (process.platform === 'darwin') { try { - return require('./index.darwin-universal.node') + return require('./markdown-rs.darwin-universal.node') } catch (e) { loadErrors.push(e) } try { - return require('root-darwin-universal') + return require('@xmorse/markdown-rs-binding-darwin-universal') } catch (e) { loadErrors.push(e) } if (process.arch === 'x64') { try { - return require('./index.darwin-x64.node') + return require('./markdown-rs.darwin-x64.node') } catch (e) { loadErrors.push(e) } try { - return require('root-darwin-x64') + return require('@xmorse/markdown-rs-binding-darwin-x64') } catch (e) { loadErrors.push(e) } } else if (process.arch === 'arm64') { try { - return require('./index.darwin-arm64.node') + return require('./markdown-rs.darwin-arm64.node') } catch (e) { loadErrors.push(e) } try { - return require('root-darwin-arm64') + return require('@xmorse/markdown-rs-binding-darwin-arm64') } catch (e) { loadErrors.push(e) } @@ -180,24 +180,24 @@ function requireNative() { } else if (process.platform === 'freebsd') { if (process.arch === 'x64') { try { - return require('./index.freebsd-x64.node') + return require('./markdown-rs.freebsd-x64.node') } catch (e) { loadErrors.push(e) } try { - return require('root-freebsd-x64') + return require('@xmorse/markdown-rs-binding-freebsd-x64') } catch (e) { loadErrors.push(e) } } else if (process.arch === 'arm64') { try { - return require('./index.freebsd-arm64.node') + return require('./markdown-rs.freebsd-arm64.node') } catch (e) { loadErrors.push(e) } try { - return require('root-freebsd-arm64') + return require('@xmorse/markdown-rs-binding-freebsd-arm64') } catch (e) { loadErrors.push(e) } @@ -209,24 +209,24 @@ function requireNative() { if (process.arch === 'x64') { if (isMusl()) { try { - return require('./index.linux-x64-musl.node') + return require('./markdown-rs.linux-x64-musl.node') } catch (e) { loadErrors.push(e) } try { - return require('root-linux-x64-musl') + return require('@xmorse/markdown-rs-binding-linux-x64-musl') } catch (e) { loadErrors.push(e) } } else { try { - return require('./index.linux-x64-gnu.node') + return require('./markdown-rs.linux-x64-gnu.node') } catch (e) { loadErrors.push(e) } try { - return require('root-linux-x64-gnu') + return require('@xmorse/markdown-rs-binding-linux-x64-gnu') } catch (e) { loadErrors.push(e) } @@ -235,24 +235,24 @@ function requireNative() { } else if (process.arch === 'arm64') { if (isMusl()) { try { - return require('./index.linux-arm64-musl.node') + return require('./markdown-rs.linux-arm64-musl.node') } catch (e) { loadErrors.push(e) } try { - return require('root-linux-arm64-musl') + return require('@xmorse/markdown-rs-binding-linux-arm64-musl') } catch (e) { loadErrors.push(e) } } else { try { - return require('./index.linux-arm64-gnu.node') + return require('./markdown-rs.linux-arm64-gnu.node') } catch (e) { loadErrors.push(e) } try { - return require('root-linux-arm64-gnu') + return require('@xmorse/markdown-rs-binding-linux-arm64-gnu') } catch (e) { loadErrors.push(e) } @@ -261,24 +261,24 @@ function requireNative() { } else if (process.arch === 'arm') { if (isMusl()) { try { - return require('./index.linux-arm-musleabihf.node') + return require('./markdown-rs.linux-arm-musleabihf.node') } catch (e) { loadErrors.push(e) } try { - return require('root-linux-arm-musleabihf') + return require('@xmorse/markdown-rs-binding-linux-arm-musleabihf') } catch (e) { loadErrors.push(e) } } else { try { - return require('./index.linux-arm-gnueabihf.node') + return require('./markdown-rs.linux-arm-gnueabihf.node') } catch (e) { loadErrors.push(e) } try { - return require('root-linux-arm-gnueabihf') + return require('@xmorse/markdown-rs-binding-linux-arm-gnueabihf') } catch (e) { loadErrors.push(e) } @@ -287,24 +287,24 @@ function requireNative() { } else if (process.arch === 'riscv64') { if (isMusl()) { try { - return require('./index.linux-riscv64-musl.node') + return require('./markdown-rs.linux-riscv64-musl.node') } catch (e) { loadErrors.push(e) } try { - return require('root-linux-riscv64-musl') + return require('@xmorse/markdown-rs-binding-linux-riscv64-musl') } catch (e) { loadErrors.push(e) } } else { try { - return require('./index.linux-riscv64-gnu.node') + return require('./markdown-rs.linux-riscv64-gnu.node') } catch (e) { loadErrors.push(e) } try { - return require('root-linux-riscv64-gnu') + return require('@xmorse/markdown-rs-binding-linux-riscv64-gnu') } catch (e) { loadErrors.push(e) } @@ -312,24 +312,24 @@ function requireNative() { } } else if (process.arch === 'ppc64') { try { - return require('./index.linux-ppc64-gnu.node') + return require('./markdown-rs.linux-ppc64-gnu.node') } catch (e) { loadErrors.push(e) } try { - return require('root-linux-ppc64-gnu') + return require('@xmorse/markdown-rs-binding-linux-ppc64-gnu') } catch (e) { loadErrors.push(e) } } else if (process.arch === 's390x') { try { - return require('./index.linux-s390x-gnu.node') + return require('./markdown-rs.linux-s390x-gnu.node') } catch (e) { loadErrors.push(e) } try { - return require('root-linux-s390x-gnu') + return require('@xmorse/markdown-rs-binding-linux-s390x-gnu') } catch (e) { loadErrors.push(e) } @@ -346,7 +346,7 @@ nativeBinding = requireNative() if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) { try { - nativeBinding = require('./index.wasi.cjs') + nativeBinding = require('./markdown-rs.wasi.cjs') } catch (err) { if (process.env.NAPI_RS_FORCE_WASI) { loadErrors.push(err) @@ -354,7 +354,7 @@ if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) { } if (!nativeBinding) { try { - nativeBinding = require('root-wasm32-wasi') + nativeBinding = require('@xmorse/markdown-rs-binding-wasm32-wasi') } catch (err) { if (process.env.NAPI_RS_FORCE_WASI) { loadErrors.push(err) From cad5c32ebc689277ca2ebd4720aaeeb4f78d2845 Mon Sep 17 00:00:00 2001 From: remorses Date: Fri, 20 Jun 2025 13:18:19 +0200 Subject: [PATCH 60/61] scripts in root are wrong --- package.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/package.json b/package.json index 301705f0..6d2347a1 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,5 @@ { "name": "root", - "scripts": { - "build:debug": "pnpm napi build --platform --manifest-path napi/Cargo.toml", - "build": "pnpm run build:debug --release" - }, "dependencies": { "@napi-rs/cli": "3.0.0-alpha.89" }, From 229f7dfd25d5a74022ecdb7f16b9bfb12cc37860 Mon Sep 17 00:00:00 2001 From: remorses Date: Sat, 21 Jun 2025 10:30:39 +0200 Subject: [PATCH 61/61] fix artifacts step in ci --- .github/workflows/release-napi.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-napi.yml b/.github/workflows/release-napi.yml index 52bdcbb9..a0113ccb 100644 --- a/.github/workflows/release-napi.yml +++ b/.github/workflows/release-napi.yml @@ -168,7 +168,8 @@ jobs: - run: pnpm napi create-npm-dirs --package-json-path napi/package.json - - run: pnpm napi artifacts --package-json-path napi/package.json --npm-dir npm --build-output-dir napi + - run: pnpm napi artifacts --package-json-path package.json --npm-dir ../npm --build-output-dir . + working-directory: napi - name: Publish npm packages as latest env: