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
    \n
  • b
  • \n
\n

a

', + ); + }); + }); + + 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( + "
\n

a

\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( + "
    \n
  • a
  • \n
", + ); + expect(renderSync(() => )).toBe( + "
    \n
  1. a
  2. \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( + '

a

', + ); + expect(renderSync(() => )).toBe( + '

a

', + ); + expect(renderSync(() => )).toBe( + '

a

', + ); + 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( + "
a
b
", + ); + expect( + renderSync(() => ( + + )), + ).toBe( + '
abcd
', + ); + }); + }); + + 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('

a

'); + }); + + 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
      {props.children}
    ; + }, + 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
      \n
    • b
    • \n
    "); + expect( + renderSync(() => ( + element.tagName !== "em"} + /> + )), + ).toBe("

    b

    "); + expect( + renderSync(() => ( + + )), + ).toBe("

    \n
      \n
    • b
    • \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
    • +
    +

    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( + '
    a
    ', + ); + }); + + 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); -});