From 2334f3aae9122ded0933a396c0862898cc2b9b2e Mon Sep 17 00:00:00 2001
From: mintaka
Date: Sat, 22 Aug 2026 00:17:42 -0400
Subject: [PATCH] feat!: adopt react-markdown-10 API on Solid 2, tested and
built under bun
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Replaces the Solid-1 upstream renderer with the react-markdown-10 API
(upstream PR #44 + #45), re-ported to Solid 2, and ships the bun test
harness + bun build that the fork's bun + biome toolchain needs.
## Source
- `src/index.tsx` — the react-markdown-10 renderer (`Markdown`,
`MarkdownAsync`, `MarkdownResource`, `defaultUrlTransform`) built on
`hast-util-to-jsx-runtime`, re-ported to Solid 2 (`@solidjs/web`,
`createStore`/`reconcile`, owned-write signals).
- `src/jsx-runtime.ts` — fork-local JSX runtime for
`hast-util-to-jsx-runtime` over Solid-2 primitives, replacing the
Solid-1-bound `solid-jsx` dependency.
- `src/types.ts` — public option/component types over `@solidjs/web` `JSX`.
- Retires the Solid-1 renderer: `renderer.tsx`, `rehype-filter.ts`,
`utils.ts`, `utils.test.ts`.
## Build (bun)
`build.ts` builds `dist/` with `babel-preset-solid@2` (the Solid compiler)
as the one transform, in two output modes:
- Compiled (`index.js` dom/prod, `dev.js` dom/dev, `server.js` ssr) — Solid
compiles the JSX to `@solidjs/web` runtime calls, then `bun build` bundles
the now JSX-free modules. `bun build` never sees JSX.
- Source (`index.jsx` + a sibling `jsx-runtime.js`) — babel strips types but
leaves the JSX untransformed, written directly, so the `solid` export
condition ships raw JSX for a consuming app's own Solid compiler (matching
its exact `solid-js` version and generate settings). This variant is not
routed through `bun build`, whose own automatic JSX-runtime transform would
emit a `@solidjs/web/jsx-dev-runtime` import that subpath does not provide.
- `index.d.ts` via `tsc --project tsconfig.build.json`.
- `scripts/smoke-dist.ts` guards the published artifact: imports each compiled
entry and asserts the public API resolves, and compiles the `.jsx` source
entry the way a consumer would, asserting it targets `@solidjs/web` and never
a removed subpath. Chained into `build` and run in CI + before publish, so a
dead-on-arrival bundle fails the gate (nothing else imports `dist`).
- Runtime deps are declared under `dependencies` (externalized in dist);
peer deps under `peerDependencies`; build/harness tooling under
`devDependencies`.
## Test harness (bun)
`bun test` has no Vite pipeline and no Solid JSX transform, so the Solid-2
suite needs a harness:
- `test/setup.ts` — a `Bun.plugin` preload that runs `babel-preset-solid`
over `.tsx` sources (`SOLID_GENERATE` picks `dom` vs `ssr`) and registers
happy-dom globals for the client leg only.
- `bunfig.toml` — wires the preload into `bun test`.
- Two legs mirror the retired vitest `--mode ssr` split:
`test:client` (happy-dom, `--conditions=browser --conditions=development`)
and `test:ssr` (node env, `--conditions=development` for `devlop`
assertion messages). `bun run test` runs both.
- `test/client.test.tsx` (11) + `test/server.test.tsx` (20) converted from
vitest to `bun:test`; `@solidjs/testing-library` bumped to `1.0.0-beta.2`
(the Solid-2 line — imports from `@solidjs/web`, drops the removed
`onError`, which bun's strict ESM rejects where vitest silently tolerated).
## Packaging
- `package.json` — Solid-2 peers (`solid-js`, `@solidjs/web` `^2.0.0-rc.0`),
`3.0.0-rc.0`, runtime `dependencies` + bun harness/build devDeps, two-leg
test scripts, `bun run build.ts` build.
- `biome.json` — disables the React-specific `noChildrenProp` rule
(`children` as a prop is this package's public API).
- `.github/workflows/ci.yml` + `publish.yml` — run `bun run test` (both
legs) + `bun run build` (which self-verifies via the dist smoke check);
`publish.yml` converted pnpm -> bun, tag-driven, dist-tag aware.
Spec-impact: none. Refs RIG-2187, RIG-2358.
Co-authored-by: Matt Wilkinson
---
.github/workflows/ci.yml | 2 +-
.github/workflows/publish.yml | 37 ++
README.md | 220 +++++++++-
biome.json | 5 +-
build.ts | 149 +++++++
bun.lock | 427 +++++++++-----------
bunfig.toml | 2 +
package.json | 67 +--
scripts/smoke-dist.ts | 95 +++++
src/index.tsx | 440 ++++++++++++++++----
src/jsx-runtime.ts | 30 ++
src/rehype-filter.ts | 67 ---
src/renderer.tsx | 286 -------------
src/types.ts | 150 ++-----
src/utils.test.ts | 63 ---
src/utils.ts | 85 ----
test/client.test.tsx | 294 ++++++++++++++
test/helpers.tsx | 89 ++++
test/server.test.tsx | 740 ++++++++++++++++++++++++++++++++++
test/setup.ts | 50 +++
tsconfig.build.json | 10 +
tsconfig.json | 6 +-
tsup.config.ts | 45 ---
23 files changed, 2322 insertions(+), 1037 deletions(-)
create mode 100644 .github/workflows/publish.yml
create mode 100644 build.ts
create mode 100644 bunfig.toml
create mode 100644 scripts/smoke-dist.ts
create mode 100644 src/jsx-runtime.ts
delete mode 100644 src/rehype-filter.ts
delete mode 100644 src/renderer.tsx
delete mode 100644 src/utils.test.ts
delete mode 100644 src/utils.ts
create mode 100644 test/client.test.tsx
create mode 100644 test/helpers.tsx
create mode 100644 test/server.test.tsx
create mode 100644 test/setup.ts
create mode 100644 tsconfig.build.json
delete mode 100644 tsup.config.ts
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 7133d4f..2490a86 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -21,5 +21,5 @@ jobs:
- run: bun install --frozen-lockfile
- run: bun run lint
- run: bun run typecheck
- - run: bun test
+ - run: bun run test
- run: bun run build
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 0000000..7c0bbde
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,37 @@
+name: Publish
+
+permissions:
+ contents: read
+
+on:
+ push:
+ tags:
+ - "v*"
+ workflow_dispatch:
+
+jobs:
+ publish:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
+ - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
+ with:
+ # renovate: datasource=github-releases depName=oven-sh/bun
+ bun-version: "1.3.14"
+ - run: bun install --frozen-lockfile
+ - run: bun run lint
+ - run: bun run typecheck
+ - run: bun run test
+ - run: bun run build
+ - name: Resolve npm dist-tag from version
+ id: disttag
+ run: |
+ version=$(node -p "require('./package.json').version")
+ if [[ "$version" == *-* ]]; then
+ echo "tag=next" >> "$GITHUB_OUTPUT"
+ else
+ echo "tag=latest" >> "$GITHUB_OUTPUT"
+ fi
+ - run: bun publish --access public --tag ${{ steps.disttag.outputs.tag }}
+ env:
+ NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
diff --git a/README.md b/README.md
index 6f17b74..ac56bf4 100644
--- a/README.md
+++ b/README.md
@@ -4,27 +4,25 @@
# `solid-markdown`
-Render markdown as solid components.
+Render markdown to Solid components.
-The implementation is 90% shamelessly copied from https://github.com/remarkjs/react-markdown.
+`solid-markdown` now tracks the `react-markdown` 10.x API closely and keeps the rendering pipeline upstream-aligned while adapting the JSX output to Solid.
-Changes include:
+## Why this update matters
-- Replacing React specific component creation with SolidJS components
-- Porting the implementation from javascript with JSDoc types to typescript
-
-Please check the original repo for in-depth details on how to use.
+This package is now a real Solid port of modern `react-markdown`, not a compatibility wrapper around older behavior. The public API matches upstream concepts such as `components`, `remarkRehypeOptions`, `urlTransform`, and async plugin support, while Solid gets one extra client-side helper: `MarkdownResource`.
## Installation
+
```bash
-npm install solid-markdown
+bun add @rigelbuild/solid-markdown
```
-
## Usage
-```jsx
-import { SolidMarkdown } from "solid-markdown";
+```tsx
+import Markdown from "@rigelbuild/solid-markdown";
+import remarkGfm from "remark-gfm";
const markdown = `
# This is a title
@@ -33,25 +31,203 @@ const markdown = `
- a
- list
`;
-const App = () => {
- return ;
+
+export default function App() {
+ return {markdown} ;
+}
+```
+
+## API reference
+
+| Export | Type | Purpose |
+| --- | --- | --- |
+| `Markdown` | component | Synchronous markdown renderer. |
+| `MarkdownAsync` | function | Async/server renderer for async unified plugins. |
+| `MarkdownResource` | component | Solid client wrapper for async plugin pipelines. |
+| `defaultUrlTransform` | function | Default URL sanitizer used for links and images. |
+| `AllowElement` | type | Per-element allow/deny callback. |
+| `Components` | type | Custom tag-to-component overrides. |
+| `ExtraProps` | type | Extra props passed to custom components (`node`). |
+| `Options` | type | Shared renderer options. |
+| `MarkdownResourceOptions` | type | `Options` plus `fallback`. |
+| `UrlTransform` | type | URL rewrite/sanitization hook. |
+
+### `Markdown`
+
+Synchronous markdown renderer.
+
+```tsx
+import Markdown from "@rigelbuild/solid-markdown";
+import remarkGfm from "remark-gfm";
+
+{value()} ;
+```
+
+### `MarkdownAsync`
+
+Async/server helper for async unified plugins.
+
+```tsx
+import { MarkdownAsync } from "@rigelbuild/solid-markdown";
+import rehypeStarryNight from "rehype-starry-night";
+
+const content = await MarkdownAsync({
+ children: "```js\nconsole.log(3.14)\n```",
+ rehypePlugins: [rehypeStarryNight],
+});
+
+return {content}
;
+```
+
+### `MarkdownResource`
+
+Solid-native client wrapper for async plugins.
+
+```tsx
+import { MarkdownResource } from "@rigelbuild/solid-markdown";
+import rehypeStarryNight from "rehype-starry-night";
+
+Rendering…
}
+ rehypePlugins={[rehypeStarryNight]}
+/>;
+```
+
+### `defaultUrlTransform`
+
+By default, unsafe protocols such as `javascript:` are removed while standard URLs, fragments, and paths are preserved.
+
+```tsx
+import Markdown, { defaultUrlTransform } from "@rigelbuild/solid-markdown";
+
+ {
+ const safe = defaultUrlTransform(url);
+ if (!safe) return safe;
+ return key === "href" && node.tagName === "a" ? `/out?url=${encodeURIComponent(safe)}` : safe;
+ }}
+>
+ {"[OpenAI](https://openai.com)"}
+ ;
+```
+
+## Options
+
+Supported options match upstream `react-markdown` 10.x semantics:
+
+| Option | Purpose |
+| --- | --- |
+| `allowElement` | Decide per HAST element whether it should render. |
+| `allowedElements` | Allowlist tag names. |
+| `children` | Markdown source string. `null` and `undefined` render nothing. |
+| `components` | Override specific HTML tags with Solid components or tag names. |
+| `disallowedElements` | Blocklist tag names. |
+| `rehypePlugins` | Rehype plugins applied after markdown is converted to HAST. |
+| `remarkPlugins` | Remark plugins applied while parsing markdown. |
+| `remarkRehypeOptions` | Extra `remark-rehype` options merged with the safe defaults used by upstream. |
+| `skipHtml` | Ignore raw HTML in the markdown source. |
+| `unwrapDisallowed` | Keep children of removed nodes instead of dropping the whole subtree. |
+| `urlTransform` | Rewrite or sanitize link and image URLs. |
+
+## Components
+
+Custom components receive normal Solid intrinsic props plus `node`.
+
+```tsx
+import Markdown, { type Components } from "@rigelbuild/solid-markdown";
+
+const components: Components = {
+ code(props) {
+ return {props.children};
+ },
};
+
+{"`example`"} ;
+```
+
+## Migration
+
+### Default import
+
+Before:
+
+```tsx
+import { SolidMarkdown } from "@rigelbuild/solid-markdown";
+
+ ;
```
-## Rendering strategy
-There's an extra option you can pass to the markdown component: `renderingStrategy: "memo" | "reconcile"`.
+After:
-The default value is `"memo"`, which means that the markdown parser will generate a new full AST tree each time (inside a `useMemo`), and use that.
-As a consequence, the full DOM will be re-rendered, even the markdown nodes that haven't changed. (Should be fine 90% of the time).
+```tsx
+import Markdown from "@rigelbuild/solid-markdown";
-Using `reconcile` will switch the strategy to using a solid store with the `reconcile` function (https://docs.solidjs.com/reference/store-utilities/reconcile). This will diff the previous and next markdown ASTs and only trigger re-renders for the parts that have changed.
-This will help with cases like streaming partial content and updating the markdown gradually (see https://github.com/andi23rosca/solid-markdown/issues/32).
+{markdown} ;
+```
+### Wrapper ownership
+
+Before:
```tsx
- ;
+{markdown} ;
+```
+
+After:
+
+```tsx
+
+ {markdown}
+
+```
+
+### URL transforms
+
+Before:
+
+```tsx
+ href} transformImageUri={(src) => src}>
+ {markdown}
+ ;
+```
+
+After:
+
+```tsx
+ {
+ if (key === "href") return url;
+ if (key === "src") return url;
+ return url;
+ }}
+>
+ {markdown}
+ ;
+```
+
+### Removed and deprecated behavior
+
+- `SolidMarkdown` is gone. Use the default export instead.
+- Wrapper props such as `class` and `className` are gone. Wrap `Markdown` in your own element.
+- Legacy pre-v9 props now throw at runtime instead of being silently accepted. This includes deprecated names such as `source`, `plugins`, `renderers`, `allowNode`, `allowedTypes`, `disallowedTypes`, `transformLinkUri`, `transformImageUri`, `linkTarget`, and the old source-position props.
+- `urlTransform` replaces `transformLinkUri` and `transformImageUri`.
+- `renderingStrategy="memo" | "reconcile"` is a supported, Solid-specific prop on the synchronous `Markdown` export. This fork keeps it un-deprecated: `"reconcile"` is load-bearing for streaming DOM stability (it rebuilds the subtree each tick so growing content stays consistent), and consumers rely on it permanently.
+
+## Testing and status
+
+Local verification for this port currently runs through:
+
+```bash
+bun run lint
+bun run typecheck
+bun run test
+bun run build
```
-## TODO
+Current status:
-- [ ] Port unit tests from from original library
+- Sync rendering is supported through `Markdown`.
+- Async unified plugins are supported on the server through `MarkdownAsync`.
+- Async unified plugins are supported on the client through `MarkdownResource`.
+- SSR and DOM behavior are covered by the package test suite.
diff --git a/biome.json b/biome.json
index 22dfc58..ed36ac6 100644
--- a/biome.json
+++ b/biome.json
@@ -18,7 +18,10 @@
"linter": {
"enabled": true,
"rules": {
- "recommended": true
+ "recommended": true,
+ "correctness": {
+ "noChildrenProp": "off"
+ }
}
},
"overrides": [
diff --git a/build.ts b/build.ts
new file mode 100644
index 0000000..d17d1a3
--- /dev/null
+++ b/build.ts
@@ -0,0 +1,149 @@
+import { rm } from "node:fs/promises";
+import { type PluginItem, transformAsync } from "@babel/core";
+// @ts-expect-error - @babel/preset-typescript ships no type declarations.
+import tsPreset from "@babel/preset-typescript";
+// @ts-expect-error - babel-preset-solid ships no type declarations.
+import solid from "babel-preset-solid";
+import type { BunPlugin } from "bun";
+
+/**
+ * Build the publishable `dist/`.
+ *
+ * `babel-preset-solid@2` is the Solid compiler, and it is used in both output
+ * modes; the two modes differ only in whether the JSX is compiled now or left
+ * for the consumer's own compiler:
+ *
+ * - **Compiled** (`index.js`, `dev.js`, `server.js`) — Solid compiles the JSX
+ * to `@solidjs/web` runtime calls, then `Bun.build` bundles the now
+ * JSX-free modules into one file per variant. `Bun.build` never sees JSX.
+ * - **Source** (`index.jsx` + sibling `jsx-runtime.js`) — babel strips types
+ * but leaves the JSX untransformed, and the files are written directly, so
+ * the `solid` export condition ships raw JSX for the consuming app's Solid
+ * compiler (matching its exact `solid-js` version and generate settings).
+ * This variant is NOT routed through `Bun.build`, which would apply its own
+ * automatic JSX-runtime transform (emitting a `@solidjs/web/jsx-dev-runtime`
+ * import that subpath does not provide) and defeat JSX preservation.
+ *
+ * The compiled variants set `moduleName: "@solidjs/web"` (babel-preset-solid@2's
+ * default) and `hydratable: true` so the DOM and SSR outputs interoperate for
+ * hydration.
+ */
+
+const entry = "src/index.tsx";
+const outdir = "dist";
+
+// Runtime + peer deps stay external so the published package resolves them from
+// the consumer's tree rather than inlining them (they are declared under
+// `dependencies`/`peerDependencies`).
+const external = [
+ "solid-js",
+ "@solidjs/web",
+ "unified",
+ "remark-parse",
+ "remark-rehype",
+ "unist-util-visit",
+ "vfile",
+ "hast-util-to-jsx-runtime",
+ "html-url-attributes",
+ "devlop",
+];
+
+type CompiledVariant = { file: string; generate: "dom" | "ssr"; dev: boolean };
+
+const compiledVariants: ReadonlyArray = [
+ { file: "index.js", generate: "dom", dev: false },
+ { file: "dev.js", generate: "dom", dev: true },
+ { file: "server.js", generate: "ssr", dev: false },
+];
+
+/** Compile JSX away with `babel-preset-solid`, so `Bun.build` bundles no JSX. */
+function solidCompilePlugin(variant: CompiledVariant): BunPlugin {
+ return {
+ name: `solid-${variant.file}`,
+ setup(build) {
+ build.onLoad({ filter: /\.tsx$/ }, async (args) => {
+ const source = await Bun.file(args.path).text();
+ const result = await transformAsync(source, {
+ filename: args.path,
+ presets: [
+ [tsPreset, { onlyRemoveTypeImports: true }],
+ [
+ solid,
+ {
+ generate: variant.generate,
+ hydratable: true,
+ dev: variant.dev,
+ },
+ ],
+ ],
+ sourceMaps: false,
+ });
+ if (!result?.code) {
+ throw new Error(`solid build: empty transform for ${args.path}`);
+ }
+ return { contents: result.code, loader: "js" };
+ });
+ },
+ };
+}
+
+/** Strip types but preserve JSX for the `solid` export condition. */
+async function emitSource(src: string): Promise {
+ const source = await Bun.file(src).text();
+ const presets: PluginItem[] = [[tsPreset, { onlyRemoveTypeImports: true }]];
+ const result = await transformAsync(source, {
+ filename: src,
+ presets,
+ plugins: ["@babel/plugin-syntax-jsx"],
+ sourceMaps: false,
+ });
+ if (!result?.code) {
+ throw new Error(`solid build: empty source transform for ${src}`);
+ }
+ return result.code;
+}
+
+await rm(outdir, { recursive: true, force: true });
+
+for (const variant of compiledVariants) {
+ const result = await Bun.build({
+ entrypoints: [entry],
+ external,
+ target: variant.generate === "ssr" ? "node" : "browser",
+ format: "esm",
+ plugins: [solidCompilePlugin(variant)],
+ });
+ if (!result.success) {
+ for (const log of result.logs) console.error(log);
+ throw new Error(`solid build: ${variant.file} failed`);
+ }
+ const [artifact] = result.outputs;
+ if (!artifact)
+ throw new Error(`solid build: ${variant.file} produced no output`);
+ await Bun.write(`${outdir}/${variant.file}`, await artifact.text());
+}
+
+// Source variant: JSX left intact for the consumer's Solid compiler. `index.tsx`
+// imports the JSX-free `./jsx-runtime`; ship it as a resolvable sibling and point
+// the import at the emitted `.js`.
+const indexSource = (await emitSource(entry)).replaceAll(
+ 'from "./jsx-runtime"',
+ 'from "./jsx-runtime.js"',
+);
+await Bun.write(`${outdir}/index.jsx`, indexSource);
+await Bun.write(
+ `${outdir}/jsx-runtime.js`,
+ await emitSource("src/jsx-runtime.ts"),
+);
+
+// Type declarations: tsc emits the single `index.d.ts` the exports map points at.
+const dts = Bun.spawnSync(["tsc", "--project", "tsconfig.build.json"], {
+ stdout: "inherit",
+ stderr: "inherit",
+});
+if (dts.exitCode !== 0)
+ throw new Error("solid build: tsc declaration emit failed");
+
+console.log(
+ `built ${compiledVariants.length} compiled variants + index.jsx source + index.d.ts into ${outdir}/`,
+);
diff --git a/bun.lock b/bun.lock
index 13a222e..7cba257 100644
--- a/bun.lock
+++ b/bun.lock
@@ -3,39 +3,46 @@
"configVersion": 1,
"workspaces": {
"": {
- "name": "solid-markdown",
+ "name": "@rigelbuild/solid-markdown",
"dependencies": {
- "comma-separated-tokens": "^2.0.3",
- "property-information": "^6.5.0",
+ "devlop": "^1.1.0",
+ "hast-util-to-jsx-runtime": "^2.3.6",
+ "html-url-attributes": "^3.0.1",
"remark-parse": "^11.0.0",
"remark-rehype": "^11.1.2",
- "space-separated-tokens": "^2.0.2",
- "style-to-object": "^0.3.0",
"unified": "^11.0.5",
- "unist-util-visit": "^4.1.2",
+ "unist-util-visit": "^5.1.0",
"vfile": "^6.0.3",
},
"devDependencies": {
+ "@babel/core": "^7.28.4",
+ "@babel/preset-typescript": "^7.27.1",
"@biomejs/biome": "1.9.4",
+ "@happy-dom/global-registrator": "^20.0.0",
+ "@solidjs/testing-library": "1.0.0-beta.2",
+ "@solidjs/web": "2.0.0-rc.0",
"@types/bun": "^1.4.0",
- "@types/hast": "^2.3.10",
+ "@types/hast": "^3.0.4",
"@types/unist": "^3.0.3",
- "esbuild": "^0.18.20",
- "esbuild-plugin-solid": "^0.5.0",
+ "babel-preset-solid": "2.0.0-rc.0",
+ "rehype-raw": "^7.0.0",
+ "rehype-starry-night": "^2.2.0",
"remark-gfm": "^4.0.1",
- "solid-js": "^1.9.10",
- "tsup": "^8.5.1",
- "tsup-preset-solid": "^2.2.0",
+ "remark-toc": "^9.0.0",
+ "solid-js": "2.0.0-rc.0",
"typescript": "^5.9.3",
"vite": "^7.2.4",
- "vite-plugin-solid": "^2.11.10",
+ "vite-plugin-solid": "3.0.0-next.27",
},
"peerDependencies": {
- "solid-js": "^1.6.0",
+ "@solidjs/web": "^2.0.0-rc.0",
+ "solid-js": "^2.0.0-rc.0",
},
},
},
"packages": {
+ "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
+
"@babel/code-frame": ["@babel/code-frame@7.29.7", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw=="],
"@babel/compat-data": ["@babel/compat-data@7.29.7", "", {}, "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg=="],
@@ -86,6 +93,8 @@
"@babel/preset-typescript": ["@babel/preset-typescript@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-validator-option": "^7.29.7", "@babel/plugin-syntax-jsx": "^7.29.7", "@babel/plugin-transform-modules-commonjs": "^7.29.7", "@babel/plugin-transform-typescript": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ=="],
+ "@babel/runtime": ["@babel/runtime@7.29.7", "", {}, "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw=="],
+
"@babel/template": ["@babel/template@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg=="],
"@babel/traverse": ["@babel/traverse@7.29.8", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.8", "@babel/helper-globals": "^7.29.7", "@babel/parser": "^7.29.8", "@babel/template": "^7.29.7", "@babel/types": "^7.29.8", "debug": "^4.3.1" } }, "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg=="],
@@ -110,57 +119,81 @@
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@1.9.4", "", { "os": "win32", "cpu": "x64" }, "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA=="],
- "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="],
+ "@dom-expressions/babel-plugin-jsx": ["@dom-expressions/babel-plugin-jsx@0.50.0-next.42", "", { "dependencies": { "@babel/helper-module-imports": "7.18.6", "@babel/plugin-syntax-jsx": "^7.18.6", "@babel/types": "^7.20.7", "html-entities": "2.3.3", "parse5": "^7.1.2", "validate-html-nesting": "^1.2.1" }, "peerDependencies": { "@babel/core": "^7.20.12" } }, "sha512-ol24x9RW8loPyOTzC/mQzh/zAsrsPxyTG4WRxxRlwzNK2uBWIBftWN5IwmSV51zDQa7JcT6sE6kkXFCLUvsYIQ=="],
+
+ "@dom-expressions/compiler": ["@dom-expressions/compiler@0.50.0-next.43", "", { "optionalDependencies": { "@dom-expressions/compiler-darwin-arm64": "0.50.0-next.43", "@dom-expressions/compiler-darwin-x64": "0.50.0-next.43", "@dom-expressions/compiler-linux-arm64-gnu": "0.50.0-next.43", "@dom-expressions/compiler-linux-x64-gnu": "0.50.0-next.43", "@dom-expressions/compiler-wasm32-wasi": "0.50.0-next.43", "@dom-expressions/compiler-win32-x64-msvc": "0.50.0-next.43" } }, "sha512-ekEuAFLb868iGu6bw8KA2wgD3gYJpYYTjSbOtuXGlCZnWFA6Wx8Qf720ZYNlb40QjGe3/2kUHTtn47JfaCwPcA=="],
+
+ "@dom-expressions/compiler-darwin-arm64": ["@dom-expressions/compiler-darwin-arm64@0.50.0-next.43", "", { "os": "darwin", "cpu": "arm64" }, "sha512-aVkvvRtEyHPbtZMZe4DHhFzPzQ4qHO9uGXyPDiddBXfjZgkCqejpcJ18t0emJIpIPpproHFdr+9VyLOKs9ENNw=="],
+
+ "@dom-expressions/compiler-darwin-x64": ["@dom-expressions/compiler-darwin-x64@0.50.0-next.43", "", { "os": "darwin", "cpu": "x64" }, "sha512-zJXhjsSydgZbu0pCfD5/FH5UYH7t6Vy8dKD9AVTokE3LFQgLIVrssX2WwN60jh5+OW9okbJBGZXiZ4/2sqb9OA=="],
+
+ "@dom-expressions/compiler-linux-arm64-gnu": ["@dom-expressions/compiler-linux-arm64-gnu@0.50.0-next.43", "", { "os": "linux", "cpu": "arm64" }, "sha512-ZEjWL59aAj39C7TANYvtzW5rmeH/kfzZIWoZ3Wf/MSiXm8Ermadx76hX0yMMqLdxy0ec69lRYF4gXC7X2k6LMw=="],
+
+ "@dom-expressions/compiler-linux-x64-gnu": ["@dom-expressions/compiler-linux-x64-gnu@0.50.0-next.43", "", { "os": "linux", "cpu": "x64" }, "sha512-ur/VTzMqAkJq45GHSGlk4uq0I/92Zow5mPcovh+Lg2bnyNrPXMNM9kXrIqio2jUgSyRT4y2QbeI9Us30IeZI6g=="],
+
+ "@dom-expressions/compiler-wasm32-wasi": ["@dom-expressions/compiler-wasm32-wasi@0.50.0-next.43", "", { "dependencies": { "@emnapi/core": "1.11.2", "@emnapi/runtime": "1.11.2", "@napi-rs/wasm-runtime": "^1.1.6" } }, "sha512-X+0Rz1fm7Z1S3ONFwg+NJ8edf2MWUrxOrP50hM2x4PkIe2ST0WzqHbkH4yIXjqttF0R1NErh+ac3q4WGF4wWBg=="],
+
+ "@dom-expressions/compiler-win32-x64-msvc": ["@dom-expressions/compiler-win32-x64-msvc@0.50.0-next.43", "", { "os": "win32", "cpu": "x64" }, "sha512-hQlqtiYVst4rNKAWtC9cwfuP95L8Dw+PR5Zwp6AA92vsMgQlJ7+QaJoQAxuKkEUtl212VnW06SJKzx00pSkv8g=="],
- "@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="],
+ "@emnapi/core": ["@emnapi/core@1.11.2", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" } }, "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA=="],
- "@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="],
+ "@emnapi/runtime": ["@emnapi/runtime@1.11.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA=="],
- "@esbuild/android-x64": ["@esbuild/android-x64@0.18.20", "", { "os": "android", "cpu": "x64" }, "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg=="],
+ "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="],
- "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.18.20", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA=="],
+ "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ=="],
- "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.18.20", "", { "os": "darwin", "cpu": "x64" }, "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ=="],
+ "@esbuild/android-arm": ["@esbuild/android-arm@0.28.2", "", { "os": "android", "cpu": "arm" }, "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg=="],
- "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.18.20", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw=="],
+ "@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.2", "", { "os": "android", "cpu": "arm64" }, "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A=="],
- "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.18.20", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ=="],
+ "@esbuild/android-x64": ["@esbuild/android-x64@0.28.2", "", { "os": "android", "cpu": "x64" }, "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q=="],
- "@esbuild/linux-arm": ["@esbuild/linux-arm@0.18.20", "", { "os": "linux", "cpu": "arm" }, "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg=="],
+ "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw=="],
- "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.18.20", "", { "os": "linux", "cpu": "arm64" }, "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA=="],
+ "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw=="],
- "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.18.20", "", { "os": "linux", "cpu": "ia32" }, "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA=="],
+ "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw=="],
- "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg=="],
+ "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg=="],
- "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ=="],
+ "@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.2", "", { "os": "linux", "cpu": "arm" }, "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w=="],
- "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.18.20", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA=="],
+ "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug=="],
- "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A=="],
+ "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ=="],
- "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.18.20", "", { "os": "linux", "cpu": "s390x" }, "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ=="],
+ "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ=="],
- "@esbuild/linux-x64": ["@esbuild/linux-x64@0.18.20", "", { "os": "linux", "cpu": "x64" }, "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w=="],
+ "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA=="],
- "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w=="],
+ "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ=="],
- "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.18.20", "", { "os": "none", "cpu": "x64" }, "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A=="],
+ "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA=="],
- "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.7", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A=="],
+ "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg=="],
- "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.18.20", "", { "os": "openbsd", "cpu": "x64" }, "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg=="],
+ "@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.2", "", { "os": "linux", "cpu": "x64" }, "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ=="],
- "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw=="],
+ "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw=="],
- "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.18.20", "", { "os": "sunos", "cpu": "x64" }, "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ=="],
+ "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.2", "", { "os": "none", "cpu": "x64" }, "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw=="],
- "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.18.20", "", { "os": "win32", "cpu": "arm64" }, "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg=="],
+ "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ=="],
- "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="],
+ "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw=="],
- "@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="],
+ "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q=="],
+
+ "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g=="],
+
+ "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ=="],
+
+ "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA=="],
+
+ "@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g=="],
+
+ "@happy-dom/global-registrator": ["@happy-dom/global-registrator@20.11.6", "", { "dependencies": { "@types/node": ">=20.0.0", "happy-dom": "^20.11.6" } }, "sha512-ZQ47qUTeNbGhHkCGExJ1oZhruoxKRaxO44RgFETl3T4c1rRxIBlAOnM3SAH4XHu7Ue2owJXP+jOx1vOuKuxcSg=="],
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
@@ -174,6 +207,8 @@
"@napi-rs/lzma-linux-x64-gnu": ["@napi-rs/lzma-linux-x64-gnu@1.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ=="],
+ "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.2.3", "", { "dependencies": { "@tybys/wasm-util": "^0.10.3" }, "peerDependencies": { "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" } }, "sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q=="],
+
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.62.5", "", { "os": "android", "cpu": "arm" }, "sha512-jfkGfTwhQpsiSckPF8r9bU3pn3vyd72NlWaO+TgEO6WPSDnUhXzrNYCHBMOYj0ACaUgjm6eERLF+XV9a6RstoA=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.62.5", "", { "os": "android", "cpu": "arm64" }, "sha512-oGVqyQlxnrz9/ty89oHpU857VUHEl5/Xu4R2lS+aivCTrNnSsbiENzTnNaBsjxH0CNWGPhzHArOLFwo+oKXveA=="],
@@ -224,6 +259,20 @@
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.62.5", "", { "os": "win32", "cpu": "x64" }, "sha512-/gDJaRs4gl0NPIwqCz+6PkpmhhjRAD2j6P4rSNHBzUkO3naEx2mIU0pRle1vUNRQ7mE/+8OOeXLTv/J56FKiQg=="],
+ "@solidjs/signals": ["@solidjs/signals@2.0.0-rc.0", "", {}, "sha512-oKZSfvsCcKw1uJjOGbUkJ+OqlhXLHtZ+rShSyu9KH0lUH7UUwfMfsKeh81JPiQxDDg4YLhEwI38hg0JkwzTdvA=="],
+
+ "@solidjs/testing-library": ["@solidjs/testing-library@1.0.0-beta.2", "", { "dependencies": { "@testing-library/dom": "^10.4.1" }, "peerDependencies": { "@solidjs/web": ">=2.0.0", "solid-js": ">=2.0.0" } }, "sha512-TLhQ5IUT/fdDfqa4X2rkQWB28Y+zEwi6mK/TVTeiQlEHG63eK2jfgwNYf2NtQoPh2c3ihLilsCzxABiSTP3JoQ=="],
+
+ "@solidjs/vite-plugin": ["@solidjs/vite-plugin@3.0.0-next.31", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "@babel/core": "^7.23.3", "@dom-expressions/compiler": "^0.50.0-next.43", "@types/babel__core": "^7.20.4", "babel-preset-solid": "^2.0.0-rc.0", "merge-anything": "^5.1.7", "vitefu": "^1.0.4" }, "peerDependencies": { "@solidjs/start-devtools": "^1.0.0-next.0", "@solidjs/web": "^2.0.0-rc.0", "@testing-library/jest-dom": "^5.16.6 || ^5.17.0 || ^6.*", "solid-js": "^2.0.0-rc.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" }, "optionalPeers": ["@solidjs/start-devtools", "@testing-library/jest-dom"] }, "sha512-iS9zz4MdzQwZyXGtEYKxFu9fHjX6fs0CWWQTQZ54xaaPKPOcv1sXJtxZ+th7EsmGlmeUNP0jBYoB9qxkd47tiQ=="],
+
+ "@solidjs/web": ["@solidjs/web@2.0.0-rc.0", "", { "dependencies": { "seroval": "~1.5.4", "seroval-plugins": "~1.5.4" }, "peerDependencies": { "solid-js": "^2.0.0-rc.0" } }, "sha512-pYSaA9+dH8H1h/d/ZF/P2kR6omfzFGNcdzKhWTcg9fJghXhn8+5UrXUr2iYxDdYNOXZzxxFQhYHSJ7P4HKDqgw=="],
+
+ "@testing-library/dom": ["@testing-library/dom@10.4.1", "", { "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.3.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "picocolors": "1.1.1", "pretty-format": "^27.0.2" } }, "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg=="],
+
+ "@tybys/wasm-util": ["@tybys/wasm-util@0.10.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg=="],
+
+ "@types/aria-query": ["@types/aria-query@5.0.4", "", {}, "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw=="],
+
"@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="],
"@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="],
@@ -238,7 +287,9 @@
"@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="],
- "@types/hast": ["@types/hast@2.3.10", "", { "dependencies": { "@types/unist": "^2" } }, "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw=="],
+ "@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="],
+
+ "@types/hast": ["@types/hast@3.0.5", "", { "dependencies": { "@types/unist": "*" } }, "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g=="],
"@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="],
@@ -246,17 +297,25 @@
"@types/node": ["@types/node@26.2.0", "", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg=="],
+ "@types/ungap__structured-clone": ["@types/ungap__structured-clone@1.2.0", "", {}, "sha512-ZoaihZNLeZSxESbk9PUAPZOlSpcKx81I1+4emtULDVmBLkYutTcMlCj2K9VNlf9EWODxdO6gkAqEaLorXwZQVA=="],
+
"@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
+ "@types/whatwg-mimetype": ["@types/whatwg-mimetype@3.0.2", "", {}, "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA=="],
+
+ "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
+
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.3", "", {}, "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg=="],
- "acorn": ["acorn@8.18.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ=="],
+ "@wooorm/starry-night": ["@wooorm/starry-night@3.10.0", "", { "dependencies": { "@types/hast": "^3.0.0", "import-meta-resolve": "^4.0.0", "vscode-oniguruma": "^2.0.0", "vscode-textmate": "^9.0.0" } }, "sha512-JRp2va6hfbC14fXgYQTmwdl4j1+4ZID9KKkCD+Mn/+B/j1QMlzZYPUtXOFNxA+CWrEo+IPha6EMVbsap2OFZig=="],
+
+ "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
- "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="],
+ "ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
- "babel-plugin-jsx-dom-expressions": ["babel-plugin-jsx-dom-expressions@0.40.10", "", { "dependencies": { "@babel/helper-module-imports": "7.18.6", "@babel/plugin-syntax-jsx": "^7.18.6", "@babel/types": "^7.20.7", "html-entities": "2.3.3", "parse5": "^7.1.2" }, "peerDependencies": { "@babel/core": "^7.20.12" } }, "sha512-lxve6Y02YiZTldB7efKpnbf1BH00XCFZNYYW235jSGsYaJNFtHrYlKV6/O+miHbjqpIr9FTe5+0no4hofAMbfA=="],
+ "aria-query": ["aria-query@5.3.0", "", { "dependencies": { "dequal": "^2.0.3" } }, "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A=="],
- "babel-preset-solid": ["babel-preset-solid@1.9.15", "", { "dependencies": { "babel-plugin-jsx-dom-expressions": "^0.40.10" }, "peerDependencies": { "@babel/core": "^7.0.0", "solid-js": "^1.9.15" }, "optionalPeers": ["solid-js"] }, "sha512-GBmg1OiPb+OwcH51XbDAKPtvrPfQW7rCJTJxcp8+yhtWwN+kqnbEJk2SgVybd+uhTxTKAvjaFyiQSr/eUZBwzg=="],
+ "babel-preset-solid": ["babel-preset-solid@2.0.0-rc.0", "", { "dependencies": { "@dom-expressions/babel-plugin-jsx": "0.50.0-next.42" }, "peerDependencies": { "@babel/core": "^7.0.0", "solid-js": "^2.0.0-rc.0" }, "optionalPeers": ["solid-js"] }, "sha512-Ap2/QQY3pICj+Q0VM/RnIOpZo7e6icZnUA0oBJuhqzoCrljqMNo3eFb2OeEa4pUQeFREJOlex4Bt1ggwrcgC8w=="],
"bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="],
@@ -264,11 +323,9 @@
"browserslist": ["browserslist@4.28.8", "", { "dependencies": { "baseline-browser-mapping": "^2.11.12", "caniuse-lite": "^1.0.30001809", "electron-to-chromium": "^1.5.402", "node-releases": "^2.0.53", "update-browserslist-db": "^1.3.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA=="],
- "bun-types": ["bun-types@1.4.0", "", { "dependencies": { "@types/node": "*" } }, "sha512-iIKw23BspnQQYd3prITOBxeUsxBHnwzX6YJfGMuNOZzeNcMmVqzIIVGRm1l69ogaPQmb4wB6BN8mA5bE9YuC5Q=="],
-
- "bundle-require": ["bundle-require@5.1.0", "", { "dependencies": { "load-tsconfig": "^0.2.3" }, "peerDependencies": { "esbuild": ">=0.18" } }, "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA=="],
+ "buffer-image-size": ["buffer-image-size@0.6.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-nEh+kZOPY1w+gcCMobZ6ETUp9WfibndnosbpwB1iJk/8Gt5ZF2bhS6+B6bPYz424KtwsR6Rflc3tCz1/ghX2dQ=="],
- "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="],
+ "bun-types": ["bun-types@1.4.0", "", { "dependencies": { "@types/node": "*" } }, "sha512-iIKw23BspnQQYd3prITOBxeUsxBHnwzX6YJfGMuNOZzeNcMmVqzIIVGRm1l69ogaPQmb4wB6BN8mA5bE9YuC5Q=="],
"caniuse-lite": ["caniuse-lite@1.0.30001809", "", {}, "sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ=="],
@@ -276,15 +333,13 @@
"character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="],
- "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
-
- "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="],
+ "character-entities-html4": ["character-entities-html4@2.1.0", "", {}, "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="],
- "commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="],
+ "character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="],
- "confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
+ "character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="],
- "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="],
+ "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="],
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
@@ -298,55 +353,83 @@
"devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="],
- "electron-to-chromium": ["electron-to-chromium@1.5.412", "", {}, "sha512-z4rMe3esBzlzovKHj4gxJnsCGZRK5l4baUvm+gCGJBPE+gsyUMKsuU9tnEUtI1dOebXz1ytAPGjvXhmQ7rIPwA=="],
+ "dom-accessibility-api": ["dom-accessibility-api@0.5.16", "", {}, "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="],
- "entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
+ "electron-to-chromium": ["electron-to-chromium@1.5.412", "", {}, "sha512-z4rMe3esBzlzovKHj4gxJnsCGZRK5l4baUvm+gCGJBPE+gsyUMKsuU9tnEUtI1dOebXz1ytAPGjvXhmQ7rIPwA=="],
- "esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="],
+ "entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="],
- "esbuild-plugin-solid": ["esbuild-plugin-solid@0.5.0", "", { "dependencies": { "@babel/core": "^7.20.12", "@babel/preset-typescript": "^7.18.6", "babel-preset-solid": "^1.6.9" }, "peerDependencies": { "esbuild": ">=0.12", "solid-js": ">= 1.0" } }, "sha512-ITK6n+0ayGFeDVUZWNMxX+vLsasEN1ILrg4pISsNOQ+mq4ljlJJiuXotInd+HE0MzwTcA9wExT1yzDE2hsqPsg=="],
+ "esbuild": ["esbuild@0.28.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.2", "@esbuild/android-arm": "0.28.2", "@esbuild/android-arm64": "0.28.2", "@esbuild/android-x64": "0.28.2", "@esbuild/darwin-arm64": "0.28.2", "@esbuild/darwin-x64": "0.28.2", "@esbuild/freebsd-arm64": "0.28.2", "@esbuild/freebsd-x64": "0.28.2", "@esbuild/linux-arm": "0.28.2", "@esbuild/linux-arm64": "0.28.2", "@esbuild/linux-ia32": "0.28.2", "@esbuild/linux-loong64": "0.28.2", "@esbuild/linux-mips64el": "0.28.2", "@esbuild/linux-ppc64": "0.28.2", "@esbuild/linux-riscv64": "0.28.2", "@esbuild/linux-s390x": "0.28.2", "@esbuild/linux-x64": "0.28.2", "@esbuild/netbsd-arm64": "0.28.2", "@esbuild/netbsd-x64": "0.28.2", "@esbuild/openbsd-arm64": "0.28.2", "@esbuild/openbsd-x64": "0.28.2", "@esbuild/openharmony-arm64": "0.28.2", "@esbuild/sunos-x64": "0.28.2", "@esbuild/win32-arm64": "0.28.2", "@esbuild/win32-ia32": "0.28.2", "@esbuild/win32-x64": "0.28.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA=="],
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
"escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
+ "estree-util-is-identifier-name": ["estree-util-is-identifier-name@3.0.0", "", {}, "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg=="],
+
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
- "fix-dts-default-cjs-exports": ["fix-dts-default-cjs-exports@1.0.1", "", { "dependencies": { "magic-string": "^0.30.17", "mlly": "^1.7.4", "rollup": "^4.34.8" } }, "sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg=="],
-
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
+ "github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="],
+
+ "happy-dom": ["happy-dom@20.11.6", "", { "dependencies": { "@types/node": ">=20.0.0", "@types/whatwg-mimetype": "^3.0.2", "@types/ws": "^8.18.1", "buffer-image-size": "^0.6.4", "entities": "^7.0.1", "whatwg-mimetype": "^3.0.0", "ws": "^8.21.0" } }, "sha512-Hldbg8AdAa5a5oDcZpjqnGitp7JB0hqWmfv/8qr+kft4vzSD8BHsbdRfzYvL/0QcbKcURC/yyoygbeDQarPvYg=="],
+
+ "hast-util-from-parse5": ["hast-util-from-parse5@8.0.3", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", "hastscript": "^9.0.0", "property-information": "^7.0.0", "vfile": "^6.0.0", "vfile-location": "^5.0.0", "web-namespaces": "^2.0.0" } }, "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg=="],
+
+ "hast-util-parse-selector": ["hast-util-parse-selector@4.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A=="],
+
+ "hast-util-raw": ["hast-util-raw@9.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "@ungap/structured-clone": "^1.0.0", "hast-util-from-parse5": "^8.0.0", "hast-util-to-parse5": "^8.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "parse5": "^7.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0", "web-namespaces": "^2.0.0", "zwitch": "^2.0.0" } }, "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw=="],
+
+ "hast-util-to-jsx-runtime": ["hast-util-to-jsx-runtime@2.3.6", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "hast-util-whitespace": "^3.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "style-to-js": "^1.0.0", "unist-util-position": "^5.0.0", "vfile-message": "^4.0.0" } }, "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg=="],
+
+ "hast-util-to-parse5": ["hast-util-to-parse5@8.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "web-namespaces": "^2.0.0", "zwitch": "^2.0.0" } }, "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA=="],
+
+ "hast-util-to-string": ["hast-util-to-string@3.0.1", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A=="],
+
+ "hast-util-whitespace": ["hast-util-whitespace@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw=="],
+
+ "hastscript": ["hastscript@9.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-parse-selector": "^4.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0" } }, "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w=="],
+
"html-entities": ["html-entities@2.3.3", "", {}, "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA=="],
- "inline-style-parser": ["inline-style-parser@0.1.1", "", {}, "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q=="],
+ "html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="],
+
+ "html-void-elements": ["html-void-elements@3.0.0", "", {}, "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="],
+
+ "import-meta-resolve": ["import-meta-resolve@4.2.0", "", {}, "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg=="],
+
+ "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="],
+
+ "is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="],
+
+ "is-alphanumerical": ["is-alphanumerical@2.0.1", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw=="],
+
+ "is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="],
+
+ "is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="],
"is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="],
"is-what": ["is-what@4.1.16", "", {}, "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A=="],
- "joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="],
-
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
"jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
"json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
- "lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="],
-
- "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="],
-
- "load-tsconfig": ["load-tsconfig@0.2.5", "", {}, "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg=="],
+ "levenshtein-edit-distance": ["levenshtein-edit-distance@3.0.1", "", { "bin": { "levenshtein-edit-distance": "cli.js" } }, "sha512-/qMCkZbrAF7jZP/voqlkfNrBtEn0TMdhCK7OEBh/zb39t/c3wCnTjwU1ZvrMfQ3OxB8sBQXIpWRMM6FiQJVG3g=="],
"longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="],
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
- "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
+ "lz-string": ["lz-string@1.5.0", "", { "bin": { "lz-string": "bin/bin.js" } }, "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ=="],
"markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="],
@@ -366,6 +449,12 @@
"mdast-util-gfm-task-list-item": ["mdast-util-gfm-task-list-item@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ=="],
+ "mdast-util-mdx-expression": ["mdast-util-mdx-expression@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ=="],
+
+ "mdast-util-mdx-jsx": ["mdast-util-mdx-jsx@3.2.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "devlop": "^1.1.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "parse-entities": "^4.0.0", "stringify-entities": "^4.0.0", "unist-util-stringify-position": "^4.0.0", "vfile-message": "^4.0.0" } }, "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q=="],
+
+ "mdast-util-mdxjs-esm": ["mdast-util-mdxjs-esm@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg=="],
+
"mdast-util-phrasing": ["mdast-util-phrasing@4.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "unist-util-is": "^6.0.0" } }, "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w=="],
"mdast-util-to-hast": ["mdast-util-to-hast@13.2.1", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@ungap/structured-clone": "^1.0.0", "devlop": "^1.0.0", "micromark-util-sanitize-uri": "^2.0.0", "trim-lines": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA=="],
@@ -374,6 +463,8 @@
"mdast-util-to-string": ["mdast-util-to-string@4.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0" } }, "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg=="],
+ "mdast-util-toc": ["mdast-util-toc@7.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/ungap__structured-clone": "^1.0.0", "@ungap/structured-clone": "^1.0.0", "github-slugger": "^2.0.0", "mdast-util-to-string": "^4.0.0", "unist-util-is": "^6.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-2TVKotOQzqdY7THOdn2gGzS9d1Sdd66bvxUyw3aNpWfcPXCLYSJCCgfPy30sEtuzkDraJgqF35dzgmz6xlvH/w=="],
+
"merge-anything": ["merge-anything@5.1.7", "", { "dependencies": { "is-what": "^4.1.8" } }, "sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ=="],
"micromark": ["micromark@4.0.2", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA=="],
@@ -432,37 +523,31 @@
"micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="],
- "mlly": ["mlly@1.8.2", "", { "dependencies": { "acorn": "^8.16.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.3" } }, "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA=="],
-
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
- "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="],
-
"nanoid": ["nanoid@3.3.18", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w=="],
"node-releases": ["node-releases@2.0.53", "", {}, "sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ=="],
- "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
+ "parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="],
"parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="],
- "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
-
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"picomatch": ["picomatch@4.0.5", "", {}, "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A=="],
- "pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="],
+ "postcss": ["postcss@8.5.26", "", { "dependencies": { "nanoid": "^3.3.17", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ=="],
- "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="],
+ "pretty-format": ["pretty-format@27.5.1", "", { "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" } }, "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ=="],
- "postcss": ["postcss@8.5.26", "", { "dependencies": { "nanoid": "^3.3.17", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ=="],
+ "property-information": ["property-information@7.2.0", "", {}, "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg=="],
- "postcss-load-config": ["postcss-load-config@6.0.1", "", { "dependencies": { "lilconfig": "^3.1.1" }, "peerDependencies": { "jiti": ">=1.21.0", "postcss": ">=8.0.9", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["jiti", "postcss", "tsx", "yaml"] }, "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g=="],
+ "react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="],
- "property-information": ["property-information@6.5.0", "", {}, "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig=="],
+ "rehype-raw": ["rehype-raw@7.0.0", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-raw": "^9.0.0", "vfile": "^6.0.0" } }, "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww=="],
- "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
+ "rehype-starry-night": ["rehype-starry-night@2.2.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@wooorm/starry-night": "^3.0.0", "hast-util-to-string": "^3.0.0", "levenshtein-edit-distance": "^3.0.0", "unist-util-visit-parents": "^6.0.0", "vfile": "^6.0.0" } }, "sha512-hAdJb/14aNHPEAsP37Rt1X8HbkTsQb/2pAyL0inJn+VnXqdM714MBAL/9zC5CObCM3/zIjpwOsXMETTayx2iaw=="],
"remark-gfm": ["remark-gfm@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-gfm": "^3.0.0", "micromark-extension-gfm": "^3.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.0" } }, "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg=="],
@@ -472,7 +557,7 @@
"remark-stringify": ["remark-stringify@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", "unified": "^11.0.0" } }, "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw=="],
- "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="],
+ "remark-toc": ["remark-toc@9.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-toc": "^7.0.0" } }, "sha512-KJ9txbo33GjDAV1baHFze7ij4G8c7SGYoY8Kzsm2gzFpbhL/bSoVpMMzGa3vrNDSWASNd/3ppAqL7cP2zD6JIA=="],
"rollup": ["rollup@4.62.5", "", { "dependencies": { "@types/estree": "1.0.9" }, "optionalDependencies": { "@napi-rs/lzma-linux-x64-gnu": "1.5.1", "@rollup/rollup-android-arm-eabi": "4.62.5", "@rollup/rollup-android-arm64": "4.62.5", "@rollup/rollup-darwin-arm64": "4.62.5", "@rollup/rollup-darwin-x64": "4.62.5", "@rollup/rollup-freebsd-arm64": "4.62.5", "@rollup/rollup-freebsd-x64": "4.62.5", "@rollup/rollup-linux-arm-gnueabihf": "4.62.5", "@rollup/rollup-linux-arm-musleabihf": "4.62.5", "@rollup/rollup-linux-arm64-gnu": "4.62.5", "@rollup/rollup-linux-arm64-musl": "4.62.5", "@rollup/rollup-linux-loong64-gnu": "4.62.5", "@rollup/rollup-linux-loong64-musl": "4.62.5", "@rollup/rollup-linux-ppc64-gnu": "4.62.5", "@rollup/rollup-linux-ppc64-musl": "4.62.5", "@rollup/rollup-linux-riscv64-gnu": "4.62.5", "@rollup/rollup-linux-riscv64-musl": "4.62.5", "@rollup/rollup-linux-s390x-gnu": "4.62.5", "@rollup/rollup-linux-x64-gnu": "4.62.5", "@rollup/rollup-linux-x64-musl": "4.62.5", "@rollup/rollup-openbsd-x64": "4.62.5", "@rollup/rollup-openharmony-arm64": "4.62.5", "@rollup/rollup-win32-arm64-msvc": "4.62.5", "@rollup/rollup-win32-ia32-msvc": "4.62.5", "@rollup/rollup-win32-x64-gnu": "4.62.5", "@rollup/rollup-win32-x64-msvc": "4.62.5", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-/tqMfgP7GPA3PHhCmuiS4vIjrSVhHLgY++i+dhbG462euyAj7FpM4D9uq1X3BgjlqRdpcOrYhcQtfiQLNc8tqw=="],
@@ -482,204 +567,76 @@
"seroval-plugins": ["seroval-plugins@1.5.6", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-HXuLAX2pu/UByPpaeo/TaMfvMIi+1QqIoPJYCcAtU8QkVNwgR6MPlGuCQTErV1JwraaMbYaWVIBX7mppzGLATQ=="],
- "solid-js": ["solid-js@1.9.15", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.5.4", "seroval-plugins": "~1.5.4" } }, "sha512-EeiY2xfpZJqPLjXspVEKjAII4yv8NyG//NxZ3IpOFHdUNnnTyL0uJOeS9LWGvA7cFCz5y94cjFwYlmw5Luncsg=="],
-
- "solid-refresh": ["solid-refresh@0.6.3", "", { "dependencies": { "@babel/generator": "^7.23.6", "@babel/helper-module-imports": "^7.22.15", "@babel/types": "^7.23.6" }, "peerDependencies": { "solid-js": "^1.3" } }, "sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA=="],
-
- "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
+ "solid-js": ["solid-js@2.0.0-rc.0", "", { "dependencies": { "@solidjs/signals": "^2.0.0-rc.0", "csstype": "^3.1.0", "seroval": "~1.5.4", "seroval-plugins": "~1.5.4" } }, "sha512-3enTJ71VL69nM5p/it2InVBDBt316Cqfij+F0S7VuHZLITc8YV7Rvavjoy52nAKKxYWXM+BcXh2K7KcLTf1zdQ=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
"space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="],
- "style-to-object": ["style-to-object@0.3.0", "", { "dependencies": { "inline-style-parser": "0.1.1" } }, "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA=="],
-
- "sucrase": ["sucrase@3.35.1", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "tinyglobby": "^0.2.11", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw=="],
+ "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="],
- "thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="],
+ "style-to-js": ["style-to-js@1.1.21", "", { "dependencies": { "style-to-object": "1.0.14" } }, "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ=="],
- "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="],
-
- "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="],
+ "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="],
"tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="],
- "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="],
-
"trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="],
"trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="],
- "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="],
-
- "tsup": ["tsup@8.5.1", "", { "dependencies": { "bundle-require": "^5.1.0", "cac": "^6.7.14", "chokidar": "^4.0.3", "consola": "^3.4.0", "debug": "^4.4.0", "esbuild": "^0.27.0", "fix-dts-default-cjs-exports": "^1.0.0", "joycon": "^3.1.1", "picocolors": "^1.1.1", "postcss-load-config": "^6.0.1", "resolve-from": "^5.0.0", "rollup": "^4.34.8", "source-map": "^0.7.6", "sucrase": "^3.35.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.11", "tree-kill": "^1.2.2" }, "peerDependencies": { "@microsoft/api-extractor": "^7.36.0", "@swc/core": "^1", "postcss": "^8.4.12", "typescript": ">=4.5.0" }, "optionalPeers": ["@microsoft/api-extractor", "@swc/core", "postcss", "typescript"], "bin": { "tsup": "dist/cli-default.js", "tsup-node": "dist/cli-node.js" } }, "sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing=="],
-
- "tsup-preset-solid": ["tsup-preset-solid@2.2.0", "", { "dependencies": { "esbuild-plugin-solid": "^0.5.0" }, "peerDependencies": { "tsup": "^8.0.0" } }, "sha512-sPAzeArmYkVAZNRN+m4tkiojdd0GzW/lCwd4+TQDKMENe8wr2uAuro1s0Z59ASmdBbkXoxLgCiNcuQMyiidMZg=="],
+ "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
- "ufo": ["ufo@1.6.4", "", {}, "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA=="],
-
"undici-types": ["undici-types@8.3.0", "", {}, "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="],
"unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="],
- "unist-util-is": ["unist-util-is@5.2.1", "", { "dependencies": { "@types/unist": "^2.0.0" } }, "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw=="],
+ "unist-util-is": ["unist-util-is@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g=="],
"unist-util-position": ["unist-util-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA=="],
"unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="],
- "unist-util-visit": ["unist-util-visit@4.1.2", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0", "unist-util-visit-parents": "^5.1.1" } }, "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg=="],
+ "unist-util-visit": ["unist-util-visit@5.1.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg=="],
- "unist-util-visit-parents": ["unist-util-visit-parents@5.1.3", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0" } }, "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg=="],
+ "unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="],
"update-browserslist-db": ["update-browserslist-db@1.3.1", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-ZZ61DsRsOnakl74HAmp3oSN4aXUmEWXf+i/yv0h7tIBfICc3VdrFErQKUUKPgu3AMsTUMbcongALEN4l6GSUrQ=="],
+ "validate-html-nesting": ["validate-html-nesting@1.2.4", "", {}, "sha512-doQi7e8EJ2OWneSG1aZpJluS6A49aZM0+EICXWKm1i6WvqTLmq0tpUcImc4KTWG50mORO0C4YDBtOCSYvElftw=="],
+
"vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
+ "vfile-location": ["vfile-location@5.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg=="],
+
"vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="],
"vite": ["vite@7.3.6", "", { "dependencies": { "esbuild": "^0.27.0 || ^0.28.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg=="],
- "vite-plugin-solid": ["vite-plugin-solid@2.11.14", "", { "dependencies": { "@babel/core": "^7.23.3", "@types/babel__core": "^7.20.4", "babel-preset-solid": "^1.8.4", "merge-anything": "^5.1.7", "solid-refresh": "^0.6.3", "vitefu": "^1.0.4" }, "peerDependencies": { "@testing-library/jest-dom": "^5.16.6 || ^5.17.0 || ^6.0.0 || ^7.0.0", "solid-js": "^1.7.2", "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" }, "optionalPeers": ["@testing-library/jest-dom"] }, "sha512-7ZVBt8rpoyqmlwin2kRIUveaHoF6/kulY7gsnD+qFh4nS29V4OPAnw+ojoAspXIjObiL9o1xh9a/nTuYHm02Rw=="],
+ "vite-plugin-solid": ["vite-plugin-solid@3.0.0-next.27", "", { "dependencies": { "@solidjs/vite-plugin": "^3.0.0-next.27" } }, "sha512-bDzjIIplkSDH73BiGP9pbPR3ZnjeUA18SAYugLhqDCy4u0bl3qdrETstxrXuo2vHXLB0VD9rvOr0iesZBBul4Q=="],
"vitefu": ["vitefu@1.1.3", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["vite"] }, "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg=="],
- "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
-
- "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
-
- "@types/hast/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
-
- "babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="],
-
- "mdast-util-find-and-replace/unist-util-is": ["unist-util-is@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g=="],
-
- "mdast-util-find-and-replace/unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="],
-
- "mdast-util-phrasing/unist-util-is": ["unist-util-is@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g=="],
-
- "mdast-util-to-hast/@types/hast": ["@types/hast@3.0.5", "", { "dependencies": { "@types/unist": "*" } }, "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g=="],
-
- "mdast-util-to-hast/unist-util-visit": ["unist-util-visit@5.1.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg=="],
-
- "mdast-util-to-markdown/unist-util-visit": ["unist-util-visit@5.1.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg=="],
-
- "remark-rehype/@types/hast": ["@types/hast@3.0.5", "", { "dependencies": { "@types/unist": "*" } }, "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g=="],
-
- "tsup/esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="],
-
- "unist-util-is/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
-
- "unist-util-visit/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
-
- "unist-util-visit-parents/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
-
- "vite/esbuild": ["esbuild@0.28.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.2", "@esbuild/android-arm": "0.28.2", "@esbuild/android-arm64": "0.28.2", "@esbuild/android-x64": "0.28.2", "@esbuild/darwin-arm64": "0.28.2", "@esbuild/darwin-x64": "0.28.2", "@esbuild/freebsd-arm64": "0.28.2", "@esbuild/freebsd-x64": "0.28.2", "@esbuild/linux-arm": "0.28.2", "@esbuild/linux-arm64": "0.28.2", "@esbuild/linux-ia32": "0.28.2", "@esbuild/linux-loong64": "0.28.2", "@esbuild/linux-mips64el": "0.28.2", "@esbuild/linux-ppc64": "0.28.2", "@esbuild/linux-riscv64": "0.28.2", "@esbuild/linux-s390x": "0.28.2", "@esbuild/linux-x64": "0.28.2", "@esbuild/netbsd-arm64": "0.28.2", "@esbuild/netbsd-x64": "0.28.2", "@esbuild/openbsd-arm64": "0.28.2", "@esbuild/openbsd-x64": "0.28.2", "@esbuild/openharmony-arm64": "0.28.2", "@esbuild/sunos-x64": "0.28.2", "@esbuild/win32-arm64": "0.28.2", "@esbuild/win32-ia32": "0.28.2", "@esbuild/win32-x64": "0.28.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA=="],
-
- "mdast-util-to-hast/unist-util-visit/unist-util-is": ["unist-util-is@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g=="],
-
- "mdast-util-to-hast/unist-util-visit/unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="],
-
- "mdast-util-to-markdown/unist-util-visit/unist-util-is": ["unist-util-is@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g=="],
-
- "mdast-util-to-markdown/unist-util-visit/unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="],
-
- "tsup/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.7", "", { "os": "android", "cpu": "arm" }, "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ=="],
-
- "tsup/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.7", "", { "os": "android", "cpu": "arm64" }, "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ=="],
-
- "tsup/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.7", "", { "os": "android", "cpu": "x64" }, "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg=="],
-
- "tsup/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw=="],
-
- "tsup/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ=="],
-
- "tsup/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.7", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w=="],
-
- "tsup/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.7", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ=="],
+ "vscode-oniguruma": ["vscode-oniguruma@2.0.1", "", {}, "sha512-poJU8iHIWnC3vgphJnrLZyI3YdqRlR27xzqDmpPXYzA93R4Gk8z7T6oqDzDoHjoikA2aS82crdXFkjELCdJsjQ=="],
- "tsup/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.7", "", { "os": "linux", "cpu": "arm" }, "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA=="],
+ "vscode-textmate": ["vscode-textmate@9.3.2", "", {}, "sha512-n2uGbUcrjhUEBH16uGA0TvUfhWwliFZ1e3+pTjrkim1Mt7ydB41lV08aUvsi70OlzDWp6X7Bx3w/x3fAXIsN0Q=="],
- "tsup/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A=="],
+ "web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="],
- "tsup/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.7", "", { "os": "linux", "cpu": "ia32" }, "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg=="],
+ "whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="],
- "tsup/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q=="],
+ "ws": ["ws@8.21.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw=="],
- "tsup/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw=="],
-
- "tsup/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.7", "", { "os": "linux", "cpu": "ppc64" }, "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ=="],
-
- "tsup/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ=="],
-
- "tsup/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.7", "", { "os": "linux", "cpu": "s390x" }, "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw=="],
-
- "tsup/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.7", "", { "os": "linux", "cpu": "x64" }, "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA=="],
-
- "tsup/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.7", "", { "os": "none", "cpu": "x64" }, "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw=="],
-
- "tsup/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.7", "", { "os": "openbsd", "cpu": "x64" }, "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg=="],
-
- "tsup/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.7", "", { "os": "sunos", "cpu": "x64" }, "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA=="],
-
- "tsup/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA=="],
-
- "tsup/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.7", "", { "os": "win32", "cpu": "ia32" }, "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw=="],
-
- "tsup/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.7", "", { "os": "win32", "cpu": "x64" }, "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg=="],
-
- "vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ=="],
-
- "vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.28.2", "", { "os": "android", "cpu": "arm" }, "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg=="],
-
- "vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.2", "", { "os": "android", "cpu": "arm64" }, "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A=="],
-
- "vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.28.2", "", { "os": "android", "cpu": "x64" }, "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q=="],
-
- "vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw=="],
-
- "vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw=="],
-
- "vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw=="],
-
- "vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg=="],
-
- "vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.2", "", { "os": "linux", "cpu": "arm" }, "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w=="],
-
- "vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug=="],
-
- "vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ=="],
-
- "vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ=="],
-
- "vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA=="],
-
- "vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ=="],
-
- "vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA=="],
-
- "vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg=="],
-
- "vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.2", "", { "os": "linux", "cpu": "x64" }, "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ=="],
-
- "vite/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw=="],
-
- "vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.2", "", { "os": "none", "cpu": "x64" }, "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw=="],
-
- "vite/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ=="],
-
- "vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw=="],
-
- "vite/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q=="],
+ "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
- "vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g=="],
+ "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
- "vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ=="],
+ "@dom-expressions/babel-plugin-jsx/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="],
- "vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA=="],
+ "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
- "vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g=="],
+ "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
}
}
diff --git a/bunfig.toml b/bunfig.toml
new file mode 100644
index 0000000..8755352
--- /dev/null
+++ b/bunfig.toml
@@ -0,0 +1,2 @@
+[test]
+preload = ["./test/setup.ts"]
diff --git a/package.json b/package.json
index 6e998eb..ff442e0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,9 @@
{
- "name": "solid-markdown",
- "version": "2.1.1",
+ "name": "@rigelbuild/solid-markdown",
+ "version": "3.0.0-rc.0",
+ "publishConfig": {
+ "access": "public"
+ },
"description": "Markdown renderer for solid-js",
"license": "MIT",
"keywords": [
@@ -32,11 +35,11 @@
],
"repository": {
"type": "git",
- "url": "git+https://github.com/andi23rosca/solid-markdown.git"
+ "url": "git+https://github.com/RigelBuild/solid-markdown.git"
},
- "homepage": "https://github.com/andi23rosca/solid-markdown#readme",
+ "homepage": "https://github.com/RigelBuild/solid-markdown#readme",
"bugs": {
- "url": "https://github.com/andi23rosca/solid-markdown/issues"
+ "url": "https://github.com/RigelBuild/solid-markdown/issues"
},
"files": [
"dist"
@@ -52,17 +55,14 @@
},
"exports": {
"worker": {
- "solid": "./dist/server.jsx",
+ "solid": "./dist/index.jsx",
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/server.js"
}
},
"browser": {
- "solid": {
- "development": "./dist/dev.jsx",
- "import": "./dist/index.jsx"
- },
+ "solid": "./dist/index.jsx",
"development": {
"import": {
"types": "./dist/index.d.ts",
@@ -75,23 +75,20 @@
}
},
"deno": {
- "solid": "./dist/server.jsx",
+ "solid": "./dist/index.jsx",
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/server.js"
}
},
"node": {
- "solid": "./dist/server.jsx",
+ "solid": "./dist/index.jsx",
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/server.js"
}
},
- "solid": {
- "development": "./dist/dev.jsx",
- "import": "./dist/index.jsx"
- },
+ "solid": "./dist/index.jsx",
"development": {
"import": {
"types": "./dist/index.d.ts",
@@ -106,40 +103,48 @@
"typesVersions": {},
"scripts": {
"dev": "vite serve dev",
- "build": "tsup",
- "test": "bun test",
+ "build": "bun run build.ts && bun run smoke",
+ "smoke": "bun run scripts/smoke-dist.ts",
+ "test": "bun run test:client && bun run test:ssr",
+ "test:client": "SOLID_GENERATE=dom bun --conditions=browser --conditions=development test test/client.test.tsx",
+ "test:ssr": "SOLID_GENERATE=ssr bun --conditions=development test test/server.test.tsx",
"typecheck": "tsc --noEmit",
"lint": "biome check .",
"format": "biome format --write ."
},
"dependencies": {
- "comma-separated-tokens": "^2.0.3",
- "property-information": "^6.5.0",
+ "devlop": "^1.1.0",
+ "hast-util-to-jsx-runtime": "^2.3.6",
+ "html-url-attributes": "^3.0.1",
"remark-parse": "^11.0.0",
"remark-rehype": "^11.1.2",
- "space-separated-tokens": "^2.0.2",
- "style-to-object": "^0.3.0",
"unified": "^11.0.5",
- "unist-util-visit": "^4.1.2",
+ "unist-util-visit": "^5.1.0",
"vfile": "^6.0.3"
},
"peerDependencies": {
- "solid-js": "^1.6.0"
+ "@solidjs/web": "^2.0.0-rc.0",
+ "solid-js": "^2.0.0-rc.0"
},
"devDependencies": {
+ "@babel/core": "^7.28.4",
+ "@babel/preset-typescript": "^7.27.1",
"@biomejs/biome": "1.9.4",
+ "@happy-dom/global-registrator": "^20.0.0",
+ "@solidjs/testing-library": "1.0.0-beta.2",
+ "@solidjs/web": "2.0.0-rc.0",
"@types/bun": "^1.4.0",
- "@types/hast": "^2.3.10",
+ "@types/hast": "^3.0.4",
"@types/unist": "^3.0.3",
- "esbuild": "^0.18.20",
- "esbuild-plugin-solid": "^0.5.0",
+ "babel-preset-solid": "2.0.0-rc.0",
+ "rehype-raw": "^7.0.0",
+ "rehype-starry-night": "^2.2.0",
"remark-gfm": "^4.0.1",
- "solid-js": "^1.9.10",
- "tsup": "^8.5.1",
- "tsup-preset-solid": "^2.2.0",
+ "remark-toc": "^9.0.0",
+ "solid-js": "2.0.0-rc.0",
"typescript": "^5.9.3",
"vite": "^7.2.4",
- "vite-plugin-solid": "^2.11.10"
+ "vite-plugin-solid": "3.0.0-next.27"
},
"engines": {
"node": ">=18"
diff --git a/scripts/smoke-dist.ts b/scripts/smoke-dist.ts
new file mode 100644
index 0000000..5f46654
--- /dev/null
+++ b/scripts/smoke-dist.ts
@@ -0,0 +1,95 @@
+/**
+ * Post-build guard on the published `dist/`. `tsc`/`biome`/`bun test` never
+ * import `dist` (tests run against `src` through the babel harness), so without
+ * this check a dead-on-arrival artifact passes every other gate. Run after
+ * `build`, in CI and before publish.
+ *
+ * Two artifact shapes, two checks:
+ * - Compiled `.js` entries — import each and assert the public API resolves.
+ * A wrong-target build emits a bare runtime import for a subpath the peer
+ * removed (`solid-js/web`), throwing `ERR_PACKAGE_PATH_NOT_EXPORTED` on load.
+ * - The `.jsx` source entry backing the `solid` export condition — it ships
+ * untransformed JSX, so it cannot be imported directly. Instead compile it
+ * with `babel-preset-solid` exactly as a consuming app would and assert the
+ * result imports `@solidjs/web` and never a `jsx-dev-runtime`/`solid-js/web`
+ * subpath (the failure mode when a bundler's own JSX transform leaks in).
+ */
+
+import { transformAsync } from "@babel/core";
+// @ts-expect-error - babel-preset-solid ships no type declarations.
+import solid from "babel-preset-solid";
+
+const jsEntries = ["index.js", "dev.js", "server.js"] as const;
+const expected = [
+ "MarkdownAsync",
+ "MarkdownResource",
+ "default",
+ "defaultUrlTransform",
+] as const;
+const badSubpaths = ["solid-js/web", "@solidjs/web/jsx-dev-runtime", "jsxDEV"];
+
+let failed = false;
+
+function fail(entry: string, detail: string): void {
+ console.error(`✗ dist/${entry}: ${detail}`);
+ failed = true;
+}
+
+function errorDetail(error: unknown): string {
+ if (error && typeof error === "object" && "code" in error) {
+ return String(error.code);
+ }
+ return error instanceof Error ? error.message : String(error);
+}
+
+for (const entry of jsEntries) {
+ try {
+ const mod = await import(`../dist/${entry}`);
+ const missing = expected.filter((name) => !(name in mod));
+ if (missing.length > 0) {
+ fail(entry, `missing exports ${missing.join(", ")}`);
+ } else {
+ console.log(`✓ dist/${entry}`);
+ }
+ } catch (error) {
+ fail(entry, errorDetail(error));
+ }
+}
+
+// The `.jsx` source entry: it must ship real JSX (not a leaked runtime import),
+// and must compile through a consumer's Solid compiler to `@solidjs/web` calls.
+const jsxSource = await Bun.file("dist/index.jsx").text();
+const leaked = badSubpaths.find((s) => jsxSource.includes(s));
+if (leaked) {
+ fail("index.jsx", `ships a leaked runtime reference: ${leaked}`);
+} else if (!jsxSource.includes("<>")) {
+ fail("index.jsx", "no JSX found — the source variant was transformed away");
+} else {
+ try {
+ const compiled = await transformAsync(jsxSource, {
+ filename: "dist/index.jsx",
+ presets: [[solid, { generate: "dom", hydratable: true }]],
+ sourceMaps: false,
+ });
+ const code = compiled?.code ?? "";
+ const stillBad = badSubpaths.find((s) => code.includes(s));
+ if (stillBad) {
+ fail("index.jsx", `compiles to a bad runtime reference: ${stillBad}`);
+ } else if (!code.includes("@solidjs/web")) {
+ fail("index.jsx", "compiled output does not import @solidjs/web");
+ } else {
+ console.log("✓ dist/index.jsx (compiles to @solidjs/web)");
+ }
+ } catch (error) {
+ fail("index.jsx", `does not compile: ${errorDetail(error)}`);
+ }
+}
+
+if (failed) {
+ console.error("dist smoke check failed — the published bundle is broken.");
+ process.exit(1);
+}
+
+console.log(
+ `dist smoke check passed (${jsEntries.length} compiled + 1 source entry).`,
+);
diff --git a/src/index.tsx b/src/index.tsx
index 67ae7d5..5fcec9c 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,108 +1,378 @@
-import { html } from "property-information";
+import type { JSX } from "@solidjs/web";
+import { unreachable } from "devlop";
+import type { Element, Nodes, Parents } from "hast";
+import { toJsxRuntime } from "hast-util-to-jsx-runtime";
+import { urlAttributes } from "html-url-attributes";
import remarkParse from "remark-parse";
+import type { Options as RemarkRehypeOptions } from "remark-rehype";
import remarkRehype from "remark-rehype";
import {
- type Component,
createMemo,
createRenderEffect,
- mergeProps,
+ createSignal,
+ createStore,
+ reconcile,
} from "solid-js";
-import { createStore, reconcile } from "solid-js/store";
import { type PluggableList, unified } from "unified";
+import type { Node } from "unist";
+import { visit } from "unist-util-visit";
import { VFile } from "vfile";
-import type { Options as TransformOptions } from "./types";
+import { Fragment, jsx, jsxs } from "./jsx-runtime";
+import type { Components, MarkdownResourceOptions, Options } from "./types";
-import type { Root } from "hast";
-import rehypeFilter, { type Options as FilterOptions } from "./rehype-filter";
-import { MarkdownNode, MarkdownRoot } from "./renderer";
+const changelog =
+ "https://github.com/remarkjs/react-markdown/blob/main/changelog.md";
-type CoreOptions = {
- children: string;
- renderingStrategy: "memo" | "reconcile";
+const emptyPlugins: PluggableList = [];
+const emptyRemarkRehypeOptions: Readonly = {
+ allowDangerousHtml: true,
};
-type PluginOptions = {
- remarkPlugins: PluggableList;
- rehypePlugins: PluggableList;
-};
-type LayoutOptions = {
- class: string;
+const safeProtocol = /^(https?|ircs?|mailto|xmpp)$/i;
+
+type SyncOptions = {
+ renderingStrategy?: "memo" | "reconcile" | null | undefined;
};
-export type SolidMarkdownOptions = CoreOptions &
- PluginOptions &
- LayoutOptions &
- FilterOptions &
- TransformOptions;
-
-export type SolidMarkdownComponents = TransformOptions["components"];
-
-const defaults: SolidMarkdownOptions = {
- renderingStrategy: "memo",
- remarkPlugins: [],
- rehypePlugins: [],
- class: "",
- unwrapDisallowed: false,
- disallowedElements: undefined,
- allowedElements: undefined,
- allowElement: undefined,
- children: "",
- sourcePos: false,
- rawSourcePos: false,
- skipHtml: false,
- includeElementIndex: false,
- transformLinkUri: null,
- transformImageUri: undefined,
- linkTarget: "_self",
- components: {},
+type MarkdownOptions = Options & SyncOptions;
+
+type Deprecation = {
+ from: string;
+ id: string;
+ to?: string;
};
-export const SolidMarkdown: Component> = (
- opts,
-) => {
- const options: SolidMarkdownOptions = mergeProps(defaults, opts);
- const [node, setNode] = createStore({ type: "root", children: [] });
-
- const generateNode = createMemo(() => {
- const children = options.children;
- const processor = unified()
- .use(remarkParse)
- .use(options.remarkPlugins || [])
- .use(remarkRehype, { allowDangerousHtml: true })
- .use(options.rehypePlugins || [])
- .use(rehypeFilter, options);
-
- const file = new VFile();
-
- if (typeof children === "string") {
- file.value = children;
- } else if (children !== undefined && options.children !== null) {
- console.warn(
- `[solid-markdown] Warning: please pass a string as \`children\` (not: \`${typeof children}\`)`,
- );
- }
- const hastNode = processor.runSync(processor.parse(file), file);
+const deprecations: ReadonlyArray> = [
+ { from: "astPlugins", id: "remove-buggy-html-in-markdown-parser" },
+ { from: "allowDangerousHtml", id: "remove-buggy-html-in-markdown-parser" },
+ {
+ from: "allowNode",
+ id: "replace-allownode-allowedtypes-and-disallowedtypes",
+ to: "allowElement",
+ },
+ {
+ from: "allowedTypes",
+ id: "replace-allownode-allowedtypes-and-disallowedtypes",
+ to: "allowedElements",
+ },
+ { from: "class", id: "remove-classname" },
+ { from: "className", id: "remove-classname" },
+ {
+ from: "disallowedTypes",
+ id: "replace-allownode-allowedtypes-and-disallowedtypes",
+ to: "disallowedElements",
+ },
+ { from: "escapeHtml", id: "remove-buggy-html-in-markdown-parser" },
+ { from: "includeElementIndex", id: "#remove-includeelementindex" },
+ {
+ from: "includeNodeIndex",
+ id: "change-includenodeindex-to-includeelementindex",
+ },
+ { from: "linkTarget", id: "remove-linktarget" },
+ {
+ from: "plugins",
+ id: "change-plugins-to-remarkplugins",
+ to: "remarkPlugins",
+ },
+ { from: "rawSourcePos", id: "#remove-rawsourcepos" },
+ { from: "renderers", id: "change-renderers-to-components", to: "components" },
+ { from: "source", id: "change-source-to-children", to: "children" },
+ { from: "sourcePos", id: "#remove-sourcepos" },
+ { from: "transformImageUri", id: "#add-urltransform", to: "urlTransform" },
+ { from: "transformLinkUri", id: "#add-urltransform", to: "urlTransform" },
+];
+
+export type {
+ AllowElement,
+ Components,
+ ExtraProps,
+ MarkdownResourceOptions,
+ Options,
+ UrlTransform,
+} from "./types";
+
+export default function Markdown(
+ options: Readonly,
+): JSX.Element {
+ checkOptions(options);
+ const processor = createMemo(() => createProcessor(options));
+ const tree = createMemo(() => {
+ const file = createFile(options);
+ return processor().runSync(processor().parse(file), file);
+ });
+ const [reconciledTree, setReconciledTree] = createStore({
+ type: "root",
+ children: [],
+ } as Node);
+
+ createRenderEffect(
+ () =>
+ options.renderingStrategy === "reconcile" ? cloneTree(tree()) : undefined,
+ (next) => {
+ if (next) {
+ setReconciledTree(reconcile(next));
+ }
+ },
+ );
+
+ const rendered = createMemo(() => {
+ const nextTree =
+ options.renderingStrategy === "reconcile"
+ ? cloneReconciledTree(reconciledTree as unknown as Node)
+ : cloneTree(tree());
+
+ return post(nextTree, options);
+ });
+
+ return <>{rendered()}>;
+}
+
+export async function MarkdownAsync(
+ options: Readonly,
+): Promise {
+ checkOptions(options);
+
+ const processor = createProcessor(options);
+ const file = createFile(options);
+ const tree = await processor.run(processor.parse(file), file);
+
+ // Defer the JSX build into the consuming render root: Solid 2 constructs
+ // SSR elements against the current owner's hydration id, which exists only
+ // inside a render root. Building the tree eagerly here (at await time,
+ // outside any root) binds it to whatever ambient owner is active and throws
+ // under SSR. Wrapping the call in a deferred child mirrors the sync path's
+ // `<>{rendered()}>` and keeps the return a valid `JSX.Element`.
+ return <>{() => post(tree, options)}>;
+}
- if (hastNode.type !== "root") {
- throw new TypeError("Expected a `root` node");
+export function MarkdownResource(
+ options: Readonly,
+): JSX.Element {
+ checkOptions(options);
+
+ const snapshot = createMemo(() => ({
+ allowElement: options.allowElement,
+ allowedElements: options.allowedElements,
+ children: options.children,
+ components: options.components,
+ disallowedElements: options.disallowedElements,
+ rehypePlugins: options.rehypePlugins,
+ remarkPlugins: options.remarkPlugins,
+ remarkRehypeOptions: options.remarkRehypeOptions,
+ skipHtml: options.skipHtml,
+ unwrapDisallowed: options.unwrapDisallowed,
+ urlTransform: options.urlTransform,
+ }));
+ // Solid 2 gates signal writes inside an owned scope (the render effect
+ // below); these two are intentionally written from it, so opt in.
+ const [content, setContent] = createSignal(undefined, {
+ ownedWrite: true,
+ });
+ const [resourceError, setResourceError] = createSignal(undefined, {
+ ownedWrite: true,
+ });
+ let requestId = 0;
+
+ createRenderEffect(
+ () => snapshot(),
+ (currentOptions) => {
+ const currentRequestId = ++requestId;
+
+ setResourceError(undefined);
+
+ void (async () => {
+ try {
+ const processor = createProcessor(currentOptions);
+ const file = createFile(currentOptions);
+ const tree = await processor.run(processor.parse(file), file);
+
+ if (currentRequestId === requestId) {
+ setContent(tree);
+ }
+ } catch (error) {
+ if (currentRequestId === requestId) {
+ setResourceError(error);
+ }
+ }
+ })();
+ },
+ );
+
+ const rendered = createMemo(() => {
+ const error = resourceError();
+
+ if (error) {
+ throw error;
}
- return hastNode;
+ const tree = content();
+
+ return tree ? post(cloneTree(tree), options) : (options.fallback ?? null);
});
- if (options.renderingStrategy === "reconcile") {
- createRenderEffect(() => {
- setNode(reconcile(generateNode()));
- });
+ return <>{rendered()}>;
+}
+
+export function defaultUrlTransform(value: string): string {
+ const colon = value.indexOf(":");
+ const questionMark = value.indexOf("?");
+ const numberSign = value.indexOf("#");
+ const slash = value.indexOf("/");
+
+ if (
+ colon === -1 ||
+ (slash !== -1 && colon > slash) ||
+ (questionMark !== -1 && colon > questionMark) ||
+ (numberSign !== -1 && colon > numberSign) ||
+ safeProtocol.test(value.slice(0, colon))
+ ) {
+ return value;
}
- return (
- <>
-
-
-
- >
+ return "";
+}
+
+function createProcessor(options: Readonly) {
+ const rehypePlugins = options.rehypePlugins || emptyPlugins;
+ const remarkPlugins = options.remarkPlugins || emptyPlugins;
+ const remarkRehypeOptions = options.remarkRehypeOptions
+ ? { ...options.remarkRehypeOptions, ...emptyRemarkRehypeOptions }
+ : emptyRemarkRehypeOptions;
+
+ return unified()
+ .use(remarkParse)
+ .use(remarkPlugins)
+ .use(remarkRehype, remarkRehypeOptions)
+ .use(rehypePlugins);
+}
+
+function createFile(options: Readonly): VFile {
+ const children = options.children ?? "";
+ const file = new VFile();
+
+ if (typeof children === "string") {
+ file.value = children;
+ return file;
+ }
+
+ unreachable(
+ `Unexpected value \`${String(children)}\` for \`children\` prop, expected \`string\``,
);
-};
+
+ throw new TypeError("Unreachable");
+}
+
+function post(tree: Node, options: Readonly): JSX.Element {
+ const allowedElements = options.allowedElements;
+ const allowElement = options.allowElement;
+ const components = options.components;
+ const disallowedElements = options.disallowedElements;
+ const skipHtml = options.skipHtml;
+ const unwrapDisallowed = options.unwrapDisallowed;
+ const urlTransform = options.urlTransform || defaultUrlTransform;
+
+ if (allowedElements && disallowedElements) {
+ unreachable(
+ "Unexpected combined `allowedElements` and `disallowedElements`, expected one or the other",
+ );
+ }
+
+ visit(tree, transform);
+
+ return toJsxRuntime(tree as Nodes, {
+ Fragment,
+ components: components as Partial,
+ elementAttributeNameCase: "html",
+ ignoreInvalidStyle: true,
+ jsx,
+ jsxs,
+ passKeys: true,
+ passNode: true,
+ stylePropertyNameCase: "css",
+ tableCellAlignToStyle: true,
+ });
+
+ function transform(
+ node: Node,
+ index: number | undefined,
+ parent: Parents | undefined,
+ ) {
+ if (isRaw(node) && parent && typeof index === "number") {
+ if (skipHtml) {
+ parent.children.splice(index, 1);
+ } else {
+ parent.children[index] = { type: "text", value: node.value };
+ }
+
+ return index;
+ }
+
+ if (isElement(node)) {
+ for (const key in urlAttributes) {
+ if (hasOwn(urlAttributes, key) && hasOwn(node.properties, key)) {
+ const value = node.properties[key];
+ const test = urlAttributes[key as keyof typeof urlAttributes];
+
+ if (test === null || test?.includes(node.tagName)) {
+ node.properties[key] = urlTransform(String(value || ""), key, node);
+ }
+ }
+ }
+ }
+
+ if (isElement(node)) {
+ let remove = allowedElements
+ ? !allowedElements.includes(node.tagName)
+ : disallowedElements
+ ? disallowedElements.includes(node.tagName)
+ : false;
+
+ if (!remove && allowElement && typeof index === "number") {
+ remove = !allowElement(node, index, parent);
+ }
+
+ if (remove && parent && typeof index === "number") {
+ if (unwrapDisallowed && node.children) {
+ parent.children.splice(index, 1, ...node.children);
+ } else {
+ parent.children.splice(index, 1);
+ }
+
+ return index;
+ }
+ }
+ }
+}
+
+function checkOptions(
+ options: unknown,
+): asserts options is Readonly> {
+ for (const deprecation of deprecations) {
+ if (hasOwn(options, deprecation.from)) {
+ unreachable(
+ `Unexpected \`${deprecation.from}\` prop, ${
+ deprecation.to ? `use \`${deprecation.to}\` instead` : "remove it"
+ } (see <${changelog}#${deprecation.id}> for more info)`,
+ );
+ }
+ }
+}
+
+function cloneTree(tree: T): T {
+ return structuredClone(tree);
+}
+
+function cloneReconciledTree(tree: T): T {
+ return JSON.parse(JSON.stringify(tree)) as T;
+}
+
+function hasOwn(value: unknown, key: string): value is Record {
+ return Object.prototype.hasOwnProperty.call(value, key);
+}
+
+function isElement(node: Node): node is Element {
+ return node.type === "element";
+}
+
+function isRaw(node: Node): node is Node & { type: "raw"; value: string } {
+ return node.type === "raw";
+}
diff --git a/src/jsx-runtime.ts b/src/jsx-runtime.ts
new file mode 100644
index 0000000..c91ee2f
--- /dev/null
+++ b/src/jsx-runtime.ts
@@ -0,0 +1,30 @@
+import { Dynamic, type JSX } from "@solidjs/web";
+import { type Component, createComponent, merge } from "solid-js";
+
+/**
+ * Fork-local JSX runtime for `hast-util-to-jsx-runtime`, over Solid-2
+ * primitives. Replaces the Solid-1-bound third-party `solid-jsx` dependency
+ * (see the adopted design record, A2). Only the production runtime surface
+ * `hast-util-to-jsx-runtime` exercises is implemented — no `jsxDEV`, and none
+ * of solid-jsx's MDX-only machinery (`MDXProvider`, `useMDXComponents`, the
+ * `mjx-` compat cache).
+ */
+
+type Props = Record;
+
+export function Fragment(props: { children?: JSX.Element }): JSX.Element {
+ return props.children;
+}
+
+export function jsx(
+ type: string | Component,
+ props: Props,
+): JSX.Element {
+ if (typeof type === "string") {
+ return createComponent(Dynamic, merge(props, { component: type }));
+ }
+
+ return createComponent(type, props);
+}
+
+export const jsxs = jsx;
diff --git a/src/rehype-filter.ts b/src/rehype-filter.ts
deleted file mode 100644
index d0d1fb5..0000000
--- a/src/rehype-filter.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-import type { Element as HElement, Root as HRoot } from "hast";
-import type { Plugin } from "unified";
-import { visit } from "unist-util-visit";
-
-type AllowElement = (
- element: HElement,
- index: number,
- parent: HElement | HRoot,
-) => boolean | undefined;
-
-export type Options = {
- allowedElements?: string[];
- disallowedElements?: string[];
- allowElement?: AllowElement;
- unwrapDisallowed: boolean;
-};
-
-const rehypeFilter: Plugin<[Options], HRoot> = (options: Options) => {
- if (options.allowedElements && options.disallowedElements) {
- throw new TypeError(
- "Only one of `allowedElements` and `disallowedElements` should be defined",
- );
- }
-
- if (
- options.allowedElements ||
- options.disallowedElements ||
- options.allowElement
- ) {
- return (tree) => {
- visit(tree, "element", (node, index, parent_) => {
- const parent = parent_;
- if (parent === null) return;
-
- let remove: boolean | undefined;
-
- if (options.allowedElements) {
- remove = !options.allowedElements.includes(node.tagName);
- } else if (options.disallowedElements) {
- remove = options.disallowedElements.includes(node.tagName);
- }
-
- if (
- !remove &&
- options.allowElement &&
- typeof index === "number" &&
- parent
- ) {
- remove = !options.allowElement(node, index, parent);
- }
-
- if (remove && typeof index === "number" && parent) {
- if (options.unwrapDisallowed && node.children) {
- parent.children.splice(index, 1, ...node.children);
- } else {
- parent.children.splice(index, 1);
- }
-
- return index;
- }
-
- return undefined;
- });
- };
- }
-};
-export default rehypeFilter;
diff --git a/src/renderer.tsx b/src/renderer.tsx
deleted file mode 100644
index 43fab72..0000000
--- a/src/renderer.tsx
+++ /dev/null
@@ -1,286 +0,0 @@
-import type { Element, Root, Text } from "hast";
-import { svg } from "property-information";
-import { type Component, For, Match, Show, Switch, createMemo } from "solid-js";
-import { Dynamic } from "solid-js/web";
-import type { Context, SolidMarkdownNames } from "./types";
-import {
- addProperty,
- flattenPosition,
- getElementsBeforeCount,
- getInputElement,
-} from "./utils";
-const own = {}.hasOwnProperty;
-
-export const MarkdownRoot: Component<{
- context: Context;
- node: Root;
-}> = (props) => ;
-
-export const MarkdownChildren: Component<{
- context: Context;
- node: Element | Root;
-}> = (props) => (
-
- {(child, index) => (
-
-
-
-
-
-
-
-
- )}
-
-);
-
-export const MarkdownText: Component<{
- context: Context;
- node: Text;
- index: number;
- parent: Element | Root;
-}> = (props) => {
- const childProps = createMemo(() => {
- const context = { ...props.context };
- const options = context.options;
- const node = props.node;
- const parent = props.parent;
-
- const properties: Record = {
- parent,
- };
-
- // Nodes created by plugins do not have positional info, in which case we use
- // an object that matches the position interface.
- const position = node.position || {
- start: { line: null, column: null, offset: null },
- end: { line: null, column: null, offset: null },
- };
-
- const component =
- options.components && own.call(options.components, "text")
- ? options.components.text
- : null;
- const basic = typeof component === "string"; //|| component === React.Fragment;
-
- properties.key = [
- "text",
- position.start.line,
- position.start.column,
- props.index,
- ].join("-");
-
- // If `sourcePos` is given, pass source information (line/column info from markdown source).
- if (options.sourcePos) {
- properties["data-sourcepos"] = flattenPosition(position);
- }
-
- if (!basic && options.rawSourcePos) {
- properties.sourcePosition = node.position;
- }
-
- // // If `includeElementIndex` is given, pass node index info to components.
- // if (!basic && options.includeElementIndex) {
- // properties.index = getElementsBeforeCount(parent, node);
- // properties.siblingCount = getElementsBeforeCount(parent);
- // }
-
- if (!basic) {
- properties.node = node;
- }
-
- return { properties, context, component };
- });
-
- return (
-
-
-
- );
-};
-
-export const MarkdownNode: Component<{
- context: Context;
- node: Element;
- index: number;
- parent: Element | Root;
-}> = (props) => {
- const childProps = createMemo(() => {
- const context = { ...props.context };
- const options = context.options;
- const parentSchema = context.schema;
- const node = props.node;
- const name = node.tagName as SolidMarkdownNames;
- const parent = props.parent;
-
- const properties: Record = {};
- let schema = parentSchema;
- let property: string;
-
- if (parentSchema.space === "html" && name === "svg") {
- schema = svg;
- context.schema = schema;
- }
-
- if (node.properties) {
- for (property in node.properties) {
- if (own.call(node.properties, property)) {
- addProperty(properties, property, node.properties[property], context);
- }
- }
- }
-
- if (name === "ol" || name === "ul") {
- context.listDepth++;
- }
-
- if (name === "ol" || name === "ul") {
- context.listDepth--;
- }
-
- // Restore parent schema.
- context.schema = parentSchema;
-
- // Nodes created by plugins do not have positional info, in which case we use
- // an object that matches the position interface.
- const position = node.position || {
- start: { line: null, column: null, offset: null },
- end: { line: null, column: null, offset: null },
- };
-
- const component =
- options.components && own.call(options.components, name)
- ? options.components[name]
- : name;
- const basic = typeof component === "string"; //|| component === React.Fragment;
-
- properties.key = [
- name,
- position.start.line,
- position.start.column,
- props.index,
- ].join("-");
-
- if (name === "a" && options.linkTarget) {
- properties.target =
- typeof options.linkTarget === "function"
- ? options.linkTarget(
- String(properties.href || ""),
- node.children,
- typeof properties.title === "string"
- ? properties.title
- : undefined,
- )
- : options.linkTarget;
- }
-
- if (name === "a" && options.transformLinkUri) {
- properties.href = options.transformLinkUri(
- String(properties.href || ""),
- node.children,
- typeof properties.title === "string" ? properties.title : undefined,
- );
- }
-
- if (
- !basic &&
- name === "code" &&
- parent.type === "element" &&
- parent.tagName !== "pre"
- ) {
- properties.inline = true;
- }
-
- if (
- !basic &&
- (name === "h1" ||
- name === "h2" ||
- name === "h3" ||
- name === "h4" ||
- name === "h5" ||
- name === "h6")
- ) {
- properties.level = Number.parseInt(name.charAt(1), 10);
- }
-
- if (name === "img" && options.transformImageUri) {
- properties.src = options.transformImageUri(
- String(properties.src || ""),
- String(properties.alt || ""),
- typeof properties.title === "string" ? properties.title : undefined,
- );
- }
-
- if (!basic && name === "li" && parent.type === "element") {
- const input = getInputElement(node);
- properties.checked = input?.properties
- ? Boolean(input.properties.checked)
- : null;
- properties.index = getElementsBeforeCount(parent, node);
- properties.ordered = parent.tagName === "ol";
- }
-
- if (!basic && (name === "ol" || name === "ul")) {
- properties.ordered = name === "ol";
- properties.depth = context.listDepth;
- }
-
- if (name === "td" || name === "th") {
- if (properties.align) {
- if (!properties.style) properties.style = {};
- // @ts-expect-error assume `style` is an object
- properties.style.textAlign = properties.align;
- // biome-ignore lint/performance/noDelete:
- delete properties.align;
- }
-
- if (!basic) {
- properties.isHeader = name === "th";
- }
- }
-
- if (!basic && name === "tr" && parent.type === "element") {
- properties.isHeader = Boolean(parent.tagName === "thead");
- }
-
- // If `sourcePos` is given, pass source information (line/column info from markdown source).
- if (options.sourcePos) {
- properties["data-sourcepos"] = flattenPosition(position);
- }
-
- if (!basic && options.rawSourcePos) {
- properties.sourcePosition = node.position;
- }
-
- // If `includeElementIndex` is given, pass node index info to components.
- if (!basic && options.includeElementIndex) {
- properties.index = getElementsBeforeCount(parent, node);
- properties.siblingCount = getElementsBeforeCount(parent);
- }
-
- if (!basic) {
- properties.node = node;
- }
-
- return { properties, context, component };
- });
-
- return (
-
-
-
- );
-};
diff --git a/src/types.ts b/src/types.ts
index c3d1679..8d38c48 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -1,120 +1,44 @@
-import type { Element, ElementContent, Text } from "hast";
-import type { Schema } from "property-information";
-import type { Component, JSX } from "solid-js";
-import type { Position } from "unist";
+import type { JSX } from "@solidjs/web";
+import type { Element, Parents } from "hast";
+import type { Options as RemarkRehypeOptions } from "remark-rehype";
+import type { PluggableList } from "unified";
-/* File for types which are not handled correctly in JSDoc mode */
+export type AllowElement = (
+ element: Readonly,
+ index: number,
+ parent: Readonly | undefined,
+) => boolean | null | undefined;
-export interface SolidMarkdownProps {
- node: Element;
- children: Component[];
- /**
- * Passed when `options.rawSourcePos` is given
- */
- sourcePosition?: Position;
- /**
- * Passed when `options.includeElementIndex` is given
- */
- index?: number;
- /**
- * Passed when `options.includeElementIndex` is given
- */
- siblingCount?: number;
-}
-
-export type NormalComponents = {
- [TagName in keyof JSX.IntrinsicElements]:
- | keyof JSX.IntrinsicElements
- | Component;
-};
-export type Raw = {
- type: "raw";
- value: string;
-};
-export type Context = {
- options: Options;
- schema: Schema;
- listDepth: number;
-};
-type TransformLink = (
- href: string,
- children: ElementContent[],
- title?: string,
-) => string;
-type TransformImage = (src: string, alt: string, title?: string) => string;
-type TransformLinkTargetType =
- | "_self"
- | "_blank"
- | "_parent"
- | "_top"
- | (string & {});
-type TransformLinkTarget = (
- href: string,
- children: ElementContent[],
- title?: string,
-) => TransformLinkTargetType | undefined;
-export type SolidMarkdownNames = keyof JSX.IntrinsicElements;
-type CodeComponent = Component<
- JSX.IntrinsicElements["code"] & SolidMarkdownProps & { inline?: boolean }
->;
-type HeadingComponent = Component<
- JSX.IntrinsicElements["h1"] & SolidMarkdownProps & { level: number }
->;
-type LiComponent = Component<
- JSX.IntrinsicElements["li"] &
- SolidMarkdownProps & {
- checked: boolean | null;
- index: number;
- ordered: boolean;
- }
->;
-type OrderedListComponent = Component<
- JSX.IntrinsicElements["ol"] &
- SolidMarkdownProps & { depth: number; ordered: true }
->;
-type TableCellComponent = Component<
- JSX.IntrinsicElements["table"] &
- SolidMarkdownProps & { style?: Record; isHeader: boolean }
->;
-type TableRowComponent = Component<
- JSX.IntrinsicElements["tr"] & SolidMarkdownProps & { isHeader: boolean }
->;
-type UnorderedListComponent = Component<
- JSX.IntrinsicElements["ul"] &
- SolidMarkdownProps & { depth: number; ordered: false }
->;
-type SpecialComponents = {
- code: CodeComponent | SolidMarkdownNames;
- h1: HeadingComponent | SolidMarkdownNames;
- h2: HeadingComponent | SolidMarkdownNames;
- h3: HeadingComponent | SolidMarkdownNames;
- h4: HeadingComponent | SolidMarkdownNames;
- h5: HeadingComponent | SolidMarkdownNames;
- h6: HeadingComponent | SolidMarkdownNames;
- li: LiComponent | SolidMarkdownNames;
- ol: OrderedListComponent | SolidMarkdownNames;
- td: TableCellComponent | SolidMarkdownNames;
- th: TableCellComponent | SolidMarkdownNames;
- tr: TableRowComponent | SolidMarkdownNames;
- ul: UnorderedListComponent | SolidMarkdownNames;
+export type ExtraProps = {
+ node?: Element | undefined;
};
-export type Components = Omit<
- Partial> &
- Partial,
- "text"
-> & {
- text?: Component<{
- node: Text;
- }>;
+
+export type Components = {
+ [Key in keyof JSX.IntrinsicElements]?:
+ | ((props: JSX.IntrinsicElements[Key] & ExtraProps) => JSX.Element)
+ | keyof JSX.IntrinsicElements;
};
+export type UrlTransform = (
+ url: string,
+ key: string,
+ node: Readonly,
+) => string | null | undefined;
+
export type Options = {
- sourcePos: boolean;
- rawSourcePos: boolean;
- skipHtml: boolean;
- includeElementIndex: boolean;
- transformLinkUri: null | false | TransformLink;
- transformImageUri?: TransformImage;
- linkTarget: TransformLinkTargetType | TransformLinkTarget;
- components: Components;
+ allowElement?: AllowElement | null | undefined;
+ allowedElements?: ReadonlyArray | null | undefined;
+ children?: string | null | undefined;
+ components?: Components | null | undefined;
+ disallowedElements?: ReadonlyArray | null | undefined;
+ rehypePlugins?: PluggableList | null | undefined;
+ remarkPlugins?: PluggableList | null | undefined;
+ remarkRehypeOptions?: Readonly | null | undefined;
+ skipHtml?: boolean | null | undefined;
+ unwrapDisallowed?: boolean | null | undefined;
+ urlTransform?: UrlTransform | null | undefined;
+};
+
+export type MarkdownResourceOptions = Options & {
+ fallback?: JSX.Element | null | undefined;
};
diff --git a/src/utils.test.ts b/src/utils.test.ts
deleted file mode 100644
index a89bc25..0000000
--- a/src/utils.test.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import { describe, expect, test } from "bun:test";
-import type { Element, Root } from "hast";
-import {
- flattenPosition,
- getElementsBeforeCount,
- getInputElement,
-} from "./utils";
-
-const el = (tagName: string, children: Element["children"] = []): Element => ({
- type: "element",
- tagName,
- properties: {},
- children,
-});
-
-const root = (children: Root["children"]): Root => ({
- type: "root",
- children,
-});
-
-describe("flattenPosition", () => {
- test("joins start/end line:column into a single string", () => {
- expect(
- flattenPosition({
- start: { line: 1, column: 2, offset: 0 },
- end: { line: 3, column: 4, offset: 10 },
- }),
- ).toBe("1:2-3:4");
- });
-
- test("renders null coordinates as the literal 'null'", () => {
- expect(
- flattenPosition({
- start: { line: null, column: null, offset: null },
- end: { line: null, column: null, offset: null },
- }),
- ).toBe("null:null-null:null");
- });
-});
-
-describe("getInputElement", () => {
- test("returns the first input child", () => {
- const input = el("input");
- expect(getInputElement(root([el("span"), input, el("input")]))).toBe(input);
- });
-
- test("returns null when no input child exists", () => {
- expect(getInputElement(root([el("span"), el("div")]))).toBeNull();
- });
-});
-
-describe("getElementsBeforeCount", () => {
- test("counts element siblings before the target node", () => {
- const target = el("em");
- const parent = el("p", [el("span"), el("strong"), target, el("span")]);
- expect(getElementsBeforeCount(parent, target)).toBe(2);
- });
-
- test("counts all element children when the target is absent", () => {
- const parent = el("p", [el("span"), el("strong")]);
- expect(getElementsBeforeCount(parent)).toBe(2);
- });
-});
diff --git a/src/utils.ts b/src/utils.ts
deleted file mode 100644
index 8e5c461..0000000
--- a/src/utils.ts
+++ /dev/null
@@ -1,85 +0,0 @@
-import { stringify as commas } from "comma-separated-tokens";
-import type { Element, Root } from "hast";
-import { find } from "property-information";
-import { stringify as spaces } from "space-separated-tokens";
-import type { Position } from "unist";
-import type { Context } from "./types";
-
-export function getInputElement(node: Element | Root): Element | null {
- let index = -1;
-
- while (++index < node.children.length) {
- const child = node.children[index];
-
- if (child?.type === "element" && child?.tagName === "input") {
- return child;
- }
- }
-
- return null;
-}
-export function getElementsBeforeCount(
- parent: Element | Root,
- node?: Element,
-): number {
- let index = -1;
- let count = 0;
-
- while (++index < parent.children.length) {
- if (parent.children[index] === node) break;
- if (parent.children[index]?.type === "element") count++;
- }
-
- return count;
-}
-export function addProperty(
- props: Record,
- prop: string,
- value: unknown,
- ctx: Context,
-) {
- const info = find(ctx.schema, prop);
- let result = value;
-
- if (info.property === "className") {
- info.property = "class";
- }
-
- // Ignore nullish and `NaN` values.
- // biome-ignore lint/suspicious/noSelfCompare: result !== result is an intentional NaN check
- if (result === null || result === undefined || result !== result) {
- return;
- }
-
- // Accept `array`.
- // Most props are space-separated.
- if (Array.isArray(result)) {
- result = info.commaSeparated ? commas(result) : spaces(result);
- }
-
- if (info.space && info.property) {
- props[info.property] = result;
- } else if (info.attribute) {
- props[info.attribute] = result;
- }
-}
-export function flattenPosition(
- pos:
- | Position
- | {
- start: { line: null; column: null; offset: null };
- end: { line: null; column: null; offset: null };
- },
-): string {
- return [
- pos.start.line,
- ":",
- pos.start.column,
- "-",
- pos.end.line,
- ":",
- pos.end.column,
- ]
- .map((d) => String(d))
- .join("");
-}
diff --git a/test/client.test.tsx b/test/client.test.tsx
new file mode 100644
index 0000000..85030e7
--- /dev/null
+++ b/test/client.test.tsx
@@ -0,0 +1,294 @@
+import { afterEach, describe, expect, it, vi } from "bun:test";
+import { render, waitFor } from "@solidjs/testing-library";
+import type { JSX } from "@solidjs/web";
+import type { Root } from "hast";
+import rehypeStarryNight from "rehype-starry-night";
+import remarkGfm from "remark-gfm";
+import { Errored, createSignal } from "solid-js";
+import type { Plugin } from "unified";
+import Markdown, { MarkdownResource } from "../src";
+import { deferPlugin, normalizeHtml } from "./helpers";
+
+afterEach(() => {
+ vi.restoreAllMocks();
+});
+
+describe("solid-markdown (client)", () => {
+ describe("core rendering", () => {
+ it("renders markdown in the browser", () => {
+ const result = render(() => );
+ expect(result.container.innerHTML).toBe("a
");
+ });
+
+ it("matches representative SSR output", () => {
+ const markdown = "# a\n\n* b\n\n[a](https://example.com)";
+ const result = render(() => );
+
+ expect(normalizeHtml(result.container.innerHTML)).toBe(
+ 'a \n\na
',
+ );
+ });
+ });
+
+ describe("renderingStrategy compatibility", () => {
+ it("renders correctly across memo and reconcile updates without warning", async () => {
+ const warn = vi
+ .spyOn(console, "warn")
+ .mockImplementation(() => undefined);
+ let setValue!: (value: string) => void;
+ let setStrategy!: (value: "memo" | "reconcile") => void;
+ const result = render(() => {
+ const [value, updateValue] = createSignal("*a*");
+ const [strategy, updateStrategy] = createSignal<"memo" | "reconcile">(
+ "memo",
+ );
+
+ setValue = updateValue;
+ setStrategy = updateStrategy;
+
+ return (
+
+ );
+ });
+
+ expect(result.container.innerHTML).toBe("a
");
+
+ setValue("**b**");
+ await waitFor(() => {
+ expect(result.container.innerHTML).toBe("b
");
+ });
+
+ setStrategy("reconcile");
+ setValue("c");
+ await waitFor(() => {
+ expect(result.container.innerHTML).toBe("c
");
+ });
+
+ render(() => );
+
+ expect(warn).not.toHaveBeenCalled();
+ });
+
+ // Characterizes the DOM-rebuild R1 turns on: under `reconcile`, #44's
+ // renderer re-runs `post()` + `toJsxRuntime` over a fresh clone of the
+ // reconciled tree on every changed tick, so `toJsxRuntime`'s eager DOM
+ // build replaces node identity even for a subtree whose markup is
+ // unchanged. This is deterministic — the signal drives Solid's
+ // synchronous reactivity, no timers.
+ it("rebuilds DOM node identity on a reconcile growth tick", async () => {
+ let setValue!: (value: string) => void;
+ const result = render(() => {
+ const [value, updateValue] = createSignal("first paragraph");
+ setValue = updateValue;
+ return ;
+ });
+
+ const firstParagraph = result.container.querySelector("p");
+ expect(firstParagraph).not.toBeNull();
+ expect(firstParagraph?.textContent).toBe("first paragraph");
+
+ // Grow the source by one tick: append a second paragraph below the
+ // first. The first paragraph's markup is unchanged.
+ setValue("first paragraph\n\nsecond paragraph");
+ await waitFor(() => {
+ expect(result.container.querySelectorAll("p")).toHaveLength(2);
+ });
+
+ const rebuiltParagraph = result.container.querySelector("p");
+ expect(rebuiltParagraph?.textContent).toBe("first paragraph");
+ // The rebuild replaced the node: same markup, new DOM identity.
+ expect(rebuiltParagraph).not.toBe(firstParagraph);
+ });
+ });
+
+ describe("async behavior", () => {
+ it("supports MarkdownResource fallback and resolution", async () => {
+ const plugin = deferPlugin();
+ const result = render(() => (
+
+ ));
+
+ expect(result.container.innerHTML).toBe("Loading");
+
+ plugin.resolve();
+
+ await waitFor(() => {
+ expect(result.container.innerHTML).toBe("a
");
+ });
+ });
+
+ it("supports async plugins in MarkdownResource", async () => {
+ const plugin = deferPlugin();
+ const result = render(() => (
+
+ ));
+
+ expect(result.container.innerHTML).toBe("Loading");
+
+ plugin.resolve();
+
+ await waitFor(() => {
+ expect(result.container.innerHTML).toContain('class="pl-en"');
+ expect(result.container.innerHTML).toContain("console");
+ });
+ });
+
+ it("surfaces initial MarkdownResource errors through ErrorBoundary", async () => {
+ const plugin = deferPlugin();
+ const result = render(() => (
+ {
+ const err = error();
+ return (
+
+ Error: {err instanceof Error ? err.message : String(err)}
+
+ );
+ }}
+ >
+
+
+ ));
+
+ expect(result.container.innerHTML).toBe("");
+
+ plugin.reject(new Error("rejected"));
+
+ await waitFor(() => {
+ expect(result.container.innerHTML).toBe("Error: rejected ");
+ });
+ });
+
+ it("keeps the latest rerender when async work overlaps before first success", async () => {
+ const pluginA = deferPlugin();
+ const pluginB = deferPlugin();
+ const harness = renderResourceHarness({
+ children: "a",
+ fallback: "Loading",
+ plugin: pluginA.plugin,
+ });
+
+ expect(harness.result.container.innerHTML).toBe("Loading");
+
+ harness.setChildren("b");
+ harness.setPlugin(pluginB.plugin);
+
+ expect(harness.result.container.innerHTML).toBe("Loading");
+
+ pluginA.resolve();
+ pluginB.resolve();
+
+ await waitFor(() => {
+ expect(harness.result.container.innerHTML).toBe("b
");
+ });
+ });
+
+ it("keeps previous content visible while a refresh is pending, then replaces it", async () => {
+ const pluginA = deferPlugin();
+ const pluginB = deferPlugin();
+ const harness = renderResourceHarness({
+ children: "a",
+ fallback: "Loading",
+ plugin: pluginA.plugin,
+ });
+
+ pluginA.resolve();
+
+ await waitFor(() => {
+ expect(harness.result.container.innerHTML).toBe("a
");
+ });
+
+ harness.setChildren("b");
+ harness.setPlugin(pluginB.plugin);
+
+ expect(harness.result.container.innerHTML).toBe("a
");
+
+ pluginB.resolve();
+
+ await waitFor(() => {
+ expect(harness.result.container.innerHTML).toBe("b
");
+ });
+ });
+
+ it("supports switching from async to sync rendering after prior success", async () => {
+ const plugin = deferPlugin();
+ const harness = renderResourceHarness({
+ children: "a",
+ fallback: "Loading",
+ plugin: plugin.plugin,
+ });
+
+ plugin.resolve();
+
+ await waitFor(() => {
+ expect(harness.result.container.innerHTML).toBe("a
");
+ });
+
+ harness.setChildren("b");
+ harness.setPlugin(undefined);
+
+ await waitFor(() => {
+ expect(harness.result.container.innerHTML).toBe("b
");
+ });
+ });
+
+ it("supports empty markdown rerenders", async () => {
+ const harness = renderResourceHarness({ children: "a" });
+
+ await waitFor(() => {
+ expect(harness.result.container.innerHTML).toBe("a
");
+ });
+
+ harness.setChildren("");
+
+ await waitFor(() => {
+ expect(harness.result.container.innerHTML).toBe("");
+ });
+ });
+ });
+});
+
+function renderResourceHarness(initial: {
+ children: string;
+ fallback?: JSX.Element;
+ plugin?: Plugin<[], Root>;
+}) {
+ let setChildren!: (value: string) => void;
+ let setFallback!: (value: JSX.Element | undefined) => void;
+ let setPlugin!: (value: Plugin<[], Root> | undefined) => void;
+
+ const result = render(() => {
+ const [children, updateChildren] = createSignal(initial.children);
+ const [fallback, updateFallback] = createSignal(initial.fallback);
+ const [plugin, updatePlugin] = createSignal<{
+ value: Plugin<[], Root> | undefined;
+ }>({ value: initial.plugin });
+
+ setChildren = updateChildren;
+ setFallback = updateFallback;
+ setPlugin = (value) => updatePlugin({ value });
+
+ const activePlugin = plugin().value;
+ return (
+
+ );
+ });
+
+ return { result, setChildren, setFallback, setPlugin };
+}
diff --git a/test/helpers.tsx b/test/helpers.tsx
new file mode 100644
index 0000000..8186d13
--- /dev/null
+++ b/test/helpers.tsx
@@ -0,0 +1,89 @@
+import { type JSX, NoHydration, renderToString } from "@solidjs/web";
+import type { Root, RootContent } from "hast";
+import type { Plugin } from "unified";
+
+type DeferredPlugin = {
+ plugin: Plugin<[], Root>;
+ reject: (error: Error) => void;
+ resolve: () => void;
+};
+
+const decoder = new TextDecoder();
+
+export function normalizeHtml(value: string): string {
+ return (
+ value
+ .replace(/\sdata-hk="[^"]*"/g, "")
+ // Solid 2 SSR emits `_hk=N` hydration keys and `` boundary
+ // markers between dynamic siblings; both are hydration plumbing with no
+ // semantic content, so drop them for static HTML comparison.
+ .replace(/\s_hk=\d+/g, "")
+ .replace(//g, "")
+ .replace(/ class="([^"]*?)\s+"/g, ' class="$1"')
+ .replace(/\s+>/g, ">")
+ .trim()
+ );
+}
+
+export function renderSync(code: () => JSX.Element): string {
+ // These tests compare static HTML strings and never hydrate, so render
+ // under `NoHydration` to drop most of Solid 2's hydration output; the
+ // residual `_hk`/marker artifacts are stripped in `normalizeHtml`.
+ return normalizeHtml(
+ renderToString(() => {code()} ),
+ );
+}
+
+export async function readStream(stream: {
+ pipeTo: (writable: WritableStream) => Promise | void;
+}): Promise {
+ let result = "";
+
+ await Promise.resolve(
+ stream.pipeTo(
+ new WritableStream({
+ write(chunk) {
+ result +=
+ typeof chunk === "string"
+ ? chunk
+ : decoder.decode(chunk, { stream: true });
+ },
+ }),
+ ),
+ );
+
+ return normalizeHtml(result + decoder.decode());
+}
+
+export function prependNodes(...nodes: RootContent[]): Plugin<[], Root> {
+ return function plugin() {
+ return (tree) => {
+ tree.children.unshift(...nodes);
+ };
+ };
+}
+
+export function deferPlugin(): DeferredPlugin {
+ let resolvePromise!: () => void;
+ let rejectPromise!: (error: Error) => void;
+ const promise = new Promise((resolve, reject) => {
+ resolvePromise = resolve;
+ rejectPromise = reject;
+ });
+ void promise.catch(() => undefined);
+
+ return {
+ plugin() {
+ return async (tree) => {
+ await promise;
+ return tree;
+ };
+ },
+ reject(error) {
+ rejectPromise(error);
+ },
+ resolve() {
+ resolvePromise();
+ },
+ };
+}
diff --git a/test/server.test.tsx b/test/server.test.tsx
new file mode 100644
index 0000000..49ea460
--- /dev/null
+++ b/test/server.test.tsx
@@ -0,0 +1,740 @@
+import { describe, expect, it } from "bun:test";
+import { type JSX, renderToStream } from "@solidjs/web";
+import type { RootContent } from "hast";
+import rehypeRaw from "rehype-raw";
+import rehypeStarryNight from "rehype-starry-night";
+import remarkGfm from "remark-gfm";
+import remarkToc from "remark-toc";
+import type { Component } from "solid-js";
+import { visit } from "unist-util-visit";
+import Markdown, { MarkdownAsync, defaultUrlTransform } from "../src";
+import { prependNodes, readStream, renderSync } from "./helpers";
+
+describe("solid-markdown (server)", () => {
+ it("exposes the public api", async () => {
+ const keys = Object.keys(await import("../src"))
+ // Vite's SSR transform injects internal `$$`-prefixed bindings
+ // (e.g. `$$moduleUrl`); they are not part of the package surface.
+ .filter((key) => !key.startsWith("$$"))
+ .sort();
+ expect(keys).toEqual([
+ "MarkdownAsync",
+ "MarkdownResource",
+ "default",
+ "defaultUrlTransform",
+ ]);
+ });
+
+ describe("core rendering", () => {
+ it("renders basic markdown and nullish children", () => {
+ expect(renderSync(() => a )).toBe("a
");
+ expect(renderSync(() => )).toBe("");
+ expect(renderSync(() => )).toBe("");
+ });
+
+ it("throws on invalid children", () => {
+ expect(() =>
+ renderSync(() => ),
+ ).toThrow(/Unexpected value `1` for `children` prop, expected `string`/);
+ expect(() =>
+ renderSync(() => ),
+ ).toThrow(
+ /Unexpected value `true` for `children` prop, expected `string`/,
+ );
+ });
+
+ it("supports markdown syntax parity cases", () => {
+ expect(renderSync(() => )).toBe(
+ "\na
\n ",
+ );
+ expect(renderSync(() => )).toBe(
+ "a \nb
",
+ );
+ expect(renderSync(() => )).toBe(
+ "a\n ",
+ );
+ expect(renderSync(() => )).toBe(
+ 'a\n ',
+ );
+ expect(
+ renderSync(() => (
+
+ )),
+ ).toBe("a
");
+ expect(renderSync(() => )).toBe(
+ "a
",
+ );
+ expect(renderSync(() => )).toBe("a ");
+ expect(renderSync(() => )).toBe(
+ "a
",
+ );
+ expect(renderSync(() => )).toBe(
+ "",
+ );
+ expect(renderSync(() => )).toBe(
+ "\na \n ",
+ );
+ expect(renderSync(() => )).toBe(
+ "a
",
+ );
+ expect(renderSync(() => )).toBe(" ");
+ });
+
+ it("supports footnotes, images, links, and definitions", () => {
+ expect(
+ renderSync(() => (
+
+ )),
+ ).toContain('href="#user-content-fn-x"');
+ expect(renderSync(() => )).toBe(
+ '
',
+ );
+ expect(renderSync(() => )).toBe(
+ '
',
+ );
+ expect(renderSync(() => )).toBe(
+ '
',
+ );
+ expect(renderSync(() => )).toBe(
+ 'a
',
+ );
+ expect(renderSync(() => )).toBe(
+ 'a
',
+ );
+ expect(renderSync(() => )).toBe(
+ 'a
',
+ );
+ expect(
+ renderSync(() => (
+
+ )),
+ ).toBe('
');
+ expect(
+ renderSync(() => ),
+ ).toBe('a
');
+ });
+
+ it("supports raw html behavior and tables", () => {
+ expect(renderSync(() => )).toBe(
+ "<i>a</i>
",
+ );
+ expect(
+ renderSync(() => (
+
+ )),
+ ).toBe("a
");
+ expect(
+ renderSync(() => ),
+ ).toBe("abc
");
+ expect(
+ renderSync(() => (
+
+ )),
+ ).toBe(
+ "",
+ );
+ expect(
+ renderSync(() => (
+
+ )),
+ ).toBe(
+ '',
+ );
+ });
+ });
+
+ describe("url safety", () => {
+ it("supports safe URLs and sanitizes unsafe ones", () => {
+ expect(renderSync(() => )).toBe(
+ '
',
+ );
+ expect(renderSync(() => )).toBe(
+ '
',
+ );
+ expect(renderSync(() => )).toBe(
+ '
',
+ );
+ expect(
+ renderSync(() => ),
+ ).toBe("
");
+ expect(
+ renderSync(() => ),
+ ).toBe("
");
+ expect(
+ renderSync(() => ),
+ ).toBe("
");
+ expect(
+ renderSync(() => ),
+ ).toBe("
");
+ expect(renderSync(() => )).toBe(
+ "
",
+ );
+ expect(
+ renderSync(() => ),
+ ).toBe('
');
+ expect(renderSync(() => )).toBe(
+ '
',
+ );
+ expect(
+ renderSync(() => ),
+ ).toBe('
');
+ });
+
+ it("supports urlTransform for href, empty URLs, and src", () => {
+ expect(
+ renderSync(() => (
+ {
+ expect(url).toBe("https://b.com");
+ expect(key).toBe("href");
+ expect(node.tagName).toBe("a");
+ return "";
+ }}
+ />
+ )),
+ ).toBe('a
');
+ expect(
+ renderSync(() => (
+ {
+ expect(url).toBe("");
+ expect(key).toBe("href");
+ expect(node.tagName).toBe("a");
+ return "";
+ }}
+ />
+ )),
+ ).toBe("
");
+ expect(
+ renderSync(() => (
+ {
+ expect(url).toBe("https://b.com");
+ expect(key).toBe("src");
+ expect(node.tagName).toBe("img");
+ return null;
+ }}
+ />
+ )),
+ ).toBe('
');
+ });
+
+ it("covers defaultUrlTransform edge cases directly", () => {
+ expect(defaultUrlTransform("javascript:alert(1)")).toBe("");
+ expect(defaultUrlTransform("vbscript:alert(1)")).toBe("");
+ expect(defaultUrlTransform("file:///etc/passwd")).toBe("");
+ expect(defaultUrlTransform("HTTPS://A.COM")).toBe("HTTPS://A.COM");
+ expect(defaultUrlTransform("/a")).toBe("/a");
+ expect(defaultUrlTransform("a?javascript:alert(1)")).toBe(
+ "a?javascript:alert(1)",
+ );
+ });
+ });
+
+ describe("removed props", () => {
+ it("throws for removed props with migration messages", () => {
+ const cases: ReadonlyArray<[string, Record, RegExp]> = [
+ [
+ "source",
+ { source: "a" },
+ /Unexpected `source` prop, use `children` instead/,
+ ],
+ [
+ "class",
+ { class: "markdown-body", children: "a" },
+ /Unexpected `class` prop, remove it/,
+ ],
+ [
+ "className",
+ { className: "markdown-body", children: "a" },
+ /Unexpected `className` prop, remove it/,
+ ],
+ [
+ "allowDangerousHtml",
+ { allowDangerousHtml: true, children: "a" },
+ /Unexpected `allowDangerousHtml` prop, remove it/,
+ ],
+ [
+ "plugins",
+ { plugins: [], children: "a" },
+ /Unexpected `plugins` prop, use `remarkPlugins` instead/,
+ ],
+ [
+ "renderers",
+ { renderers: {}, children: "a" },
+ /Unexpected `renderers` prop, use `components` instead/,
+ ],
+ [
+ "allowNode",
+ { allowNode: () => true, children: "a" },
+ /Unexpected `allowNode` prop, use `allowElement` instead/,
+ ],
+ [
+ "allowedTypes",
+ { allowedTypes: ["p"], children: "a" },
+ /Unexpected `allowedTypes` prop, use `allowedElements` instead/,
+ ],
+ [
+ "disallowedTypes",
+ { disallowedTypes: ["em"], children: "a" },
+ /Unexpected `disallowedTypes` prop, use `disallowedElements` instead/,
+ ],
+ [
+ "linkTarget",
+ { linkTarget: "_blank", children: "a" },
+ /Unexpected `linkTarget` prop, remove it/,
+ ],
+ [
+ "transformImageUri",
+ { transformImageUri: () => "", children: "a" },
+ /Unexpected `transformImageUri` prop, use `urlTransform` instead/,
+ ],
+ [
+ "transformLinkUri",
+ { transformLinkUri: () => "", children: "a" },
+ /Unexpected `transformLinkUri` prop, use `urlTransform` instead/,
+ ],
+ [
+ "includeElementIndex",
+ { includeElementIndex: true, children: "a" },
+ /Unexpected `includeElementIndex` prop, remove it/,
+ ],
+ [
+ "rawSourcePos",
+ { rawSourcePos: true, children: "a" },
+ /Unexpected `rawSourcePos` prop, remove it/,
+ ],
+ [
+ "sourcePos",
+ { sourcePos: true, children: "a" },
+ /Unexpected `sourcePos` prop, remove it/,
+ ],
+ ];
+
+ for (const [name, props, expected] of cases) {
+ expect(() => renderWithProps(props), name).toThrow(expected);
+ }
+ });
+ });
+
+ describe("components", () => {
+ it("supports replacing tags and generic component functions", () => {
+ expect(
+ renderSync(() => ),
+ ).toBe("a ");
+ expect(
+ renderSync(() => (
+ ;
+ },
+ }}
+ />
+ )),
+ ).toBe("a
");
+ });
+
+ it("throws on an invalid component override", () => {
+ expect(() =>
+ renderWithProps({
+ children: "# a",
+ components: { h1: 123 },
+ }),
+ ).toThrow(/Comp is not a function/);
+ });
+
+ it("passes node to component overrides for headings, code, list, and table tags", () => {
+ let headingCalls = 0;
+ let codeCalls = 0;
+ let liCalls = 0;
+ let olCalls = 0;
+ let ulCalls = 0;
+ let trCalls = 0;
+ let tdCalls = 0;
+ let thCalls = 0;
+
+ expect(
+ renderSync(() => (
+ {props.children};
+ },
+ h2(props) {
+ headingCalls += 1;
+ expect(props.node?.tagName).toBe("h2");
+ return {props.children} ;
+ },
+ code(props) {
+ codeCalls += 1;
+ expect(props.node?.tagName).toBe("code");
+ return {props.children};
+ },
+ li(props) {
+ liCalls += 1;
+ expect(props.node?.tagName).toBe("li");
+ return {props.children} ;
+ },
+ ol(props) {
+ olCalls += 1;
+ expect(props.node?.tagName).toBe("ol");
+ return {props.children} ;
+ },
+ ul(props) {
+ ulCalls += 1;
+ expect(props.node?.tagName).toBe("ul");
+ return ;
+ },
+ tr(props) {
+ trCalls += 1;
+ expect(props.node?.tagName).toBe("tr");
+ return {props.children} ;
+ },
+ td(props) {
+ tdCalls += 1;
+ expect(props.node?.tagName).toBe("td");
+ return {props.children} ;
+ },
+ th(props) {
+ thCalls += 1;
+ expect(props.node?.tagName).toBe("th");
+ return {props.children} ;
+ },
+ }}
+ remarkPlugins={[remarkGfm]}
+ />
+ )),
+ ).toContain("");
+
+ expect(headingCalls).toBe(2);
+ expect(codeCalls).toBe(1);
+ expect(liCalls).toBe(2);
+ expect(olCalls).toBe(1);
+ expect(ulCalls).toBe(1);
+ expect(trCalls).toBe(2);
+ expect(tdCalls).toBe(1);
+ expect(thCalls).toBe(1);
+ });
+ });
+
+ describe("plugin and property passthrough", () => {
+ it("supports allow/disallow filters and unwrapDisallowed", () => {
+ expect(
+ renderSync(() => (
+
+ )),
+ ).toBe(" \n");
+ expect(
+ renderSync(() => (
+ element.tagName !== "em"}
+ />
+ )),
+ ).toBe(" b
");
+ expect(
+ renderSync(() => (
+
+ )),
+ ).toBe(" \n");
+ expect(
+ renderSync(() => (
+
+ )),
+ ).toBe("a ");
+ expect(
+ renderSync(() => (
+
+ )),
+ ).toBe("a ");
+ expect(() =>
+ renderSync(() => (
+
+ )),
+ ).toThrow(
+ /Unexpected combined `allowedElements` and `disallowedElements`, expected one or the other/,
+ );
+ });
+
+ it("supports remarkRehypeOptions and other remark plugins", () => {
+ expect(
+ renderSync(() => (
+
+ )),
+ ).toContain('href="#b-fn-x"');
+ expect(
+ renderSync(() => (
+
+ )),
+ ).toBe(`a
+Contents
+
+b
+c
+d `);
+ });
+
+ it("supports aria, data, comma-separated, style, svg, and comment plugin output", () => {
+ expect(
+ renderSync(() => (
+
+ )),
+ ).toBe('c
');
+ expect(
+ renderSync(() => (
+
+ )),
+ ).toBe('b
');
+ expect(
+ renderSync(() => (
+
+ )),
+ ).toBe('c
');
+ expect(
+ renderSync(() => (
+
+ )),
+ ).toBe('a
');
+ expect(
+ renderSync(() => (
+
+ )),
+ ).toBe('a
');
+ expect(
+ renderSync(() => (
+
+ )),
+ ).toBe('a
');
+ expect(
+ renderSync(() => (
+ ` element" },
+ ],
+ },
+ {
+ type: "element",
+ tagName: "circle",
+ properties: { cx: "120", cy: "120", r: "100" },
+ children: [],
+ },
+ {
+ type: "element",
+ tagName: "path",
+ properties: { strokeMiterLimit: -1 },
+ children: [],
+ },
+ ],
+ }),
+ ]}
+ />
+ )),
+ ).toBe(
+ 'SVG `<circle>` element a
',
+ );
+ expect(
+ renderSync(() => (
+
+ )),
+ ).toBe("a
");
+ });
+
+ it("merges table cell style with alignment", () => {
+ expect(
+ renderSync(() => (
+ {
+ visit(tree, "element", (node) => {
+ if (node.tagName === "th") {
+ node.properties = {
+ ...node.properties,
+ style: "color: red",
+ };
+ }
+ });
+ };
+ },
+ ]}
+ />
+ )),
+ ).toBe(
+ '',
+ );
+ });
+
+ it("returns empty output when a plugin replaces the root", () => {
+ expect(
+ renderSync(() => (
+ ({ type: "comment", value: "things!" });
+ },
+ ]}
+ />
+ )),
+ ).toBe("");
+ });
+ });
+
+ describe("async behavior", () => {
+ it("supports MarkdownAsync with SSR and streaming", async () => {
+ const rendered = await MarkdownAsync({ children: "a" });
+
+ expect(renderSync(() => rendered)).toBe("a
");
+ expect(await readStream(renderToStream(() => rendered))).toBe("a
");
+ });
+
+ it("supports async plugins in MarkdownAsync", async () => {
+ const rendered = await MarkdownAsync({
+ children: "```js\nconsole.log(3.14)\n```",
+ rehypePlugins: [rehypeStarryNight],
+ });
+ const html = renderSync(() => rendered);
+
+ expect(html).toContain('console ');
+ expect(html).toContain('3.14 ');
+ });
+ });
+});
+
+function renderWithProps(props: Record): string {
+ const MarkdownAny = Markdown as unknown as Component>;
+ return renderSync(() => );
+}
diff --git a/test/setup.ts b/test/setup.ts
new file mode 100644
index 0000000..d91a46e
--- /dev/null
+++ b/test/setup.ts
@@ -0,0 +1,50 @@
+import { transformAsync } from "@babel/core";
+// @ts-expect-error - @babel/preset-typescript ships no type declarations.
+import tsPreset from "@babel/preset-typescript";
+import { GlobalRegistrator } from "@happy-dom/global-registrator";
+// @ts-expect-error - babel-preset-solid ships no type declarations.
+import solid from "babel-preset-solid";
+import { plugin } from "bun";
+
+/**
+ * Bun test harness for Solid 2 JSX. Bun's native transpiler does not run the
+ * Solid JSX transform, so component tests need `babel-preset-solid` applied to
+ * every `.tsx`/`.ts` source the suite loads. `SOLID_GENERATE` selects the
+ * output mode (mirrors vitest's `--mode ssr`):
+ * - `dom` (client leg): reactive DOM runtime, happy-dom globals registered.
+ * - `ssr` (server leg): SSR string runtime, node env, no DOM globals.
+ */
+const generate = process.env.SOLID_GENERATE === "ssr" ? "ssr" : "dom";
+
+// The client leg needs DOM globals for `@solidjs/testing-library`'s `render`.
+// The SSR leg renders to a string in a node env and must NOT have them.
+if (generate === "dom") {
+ GlobalRegistrator.register();
+}
+
+plugin({
+ name: "solid-babel",
+ setup(build) {
+ // Only `.tsx` files carry Solid JSX (our `src` + `test` sources); no
+ // dependency ships `.tsx`, so this never intercepts babel's own
+ // `node_modules`/cache internals (which bun would then mis-mark as async
+ // modules and fail babel's synchronous config `require`).
+ build.onLoad({ filter: /\.tsx$/ }, async (args) => {
+ const source = await Bun.file(args.path).text();
+ const result = await transformAsync(source, {
+ filename: args.path,
+ presets: [
+ [tsPreset, { onlyRemoveTypeImports: true }],
+ [solid, { generate }],
+ ],
+ sourceMaps: "inline",
+ });
+
+ if (!result?.code) {
+ throw new Error(`solid-babel: empty transform for ${args.path}`);
+ }
+
+ return { contents: result.code, loader: "js" };
+ });
+ },
+});
diff --git a/tsconfig.build.json b/tsconfig.build.json
new file mode 100644
index 0000000..c3fb58f
--- /dev/null
+++ b/tsconfig.build.json
@@ -0,0 +1,10 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "noEmit": false,
+ "declaration": true,
+ "emitDeclarationOnly": true,
+ "outDir": "dist"
+ },
+ "include": ["src/index.tsx"]
+}
diff --git a/tsconfig.json b/tsconfig.json
index fb67300..4595cf3 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -4,7 +4,7 @@
"target": "ESNext",
"module": "ESNext",
"lib": ["DOM", "DOM.Iterable", "ESNext"],
- "moduleResolution": "node",
+ "moduleResolution": "bundler",
"resolveJsonModule": true,
"esModuleInterop": true,
"noEmit": true,
@@ -14,10 +14,10 @@
"forceConsistentCasingInFileNames": true,
"noUncheckedIndexedAccess": true,
"jsx": "preserve",
- "jsxImportSource": "solid-js",
+ "jsxImportSource": "@solidjs/web",
"types": ["bun"],
"baseUrl": "."
},
- "include": ["src"],
+ "include": ["src", "test", "build.ts", "scripts"],
"exclude": ["node_modules", "dist", "dev", "ssr-demo"]
}
diff --git a/tsup.config.ts b/tsup.config.ts
deleted file mode 100644
index 0e240a0..0000000
--- a/tsup.config.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { defineConfig } from "tsup";
-import * as preset from "tsup-preset-solid";
-
-const preset_options: preset.PresetOptions = {
- // array or single object
- entries: [
- // default entry (index)
- {
- // entries with '.tsx' extension will have `solid` export condition generated
- entry: "src/index.tsx",
- // will generate a separate development entry
- dev_entry: true,
- server_entry: true,
- },
- ],
- // Set to `true` to remove all `console.*` calls and `debugger` statements in prod builds
- drop_console: true,
- // Set to `true` to generate a CommonJS build alongside ESM
- // cjs: true,
-};
-
-const CI =
- process.env.CI === "true" ||
- process.env.GITHUB_ACTIONS === "true" ||
- process.env.CI === '"1"' ||
- process.env.GITHUB_ACTIONS === '"1"';
-
-export default defineConfig((config) => {
- const watching = !!config.watch;
-
- const parsed_options = preset.parsePresetOptions(preset_options, watching);
-
- if (!watching && !CI) {
- const package_fields = preset.generatePackageExports(parsed_options);
-
- console.log(
- `package.json: \n\n${JSON.stringify(package_fields, null, 2)}\n\n`,
- );
-
- // will update ./package.json with the correct export fields
- preset.writePackageJson(package_fields);
- }
-
- return preset.generateTsupOptions(parsed_options);
-});