diff --git a/biome.json b/biome.json index c52df58e969f..6a925f575bb6 100644 --- a/biome.json +++ b/biome.json @@ -22,12 +22,13 @@ "includes": [ "**/packages/aria-data/*.js", "**/packages/@biomejs/**", + "**/packages/prettier-compare/**", "**/packages/tailwindcss-config-analyzer/**", "**/benchmark/**", "plugins/*.js", "scripts/**", "!**/crates", - "!**/dist", + "!!**/dist", "!**/packages/@biomejs/backend-jsonrpc/src/workspace.ts", "!**/__snapshots__", "!**/undefined", diff --git a/crates/biome_html_syntax/src/element_ext.rs b/crates/biome_html_syntax/src/element_ext.rs index 7edc02fd2320..3a07aaff40ba 100644 --- a/crates/biome_html_syntax/src/element_ext.rs +++ b/crates/biome_html_syntax/src/element_ext.rs @@ -1,7 +1,7 @@ use crate::{ - AnyHtmlElement, AstroEmbeddedContent, HtmlAttribute, HtmlAttributeList, HtmlElement, - HtmlEmbeddedContent, HtmlOpeningElement, HtmlSelfClosingElement, HtmlSyntaxToken, HtmlTagName, - ScriptType, inner_string_text, + AnyHtmlContent, AnyHtmlElement, AnyHtmlTextExpression, AnySvelteBlock, AstroEmbeddedContent, + HtmlAttribute, HtmlAttributeList, HtmlElement, HtmlEmbeddedContent, HtmlOpeningElement, + HtmlSelfClosingElement, HtmlSyntaxToken, HtmlTagName, ScriptType, inner_string_text, }; use biome_rowan::{AstNodeList, SyntaxResult, TokenText, declare_node_union}; @@ -55,23 +55,56 @@ impl AnyHtmlElement { pub fn name(&self) -> Option { match self { - Self::HtmlElement(el) => { - let opening_element = el.opening_element().ok()?; - let name = opening_element.name().ok()?; - let name_token = name.value_token().ok()?; - Some(name_token.token_text_trimmed()) - } - Self::HtmlSelfClosingElement(el) => { - let name = el.name().ok()?; - let name_token = name.value_token().ok()?; - Some(name_token.token_text_trimmed()) - } + Self::HtmlElement(el) => el.tag_name(), + Self::HtmlSelfClosingElement(el) => el.tag_name(), + _ => None, + } + } + + /// Returns the closing `>` token from this element's closing tag, if it has one. + /// + /// This is used for "borrowing" the closing `>` when formatting adjacent inline elements + /// to avoid introducing whitespace between them. + /// + /// Only returns a token for `HtmlElement` (which has actual closing tags like ``). + /// Self-closing elements like `` don't have a separate closing tag to borrow from. + pub fn closing_r_angle_token(&self) -> Option { + match self { + Self::HtmlElement(el) => el.closing_element().ok()?.r_angle_token().ok(), + // Self-closing elements don't have a closing tag to borrow from _ => None, } } + + pub fn is_svelte_block(&self) -> bool { + matches!( + self, + Self::AnyHtmlContent(AnyHtmlContent::AnyHtmlTextExpression( + AnyHtmlTextExpression::AnySvelteBlock(_) + )) + ) + } + + pub fn as_svelte_block(self) -> Option { + if let Self::AnyHtmlContent(AnyHtmlContent::AnyHtmlTextExpression( + AnyHtmlTextExpression::AnySvelteBlock(block), + )) = self + { + Some(block) + } else { + None + } + } } impl HtmlSelfClosingElement { + /// Returns the tag name of the element (trimmed), if it has one. + pub fn tag_name(&self) -> Option { + let name = self.name().ok()?; + let name_token = name.value_token().ok()?; + Some(name_token.token_text_trimmed()) + } + pub fn find_attribute_by_name(&self, name_to_lookup: &str) -> Option { self.attributes().iter().find_map(|attr| { let attribute = attr.as_html_attribute()?; @@ -90,6 +123,13 @@ impl HtmlSelfClosingElement { } impl HtmlOpeningElement { + /// Returns the tag name of the element (trimmed), if it has one. + pub fn tag_name(&self) -> Option { + let name = self.name().ok()?; + let name_token = name.value_token().ok()?; + Some(name_token.token_text_trimmed()) + } + pub fn find_attribute_by_name(&self, name_to_lookup: &str) -> Option { self.attributes().iter().find_map(|attr| { let attribute = attr.as_html_attribute()?; @@ -108,6 +148,12 @@ impl HtmlOpeningElement { } impl HtmlElement { + /// Returns the tag name of the element (trimmed), if it has one. + pub fn tag_name(&self) -> Option { + let opening_element = self.opening_element().ok()?; + opening_element.tag_name() + } + pub fn find_attribute_by_name(&self, name_to_lookup: &str) -> Option { self.opening_element() .ok()? diff --git a/packages/prettier-compare/README.md b/packages/prettier-compare/README.md new file mode 100644 index 000000000000..8d160fafd08b --- /dev/null +++ b/packages/prettier-compare/README.md @@ -0,0 +1,63 @@ +# `prettier-compare` Package + +## Overview + +A CLI tool that compares Prettier and Biome formatting output and IR side-by-side. Uses OpenTUI (with React renderer) for the terminal UI, including spinners during WASM rebuilds and debounced watch mode. + +## Architecture + +``` +packages/prettier-compare/ +├── src/ +│ ├── index.tsx # Main CLI entry point + React TUI app +│ ├── biome.ts # Biome formatting via @biomejs/js-api +│ ├── prettier.ts # Prettier formatting via npm package +│ ├── languages.ts # Language detection and config mapping +│ ├── components/ +│ │ ├── App.tsx # Main app component +│ │ ├── DiffView.tsx # Side-by-side diff display +│ │ ├── DiagnosticsView.tsx # Error/diagnostics section +│ │ └── Spinner.tsx # Loading spinner for rebuilds +│ └── watch.ts # Watch mode with cargo rebuild + debounce +├── bin/ +│ └── prettier-compare.js # Bin script +├── package.json +├── tsconfig.json +└── README.md +``` + +## Key Features + +1. **Multiple Input Sources**: Snippet argument, file (`--file`), or stdin +2. **Language Detection**: Auto-detect from file extension or specify with `--language` +3. **Side-by-Side Diff**: Show Biome vs Prettier formatted output +4. **IR Comparison**: Show intermediate representation from both formatters +5. **Diagnostics Section**: Display syntax errors from both tools +6. **Watch Mode**: Rebuild WASM on Rust file changes with debounce and spinner +7. **All Languages**: Support JS/TS, JSON, CSS, HTML, GraphQL, etc. + +## Usage + +In order to run the tool, you must have the WASM build of Biome available. You can use the `--rebuild` flag to build it automatically if needed, or you can run `just build-wasm-node-dev`. + +To run the tool, from the repo root run: + +```bash +# Format a snippet +bun packages/prettier-compare/bin/prettier-compare.js "const x={a:1,b:2}" + +# Specify language +bun packages/prettier-compare/bin/prettier-compare.js -l ts "const x: number = 1" + +# From file +bun packages/prettier-compare/bin/prettier-compare.js -f src/example.tsx + +# From stdin +echo "const x = 1" | bun packages/prettier-compare/bin/prettier-compare.js -l js + +# Watch mode (rebuilds WASM on Rust changes) +bun --hot packages/prettier-compare/bin/prettier-compare.js -w --watch "function f() { return 1 }" +bun --hot packages/prettier-compare/bin/prettier-compare.js -l html --watch ' A B C ' +``` + +Note: In watch mode, if you want it to reload the wasm after building biome, then you must use `bun --hot` to run the bin script. diff --git a/packages/prettier-compare/bin/prettier-compare.js b/packages/prettier-compare/bin/prettier-compare.js new file mode 100755 index 000000000000..e9b4b9606e04 --- /dev/null +++ b/packages/prettier-compare/bin/prettier-compare.js @@ -0,0 +1,2 @@ +#!/usr/bin/env -S bun --hot +import "../src/index.tsx"; diff --git a/packages/prettier-compare/package.json b/packages/prettier-compare/package.json new file mode 100644 index 000000000000..6d6f3636156c --- /dev/null +++ b/packages/prettier-compare/package.json @@ -0,0 +1,25 @@ +{ + "name": "@biomejs/prettier-compare", + "version": "0.0.0", + "private": true, + "type": "module", + "description": "Compare Biome and Prettier formatting output and IR side-by-side", + "bin": { + "prettier-compare": "./bin/prettier-compare.js" + }, + "dependencies": { + "@biomejs/js-api": "workspace:*", + "@biomejs/wasm-nodejs": "workspace:*", + "@opentui/core": "^0.1.72", + "@opentui/react": "^0.1.72", + "prettier": "^3.7.0", + "prettier-plugin-svelte": "^3.4.0", + "react": "^19.0.0" + }, + "devDependencies": { + "@types/node": "^22.0.0", + "@types/react": "^19.0.0", + "typescript": "5.7.3" + }, + "license": "MIT OR Apache-2.0" +} diff --git a/packages/prettier-compare/src/biome.ts b/packages/prettier-compare/src/biome.ts new file mode 100644 index 000000000000..f9cafbb72e80 --- /dev/null +++ b/packages/prettier-compare/src/biome.ts @@ -0,0 +1,93 @@ +/** + * Biome formatting integration using @biomejs/js-api + */ + +import { Biome, Distribution } from "@biomejs/js-api"; + +export interface BiomeDiagnostic { + description: string; + severity: string; +} + +export interface BiomeResult { + /** The formatted output */ + output: string; + /** The formatter IR (intermediate representation) */ + ir: string; + /** Any diagnostics/errors encountered */ + diagnostics: BiomeDiagnostic[]; +} + +let biomeInstance: Biome | null = null; + +/** + * Get or create a Biome instance. + */ +async function getBiome(): Promise { + if (!biomeInstance) { + biomeInstance = await Biome.create({ distribution: Distribution.NODE }); + } + return biomeInstance; +} + +/** + * Format code using Biome and return the result with IR. + * + * @param code - The source code to format + * @param filePath - Virtual file path for language detection + * @returns The formatting result including output, IR, and diagnostics + */ +export async function formatWithBiome( + code: string, + filePath: string, +): Promise { + const biome = await getBiome(); + const { projectKey } = biome.openProject(); + + try { + biome.applyConfiguration(projectKey, { + formatter: { + indentStyle: "space", + indentWidth: 2, + }, + html: { + experimentalFullSupportEnabled: true, + formatter: { + enabled: true, + selfCloseVoidElements: "always", + }, + }, + }); + + const result = biome.formatContent(projectKey, code, { + filePath, + debug: true, + }); + + return { + output: result.content, + ir: result.ir ?? "", + diagnostics: result.diagnostics.map((d) => ({ + description: + typeof d === "object" && d !== null && "description" in d + ? String(d.description) + : String(d), + severity: + typeof d === "object" && d !== null && "severity" in d + ? String(d.severity) + : "error", + })), + }; + } catch (err) { + return { + output: code, + ir: "", + diagnostics: [ + { + description: err instanceof Error ? err.message : String(err), + severity: "error", + }, + ], + }; + } +} diff --git a/packages/prettier-compare/src/components/App.tsx b/packages/prettier-compare/src/components/App.tsx new file mode 100644 index 000000000000..7e1d626d24f9 --- /dev/null +++ b/packages/prettier-compare/src/components/App.tsx @@ -0,0 +1,215 @@ +/** + * Main App component that orchestrates the comparison UI. + */ + +// biome-ignore lint/correctness/noUnusedImports: auto-suppressed +import React, { useCallback, useEffect, useState } from "react"; +import { type BiomeResult, formatWithBiome } from "../biome.js"; +import { getLanguageConfig } from "../languages.js"; +import { formatWithPrettier, type PrettierResult } from "../prettier.js"; +import { createWatcher, rebuildWasm } from "../watch.js"; +import { DiagnosticsView } from "./DiagnosticsView.js"; +import { DiffView } from "./DiffView.js"; +import { Spinner } from "./Spinner.js"; + +interface AppProps { + /** The code to format and compare */ + code: string; + /** The language identifier (e.g., "js", "ts", "json") */ + language: string; + /** Whether to enable watch mode */ + watchMode: boolean; + /** Root directory of the Biome repository */ + rootDir: string; + /** Callback when the app should exit */ + onExit: () => void; + /** Only show IR comparison */ + irOnly?: boolean; + /** Only show formatted output comparison */ + outputOnly?: boolean; + /** Force rebuild WASM before running */ + rebuild?: boolean; +} + +/** + * Main application component that manages state and renders the comparison UI. + */ +export function App({ + code, + language, + watchMode, + rootDir, + // biome-ignore lint/correctness/noUnusedFunctionParameters: auto-suppressed + onExit, + irOnly = false, + outputOnly = false, + rebuild = false, +}: AppProps) { + const [biomeResult, setBiomeResult] = useState(null); + const [prettierResult, setPrettierResult] = useState( + null, + ); + const [isLoading, setIsLoading] = useState(true); + const [isRebuilding, setIsRebuilding] = useState(false); + const [rebuildingFile, setRebuildingFile] = useState(null); + const [statusMessage, setStatusMessage] = useState(null); + const [error, setError] = useState(null); + + const runComparison = useCallback(async () => { + setIsLoading(true); + setError(null); + + try { + const config = getLanguageConfig(language); + const [biome, prettier] = await Promise.all([ + formatWithBiome(code, config.biomeFilePath), + formatWithPrettier(code, config.prettierParser), + ]); + setBiomeResult(biome); + setPrettierResult(prettier); + } catch (err) { + setError(err instanceof Error ? err.message : String(err)); + } finally { + setIsLoading(false); + } + }, [code, language]); + + // Initial setup: optionally rebuild WASM, then run comparison + useEffect(() => { + async function initialize() { + if (rebuild) { + setStatusMessage("Rebuilding WASM (--rebuild flag)..."); + setIsRebuilding(true); + try { + await rebuildWasm(rootDir); + // reloading biome is handled by bun hot reloading + setStatusMessage(null); + } catch (err) { + setError( + `Initial build failed: ${err instanceof Error ? err.message : String(err)}`, + ); + } finally { + setIsRebuilding(false); + } + } + + await runComparison(); + } + + // biome-ignore lint/nursery/noFloatingPromises: its fine here + initialize(); + }, [rebuild, rootDir, runComparison]); + + // Set up watch mode + useEffect(() => { + if (!watchMode) return; + + const watcher = createWatcher(rootDir); + + watcher.on("rebuilding", (changedFile) => { + setIsRebuilding(true); + setRebuildingFile(changedFile); + setStatusMessage(`Rebuilding WASM... (${changedFile})`); + }); + + watcher.on("rebuilt", async () => { + setStatusMessage("Reloading Biome..."); + // reloading biome is handled by bun hot reloading + setStatusMessage(null); + await runComparison(); + setIsRebuilding(false); + setRebuildingFile(null); + }); + + watcher.on("error", (err) => { + setError(`Build failed: ${err.message}`); + setIsRebuilding(false); + setRebuildingFile(null); + setStatusMessage(null); + }); + + return () => { + // biome-ignore lint/nursery/noFloatingPromises: its fine here + watcher.close(); + }; + }, [watchMode, rootDir, runComparison]); + + // Show loading spinner only on initial load (no existing results to show) + if (isLoading && !biomeResult && !prettierResult) { + return ; + } + + // Show error if something went wrong and we have no results to display + if (error && !biomeResult && !prettierResult) { + return Error: {error}; + } + + // If we have results, always show them (even while rebuilding) + + const outputMatch = biomeResult?.output === prettierResult?.output; + const config = getLanguageConfig(language); + + return ( + + {/* Status bar - always visible at top */} + {isRebuilding && ( + + + + )} + + {watchMode && !isRebuilding && ( + + Watch mode active ({config.displayName}). Press Ctrl+C to exit. + + )} + + {error && Warning: {error}} + + + + {/* Formatted output comparison */} + {!irOnly && ( + + )} + + {/* IR comparison */} + {!outputOnly && ( + + )} + + {/* Diagnostics section */} + + + {/* Language info */} + {!watchMode && ( + + Language: {config.displayName} | Prettier parser:{" "} + {config.prettierParser} + + )} + + + + ); +} diff --git a/packages/prettier-compare/src/components/DiagnosticsView.tsx b/packages/prettier-compare/src/components/DiagnosticsView.tsx new file mode 100644 index 000000000000..f16e9e53af7d --- /dev/null +++ b/packages/prettier-compare/src/components/DiagnosticsView.tsx @@ -0,0 +1,62 @@ +/** + * Diagnostics view component for displaying errors and warnings. + */ + +// biome-ignore lint/correctness/noUnusedImports: auto-suppressed +import React from "react"; +import type { BiomeDiagnostic } from "../biome.js"; + +interface DiagnosticsViewProps { + /** Diagnostics from Biome */ + biomeDiagnostics: BiomeDiagnostic[]; + /** Error message from Prettier, if any */ + prettierError?: string; +} + +/** + * Renders diagnostics and errors from both formatters. + */ +export function DiagnosticsView({ + biomeDiagnostics, + prettierError, +}: DiagnosticsViewProps) { + const hasDiagnostics = biomeDiagnostics.length > 0 || prettierError; + + if (!hasDiagnostics) { + return null; + } + + return ( + + + Diagnostics + + + {/* Biome diagnostics */} + {biomeDiagnostics.length > 0 && ( + + Biome: + {biomeDiagnostics.map((d, index) => ( + + {" "}[{d.severity}] {d.description} + + ))} + + )} + + {/* Prettier error */} + {prettierError && ( + + Prettier: + + {" "}[error] {prettierError} + + + )} + + ); +} diff --git a/packages/prettier-compare/src/components/DiffView.tsx b/packages/prettier-compare/src/components/DiffView.tsx new file mode 100644 index 000000000000..c57ad800d0ff --- /dev/null +++ b/packages/prettier-compare/src/components/DiffView.tsx @@ -0,0 +1,108 @@ +/** + * Side-by-side diff view component for comparing Biome and Prettier output. + */ + +// biome-ignore lint/correctness/noUnusedImports: auto-suppressed +import React from "react"; + +interface DiffViewProps { + /** Title for this comparison section */ + title: string; + /** Content from Biome formatter */ + biomeContent: string; + /** Content from Prettier formatter */ + prettierContent: string; + /** Whether the outputs match (for visual indicator) */ + isMatch?: boolean; + /** Whether the content is stale (dimmed while rebuilding) */ + dimmed?: boolean; +} + +/** + * Renders a side-by-side comparison of Biome and Prettier output. + */ +export function DiffView({ + title, + biomeContent, + prettierContent, + isMatch, + dimmed = false, +}: DiffViewProps) { + const biomeLines = biomeContent.split("\n"); + const prettierLines = prettierContent.split("\n"); + const maxLines = Math.max(biomeLines.length, prettierLines.length); + + // Build diff indicators + const diffLines: Array<{ + biome: string; + prettier: string; + isDiff: boolean; + }> = []; + + for (let i = 0; i < maxLines; i++) { + const biomeLine = biomeLines[i] ?? ""; + const prettierLine = prettierLines[i] ?? ""; + diffLines.push({ + biome: biomeLine, + prettier: prettierLine, + isDiff: biomeLine !== prettierLine, + }); + } + + const matchIndicator = + isMatch === undefined ? "" : isMatch ? " [MATCH]" : " [DIFF]"; + const matchColor = + isMatch === undefined ? "#FFFFFF" : isMatch ? "#00FF00" : "#FF6600"; + + // Dimmed colors for when content is stale (rebuilding) + const dimmedMatchColor = "#666666"; + const dimmedHeaderColor = "#555555"; + const dimmedDiffColor = "#885533"; + const dimmedNormalColor = "#777777"; + + const titleColor = dimmed ? dimmedMatchColor : matchColor; + const headerBiomeColor = dimmed ? dimmedHeaderColor : "#00FFFF"; + const headerPrettierColor = dimmed ? dimmedHeaderColor : "#FF00FF"; + const diffColor = dimmed ? dimmedDiffColor : "#FF6600"; + const normalColor = dimmed ? dimmedNormalColor : "#CCCCCC"; + + return ( + + {/* Title */} + + {title} + {matchIndicator} + {dimmed ? " (updating...)" : ""} + + + {/* Header row */} + + + + Biome + + + + + Prettier + + + + + {/* Content rows */} + {/** biome-ignore lint/correctness/noUnusedFunctionParameters: auto-suppressed */} + {diffLines.map((line, index) => ( + + + {line.biome} + + + + {line.prettier} + + + + ))} + + ); +} diff --git a/packages/prettier-compare/src/components/Spinner.tsx b/packages/prettier-compare/src/components/Spinner.tsx new file mode 100644 index 000000000000..275761e9474a --- /dev/null +++ b/packages/prettier-compare/src/components/Spinner.tsx @@ -0,0 +1,35 @@ +/** + * Animated spinner component for loading states. + */ + +// biome-ignore lint/correctness/noUnusedImports: auto-suppressed +import React, { useEffect, useState } from "react"; + +const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]; + +interface SpinnerProps { + /** Message to display next to the spinner */ + message: string; +} + +/** + * Renders an animated spinner with a message. + */ +export function Spinner({ message }: SpinnerProps) { + const [frameIndex, setFrameIndex] = useState(0); + + useEffect(() => { + const interval = setInterval(() => { + setFrameIndex((prev) => (prev + 1) % SPINNER_FRAMES.length); + }, 80); + + return () => clearInterval(interval); + }, []); + + return ( + + {SPINNER_FRAMES[frameIndex]} + {message} + + ); +} diff --git a/packages/prettier-compare/src/index.tsx b/packages/prettier-compare/src/index.tsx new file mode 100644 index 000000000000..4c8e634379ef --- /dev/null +++ b/packages/prettier-compare/src/index.tsx @@ -0,0 +1,248 @@ +/** + * CLI entry point for prettier-compare. + * + * Usage: + * prettier-compare "const x = 1" # Format a snippet + * prettier-compare -f file.ts # Format from file + * echo "const x = 1" | prettier-compare # Format from stdin + * prettier-compare -w "const x = 1" # Watch mode (fancy TUI) + */ + +import { parseArgs } from "node:util"; +// biome-ignore lint/style/useNodejsImportProtocol: auto-suppressed +import { readFileSync } from "fs"; +// biome-ignore lint/style/useNodejsImportProtocol: auto-suppressed +import { dirname, resolve } from "path"; +// biome-ignore lint/style/useNodejsImportProtocol: auto-suppressed +import { fileURLToPath } from "url"; +import { formatWithBiome } from "./biome.js"; +import { + detectLanguage, + getLanguageConfig, + getSupportedLanguages, +} from "./languages.js"; +import { printComparison } from "./plainOutput.js"; +import { formatWithPrettier } from "./prettier.js"; +import { rebuildWasm } from "./watch.js"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +// Find biome repo root (package is in packages/prettier-compare) +const ROOT_DIR = resolve(__dirname, "../../.."); + +/** + * Read all input from stdin. + */ +async function readStdin(): Promise { + const chunks: Buffer[] = []; + for await (const chunk of process.stdin) { + chunks.push(chunk as Buffer); + } + return Buffer.concat(chunks).toString("utf-8"); +} + +type RawCliOptionValues = { + file?: string; + language?: string; + watch?: boolean; + rebuild?: boolean; + "ir-only"?: boolean; + "output-only"?: boolean; + help?: boolean; +}; + +type NormalizedCliOptions = { + file?: string; + language?: string; + watch: boolean; + rebuild: boolean; + irOnly: boolean; + outputOnly: boolean; +}; + +function printHelp() { + const languages = getSupportedLanguages().slice(0, 8).join(", "); + + console.info( + "Compare Biome and Prettier formatting output and IR side-by-side.\n", + ); + console.info("Usage:"); + console.info(' prettier-compare "const x = 1" # Format a snippet'); + console.info(" prettier-compare -f file.ts # Format from file"); + console.info( + ' echo "const x = 1" | prettier-compare # Format from stdin', + ); + console.info( + ' prettier-compare -w "const x = 1" # Watch mode (fancy TUI)', + ); + console.info("\nOptions:"); + console.info(" -f, --file Read input from file"); + console.info(` -l, --language Language (${languages}, ...)`); + console.info( + " -w, --watch Watch mode: rebuild WASM on Rust file changes", + ); + console.info(" -r, --rebuild Rebuild WASM before running"); + console.info( + " --ir-only Only show IR comparison, not formatted output", + ); + console.info(" --output-only Only show formatted output, not IR"); + console.info(" -h, --help Show this help message"); +} + +function parseCliArgs(): { snippet?: string; options: NormalizedCliOptions } { + const { values, positionals } = parseArgs({ + args: process.argv.slice(2), + allowPositionals: true, + options: { + file: { type: "string", short: "f" }, + language: { type: "string", short: "l" }, + watch: { type: "boolean", short: "w", default: false }, + rebuild: { type: "boolean", short: "r", default: false }, + "ir-only": { type: "boolean", default: false }, + "output-only": { type: "boolean", default: false }, + help: { type: "boolean", short: "h", default: false }, + }, + }) as { + values: RawCliOptionValues; + positionals: string[]; + }; + + if (values.help) { + printHelp(); + process.exit(0); + } + + return { + snippet: positionals[0], + options: { + file: values.file, + language: values.language, + watch: values.watch ?? false, + rebuild: values.rebuild ?? false, + irOnly: values["ir-only"] ?? false, + outputOnly: values["output-only"] ?? false, + }, + }; +} + +async function run() { + const { snippet: snippetArg, options } = parseCliArgs(); + + // Determine input source + let code: string; + let detectedLang: string | undefined; + + if (options.file) { + // Read from file + try { + code = readFileSync(options.file, "utf-8"); + detectedLang = detectLanguage(options.file); + } catch (err) { + console.error( + `Error reading file: ${err instanceof Error ? err.message : err}`, + ); + process.exit(1); + } + } else if (snippetArg) { + // Use provided snippet + code = snippetArg; + } else if (!process.stdin.isTTY) { + // Read from stdin + code = await readStdin(); + } else { + // No input provided + console.error( + "Error: No input provided. Pass a snippet, use --file, or pipe to stdin.", + ); + console.error(""); + console.error("Examples:"); + console.error(' prettier-compare "const x = { a: 1 }"'); + console.error(" prettier-compare -f src/example.ts"); + console.error(" echo 'const x = 1' | prettier-compare"); + process.exit(1); + } + + const language = options.language ?? detectedLang ?? "js"; + + if (options.watch) { + // Watch mode: Use fancy TUI with React/OpenTUI + const { createCliRenderer } = await import("@opentui/core"); + const { createRoot } = await import("@opentui/react"); + const React = await import("react"); + const { App } = await import("./components/App.js"); + + const renderer = await createCliRenderer({ + targetFps: 30, + }); + + const handleExit = () => { + renderer.stop(); + process.exit(0); + }; + + const root = createRoot(renderer); + root.render( + React.createElement(App, { + code, + language, + watchMode: true, + rootDir: ROOT_DIR, + onExit: handleExit, + irOnly: options.irOnly, + outputOnly: options.outputOnly, + rebuild: options.rebuild, + }), + ); + + renderer.start(); + + // Handle Ctrl+C + process.on("SIGINT", handleExit); + process.on("SIGTERM", handleExit); + } else { + // Non-watch mode: Plain sequential output to stdout + const config = getLanguageConfig(language); + + // Optionally rebuild WASM first + if (options.rebuild) { + console.info("Rebuilding WASM..."); + try { + await rebuildWasm(ROOT_DIR); + console.info("WASM rebuilt successfully.\n"); + } catch (err) { + console.error( + `WASM rebuild failed: ${err instanceof Error ? err.message : err}`, + ); + process.exit(1); + } + } + + // Run formatting + try { + const [biomeResult, prettierResult] = await Promise.all([ + formatWithBiome(code, config.biomeFilePath), + formatWithPrettier(code, config.prettierParser), + ]); + + printComparison({ + biomeResult, + prettierResult, + language, + irOnly: options.irOnly, + outputOnly: options.outputOnly, + }); + } catch (err) { + console.error( + `Formatting failed: ${err instanceof Error ? err.message : err}`, + ); + process.exit(1); + } + } +} + +run().catch((err) => { + console.error( + err instanceof Error ? (err.stack ?? err.message) : String(err), + ); + process.exit(1); +}); diff --git a/packages/prettier-compare/src/languages.ts b/packages/prettier-compare/src/languages.ts new file mode 100644 index 000000000000..66e43155b0c0 --- /dev/null +++ b/packages/prettier-compare/src/languages.ts @@ -0,0 +1,136 @@ +/** + * Language configuration for mapping file extensions to Biome and Prettier settings. + */ + +export interface LanguageConfig { + /** Virtual file path for Biome (used for language detection) */ + biomeFilePath: string; + /** Prettier parser name */ + prettierParser: string; + /** Display name for the language */ + displayName: string; +} + +/** + * Mapping of language identifiers to their configurations. + */ +export const LANGUAGES: Record = { + js: { + biomeFilePath: "file.js", + prettierParser: "babel", + displayName: "JavaScript", + }, + javascript: { + biomeFilePath: "file.js", + prettierParser: "babel", + displayName: "JavaScript", + }, + jsx: { + biomeFilePath: "file.jsx", + prettierParser: "babel", + displayName: "JSX", + }, + ts: { + biomeFilePath: "file.ts", + prettierParser: "typescript", + displayName: "TypeScript", + }, + typescript: { + biomeFilePath: "file.ts", + prettierParser: "typescript", + displayName: "TypeScript", + }, + tsx: { + biomeFilePath: "file.tsx", + prettierParser: "typescript", + displayName: "TSX", + }, + json: { + biomeFilePath: "file.json", + prettierParser: "json", + displayName: "JSON", + }, + jsonc: { + biomeFilePath: "file.jsonc", + prettierParser: "json", + displayName: "JSON with Comments", + }, + css: { + biomeFilePath: "file.css", + prettierParser: "css", + displayName: "CSS", + }, + html: { + biomeFilePath: "file.html", + prettierParser: "html", + displayName: "HTML", + }, + graphql: { + biomeFilePath: "file.graphql", + prettierParser: "graphql", + displayName: "GraphQL", + }, + gql: { + biomeFilePath: "file.graphql", + prettierParser: "graphql", + displayName: "GraphQL", + }, + md: { + biomeFilePath: "file.md", + prettierParser: "markdown", + displayName: "Markdown", + }, + markdown: { + biomeFilePath: "file.md", + prettierParser: "markdown", + displayName: "Markdown", + }, + yaml: { + biomeFilePath: "file.yaml", + prettierParser: "yaml", + displayName: "YAML", + }, + yml: { + biomeFilePath: "file.yaml", + prettierParser: "yaml", + displayName: "YAML", + }, + svelte: { + biomeFilePath: "file.svelte", + prettierParser: "svelte", + displayName: "Svelte", + }, +}; + +/** + * Detect language from a file path based on its extension. + * @param filePath - The file path to analyze + * @returns The detected language identifier, or "js" as default + */ +export function detectLanguage(filePath?: string): string { + if (!filePath) return "js"; + + const ext = filePath.split(".").pop()?.toLowerCase(); + if (ext && ext in LANGUAGES) { + return ext; + } + + return "js"; +} + +/** + * Get the language configuration for a given language identifier. + * @param lang - The language identifier (e.g., "js", "ts", "json") + * @returns The language configuration, or JavaScript config as fallback + */ +export function getLanguageConfig(lang: string): LanguageConfig { + const normalized = lang.toLowerCase(); + return LANGUAGES[normalized] ?? LANGUAGES.js; +} + +/** + * Get a list of all supported language identifiers. + */ +export function getSupportedLanguages(): string[] { + return Object.keys(LANGUAGES); +} diff --git a/packages/prettier-compare/src/plainOutput.ts b/packages/prettier-compare/src/plainOutput.ts new file mode 100644 index 000000000000..62591ab7af3b --- /dev/null +++ b/packages/prettier-compare/src/plainOutput.ts @@ -0,0 +1,105 @@ +/** + * Plain text output for non-watch mode. + * Prints comparison results sequentially to stdout with basic ANSI colors. + */ + +import { styleText } from "node:util"; + +import type { BiomeResult } from "./biome.js"; +import { getLanguageConfig } from "./languages.js"; +import type { PrettierResult } from "./prettier.js"; + +function header(text: string): string { + return styleText(["bold", "cyan"], text); +} + +function matchIndicator(isMatch: boolean): string { + if (isMatch) { + return styleText("green", "[MATCH]"); + } + return styleText("yellow", "[DIFF]"); +} + +interface PrintComparisonOptions { + biomeResult: BiomeResult; + prettierResult: PrettierResult; + language: string; + irOnly?: boolean; + outputOnly?: boolean; +} + +/** + * Print comparison results sequentially to stdout. + */ +export function printComparison({ + biomeResult, + prettierResult, + language, + irOnly = false, + outputOnly = false, +}: PrintComparisonOptions): void { + const outputMatch = biomeResult.output === prettierResult.output; + const config = getLanguageConfig(language); + + // Formatted output comparison + if (!irOnly) { + console.info( + `${header("=== Formatted Output ===")} ${matchIndicator(outputMatch)}`, + ); + console.info(); + + console.info(styleText("cyan", "--- Biome ---")); + console.info(biomeResult.output); + + console.info(styleText("magenta", "--- Prettier ---")); + console.info(prettierResult.output); + } + + // IR comparison + if (!outputOnly) { + console.info(header("=== IR (Intermediate Representation) ===")); + console.info(); + + console.info(styleText("cyan", "--- Biome ---")); + console.info(biomeResult.ir || "(no IR available)"); + console.info(); + + console.info(styleText("magenta", "--- Prettier ---")); + console.info(prettierResult.ir || "(no IR available)"); + console.info(); + } + + // Diagnostics + const hasDiagnostics = + biomeResult.diagnostics.length > 0 || prettierResult.error; + + if (hasDiagnostics) { + console.info(header("=== Diagnostics ===")); + console.info(); + + if (biomeResult.diagnostics.length > 0) { + console.info(styleText("cyan", "Biome:")); + for (const d of biomeResult.diagnostics) { + const severityStyle = d.severity === "error" ? "red" : "yellow"; + console.info( + ` ${styleText(severityStyle, `[${d.severity}]`)} ${d.description}`, + ); + } + } + + if (prettierResult.error) { + console.info(styleText("magenta", "Prettier:")); + console.info(` ${styleText("red", "[error]")} ${prettierResult.error}`); + } + + console.info(); + } + + // Language info + console.info( + styleText( + "gray", + `Language: ${config.displayName} | Prettier parser: ${config.prettierParser}`, + ), + ); +} diff --git a/packages/prettier-compare/src/prettier.ts b/packages/prettier-compare/src/prettier.ts new file mode 100644 index 000000000000..ff94da96c11e --- /dev/null +++ b/packages/prettier-compare/src/prettier.ts @@ -0,0 +1,74 @@ +/** + * Prettier formatting integration using the npm prettier package. + */ + +import * as prettier from "prettier"; +import * as prettierPluginSvelte from "prettier-plugin-svelte"; + +export interface PrettierResult { + /** The formatted output */ + output: string; + /** The formatter IR (doc representation) */ + ir: string; + /** Error message if formatting failed */ + error?: string; +} + +// Type for Prettier's debug API (not officially typed) +interface PrettierDebugApi { + printToDoc: (code: string, options: prettier.Options) => Promise; + formatDoc: (doc: unknown, options?: prettier.Options) => Promise; +} + +/** + * Get the plugins array for a given parser. + */ +function getPluginsForParser(parser: string): prettier.Plugin[] { + if (parser === "svelte") { + return [prettierPluginSvelte]; + } + return []; +} + +/** + * Format code using Prettier and return the result with IR. + * + * @param code - The source code to format + * @param parser - The Prettier parser to use (e.g., "babel", "typescript") + * @returns The formatting result including output, IR, and any error + */ +export async function formatWithPrettier( + code: string, + parser: string, +): Promise { + try { + const plugins = getPluginsForParser(parser); + const options: prettier.Options = { parser, plugins }; + + // Get formatted output + const output = await prettier.format(code, options); + + // Get IR using Prettier's debug API + let ir = ""; + try { + const debugApi = (prettier as unknown as { __debug: PrettierDebugApi }) + .__debug; + if (debugApi?.printToDoc && debugApi?.formatDoc) { + const doc = await debugApi.printToDoc(code, options); + ir = await debugApi.formatDoc(doc, {}); + } + } catch { + // IR extraction is best-effort; don't fail if it doesn't work + ir = "(IR extraction not available)"; + } + + return { output, ir }; + } catch (err) { + const errorMessage = err instanceof Error ? err.message : String(err); + return { + output: code, + ir: "", + error: errorMessage, + }; + } +} diff --git a/packages/prettier-compare/src/watch.ts b/packages/prettier-compare/src/watch.ts new file mode 100644 index 000000000000..fb8a01f39054 --- /dev/null +++ b/packages/prettier-compare/src/watch.ts @@ -0,0 +1,261 @@ +/** + * File watcher for Rust formatter crates with debounced WASM rebuilds. + */ + +// biome-ignore lint/style/useNodejsImportProtocol: auto-suppressed +import { spawn } from "child_process"; +// biome-ignore lint/style/useNodejsImportProtocol: auto-suppressed +import { EventEmitter } from "events"; +// biome-ignore lint/style/useNodejsImportProtocol: auto-suppressed +import { type FSWatcher, watch } from "fs"; +// biome-ignore lint/style/useNodejsImportProtocol: auto-suppressed +import { readdir, stat } from "fs/promises"; +// biome-ignore lint/style/useNodejsImportProtocol: auto-suppressed +import { resolve } from "path"; + +/** Debounce delay in milliseconds */ +const DEBOUNCE_MS = 500; + +/** + * Directories containing Rust files that affect the formatter. + * We watch directories directly because `fs.watch` can't subscribe to glob patterns. + */ +const WATCH_DIRS = [ + "crates/biome_formatter", + "crates/biome_js_formatter", + "crates/biome_json_formatter", + "crates/biome_css_formatter", + "crates/biome_html_formatter", + "crates/biome_graphql_formatter", + "crates/biome_wasm", +]; + +const IGNORED_DIRS = new Set(["target", "node_modules"]); + +function isIgnoredPath(filePath: string): boolean { + return filePath.split(/[/\\]+/).some((segment) => IGNORED_DIRS.has(segment)); +} + +function toError(err: unknown): Error { + return err instanceof Error ? err : new Error(String(err)); +} + +export interface WatcherEvents { + /** Emitted when a rebuild is starting */ + on(event: "rebuilding", listener: (changedFile: string) => void): this; + /** Emitted when a rebuild completes successfully */ + on(event: "rebuilt", listener: () => void): this; + /** Emitted when a rebuild fails */ + on(event: "error", listener: (err: Error) => void): this; +} + +export interface Watcher extends WatcherEvents { + /** Stop watching for changes */ + close(): Promise; +} + +/** + * Create a file watcher for Rust formatter crates. + * + * @param rootDir - The root directory of the Biome repository + * @returns A watcher instance that emits events on file changes + */ +export function createWatcher(rootDir: string): Watcher { + const emitter = new EventEmitter(); + const watchers = new Map(); + let debounceTimer: NodeJS.Timeout | null = null; + let isRebuilding = false; + let lastChangedFile: string | null = null; + + const absoluteDirs = WATCH_DIRS.map((dir) => resolve(rootDir, dir)); + + const scheduleRebuild = (changedFile: string) => { + lastChangedFile = changedFile; + + if (debounceTimer) { + clearTimeout(debounceTimer); + } + + debounceTimer = setTimeout(async () => { + debounceTimer = null; + + if (isRebuilding) { + return; + } + + if (!lastChangedFile) { + return; + } + + isRebuilding = true; + emitter.emit("rebuilding", lastChangedFile); + + try { + await rebuildWasm(rootDir); + emitter.emit("rebuilt"); + } catch (err) { + emitter.emit("error", toError(err)); + } finally { + isRebuilding = false; + lastChangedFile = null; + } + }, DEBOUNCE_MS); + }; + + const handleWatcherEvent = ( + baseDir: string, + eventType: string, + filename?: string | Buffer, + ) => { + if (!filename) { + return; + } + + const fullPath = resolve(baseDir, filename.toString()); + + if (isIgnoredPath(fullPath)) { + return; + } + + (async () => { + if (eventType === "rename") { + try { + const stats = await stat(fullPath); + if (stats.isDirectory()) { + await visitDirectory(fullPath); + } + } catch { + // File or directory might have been removed; ignore. + } + } + + if (fullPath.endsWith(".rs")) { + scheduleRebuild(fullPath); + } + })().catch((err) => { + const error = toError(err); + emitter.emit("error", error); + }); + }; + + const startDirWatcher = async (dir: string): Promise => { + if (watchers.has(dir)) { + return; + } + + try { + const watcher = watch(dir, { persistent: true }, (eventType, filename) => + handleWatcherEvent(dir, eventType, filename ?? undefined), + ); + + watcher.on("error", (err) => { + const error = toError(err); + emitter.emit("error", error); + watcher.close(); + watchers.delete(dir); + }); + + watchers.set(dir, watcher); + } catch (err) { + const error = toError(err); + emitter.emit("error", error); + } + }; + + const visitDirectory = async (dir: string): Promise => { + const normalized = resolve(dir); + + if (isIgnoredPath(normalized) || watchers.has(normalized)) { + return; + } + + try { + const stats = await stat(normalized); + if (!stats.isDirectory()) { + return; + } + // biome-ignore lint/correctness/noUnusedVariables: auto-suppressed + } catch (err) { + return; + } + + await startDirWatcher(normalized); + + try { + const entries = await readdir(normalized, { withFileTypes: true }); + await Promise.all( + entries + .filter((entry) => entry.isDirectory()) + .map((entry) => visitDirectory(resolve(normalized, entry.name))), + ); + } catch (err) { + console.error("Failed to read directory:", normalized, err); + } + }; + + // biome-ignore lint/nursery/noFloatingPromises: its fine here + (async () => { + try { + for (const dir of absoluteDirs) { + await visitDirectory(dir); + } + } catch (err) { + emitter.emit("error", toError(err)); + } + })(); + + // biome-ignore lint/plugin: our demo plugin rule flags this + return Object.assign(emitter, { + close: async () => { + if (debounceTimer) { + clearTimeout(debounceTimer); + debounceTimer = null; + } + + for (const watcher of watchers.values()) { + watcher.close(); + } + + watchers.clear(); + }, + }) as Watcher; +} + +/** + * Rebuild the WASM module using `just build-wasm-node-dev`. + * + * @param rootDir - The root directory of the Biome repository + * @returns A promise that resolves when the build completes + */ +export function rebuildWasm(rootDir: string): Promise { + console.info("Starting WASM rebuild..."); + + return new Promise((resolve, reject) => { + const proc = spawn("just", ["build-wasm-node-dev"], { + cwd: rootDir, + stdio: "pipe", + }); + + let stderr = ""; + + proc.stderr?.on("data", (data) => { + stderr += data.toString(); + }); + + proc.on("close", (code) => { + if (code === 0) { + resolve(); + } else { + const error = new Error( + `WASM build failed with code ${code}:\n${stderr.trim()}`, + ); + reject(error); + } + }); + + proc.on("error", (err) => { + const error = new Error(`Failed to start build process: ${err.message}`); + reject(error); + }); + }); +} diff --git a/packages/prettier-compare/tsconfig.json b/packages/prettier-compare/tsconfig.json new file mode 100644 index 000000000000..48441da07cde --- /dev/null +++ b/packages/prettier-compare/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "jsx": "react-jsx", + "jsxImportSource": "@opentui/react", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "noEmit": true + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f8b765bb19ad..c6a9d9836634 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -28,16 +28,16 @@ importers: devDependencies: '@typescript-eslint/eslint-plugin': specifier: 8.50.1 - version: 8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@1.21.6))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.6))(typescript@5.9.3) + version: 8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: 8.50.1 - version: 8.50.1(eslint@9.39.2(jiti@1.21.6))(typescript@5.9.3) + version: 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) dprint: specifier: 0.51.1 version: 0.51.1 eslint: specifier: 9.39.2 - version: 9.39.2(jiti@1.21.6) + version: 9.39.2(jiti@2.6.1) prettier: specifier: 3.7.4 version: 3.7.4 @@ -58,10 +58,10 @@ importers: version: 5.9.3 vite: specifier: 7.3.1 - version: 7.3.1(@types/node@24.10.9)(jiti@1.21.6) + version: 7.3.1(@types/node@24.10.9)(jiti@2.6.1)(yaml@2.8.2) vitest: specifier: 4.0.17 - version: 4.0.17(@types/node@24.10.9)(happy-dom@20.3.3)(jiti@1.21.6) + version: 4.0.17(@types/node@24.10.9)(happy-dom@20.3.3)(jiti@2.6.1)(yaml@2.8.2) optionalDependencies: '@biomejs/cli-darwin-arm64': specifier: 2.3.11 @@ -147,10 +147,10 @@ importers: version: 5.9.3 vite: specifier: 7.3.1 - version: 7.3.1(@types/node@24.10.9)(jiti@1.21.6) + version: 7.3.1(@types/node@24.10.9)(jiti@2.6.1)(yaml@2.8.2) vitest: specifier: 4.0.17 - version: 4.0.17(@types/node@24.10.9)(happy-dom@20.3.3)(jiti@1.21.6) + version: 4.0.17(@types/node@24.10.9)(happy-dom@20.3.3)(jiti@2.6.1)(yaml@2.8.2) packages/@biomejs/plugin-api: dependencies: @@ -170,6 +170,40 @@ importers: specifier: ^20.3.1 version: 20.3.3 + packages/prettier-compare: + dependencies: + '@biomejs/js-api': + specifier: workspace:* + version: link:../@biomejs/js-api + '@biomejs/wasm-nodejs': + specifier: workspace:* + version: link:../@biomejs/wasm-nodejs + '@opentui/core': + specifier: ^0.1.72 + version: 0.1.72(stage-js@1.0.0-alpha.17)(typescript@5.7.3)(web-tree-sitter@0.25.10) + '@opentui/react': + specifier: ^0.1.72 + version: 0.1.72(react-devtools-core@7.0.1)(react@19.2.3)(stage-js@1.0.0-alpha.17)(typescript@5.7.3)(web-tree-sitter@0.25.10)(ws@8.19.0) + prettier: + specifier: ^3.7.0 + version: 3.7.4 + prettier-plugin-svelte: + specifier: ^3.4.0 + version: 3.4.1(prettier@3.7.4)(svelte@5.46.4) + react: + specifier: ^19.0.0 + version: 19.2.3 + devDependencies: + '@types/node': + specifier: ^22.0.0 + version: 22.19.5 + '@types/react': + specifier: ^19.0.0 + version: 19.2.8 + typescript: + specifier: 5.7.3 + version: 5.7.3 + packages/tailwindcss-config-analyzer: dependencies: tailwindcss: @@ -261,6 +295,9 @@ packages: '@changesets/write@0.4.0': resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} + '@dimforge/rapier2d-simd-compat@0.17.3': + resolution: {integrity: sha512-bijvwWz6NHsNj5e5i1vtd3dU2pDhthSaTUZSh14DUGGKJfw8eMnlWZsxwHBxB/a3AXVNDjL9abuHw1k9FGR+jg==} + '@dprint/darwin-arm64@0.51.1': resolution: {integrity: sha512-C7fkaz0/NGf/X4G9Cq65izdJgerND5jWShOaPiOgGs4A0CyCMKMLRd45m3xKIttuO8x0IQiZVixD22qmVglXmQ==} cpu: [arm64] @@ -539,9 +576,134 @@ packages: '@types/node': optional: true + '@jimp/core@1.6.0': + resolution: {integrity: sha512-EQQlKU3s9QfdJqiSrZWNTxBs3rKXgO2W+GxNXDtwchF3a4IqxDheFX1ti+Env9hdJXDiYLp2jTRjlxhPthsk8w==} + engines: {node: '>=18'} + + '@jimp/diff@1.6.0': + resolution: {integrity: sha512-+yUAQ5gvRC5D1WHYxjBHZI7JBRusGGSLf8AmPRPCenTzh4PA+wZ1xv2+cYqQwTfQHU5tXYOhA0xDytfHUf1Zyw==} + engines: {node: '>=18'} + + '@jimp/file-ops@1.6.0': + resolution: {integrity: sha512-Dx/bVDmgnRe1AlniRpCKrGRm5YvGmUwbDzt+MAkgmLGf+jvBT75hmMEZ003n9HQI/aPnm/YKnXjg/hOpzNCpHQ==} + engines: {node: '>=18'} + + '@jimp/js-bmp@1.6.0': + resolution: {integrity: sha512-FU6Q5PC/e3yzLyBDXupR3SnL3htU7S3KEs4e6rjDP6gNEOXRFsWs6YD3hXuXd50jd8ummy+q2WSwuGkr8wi+Gw==} + engines: {node: '>=18'} + + '@jimp/js-gif@1.6.0': + resolution: {integrity: sha512-N9CZPHOrJTsAUoWkWZstLPpwT5AwJ0wge+47+ix3++SdSL/H2QzyMqxbcDYNFe4MoI5MIhATfb0/dl/wmX221g==} + engines: {node: '>=18'} + + '@jimp/js-jpeg@1.6.0': + resolution: {integrity: sha512-6vgFDqeusblf5Pok6B2DUiMXplH8RhIKAryj1yn+007SIAQ0khM1Uptxmpku/0MfbClx2r7pnJv9gWpAEJdMVA==} + engines: {node: '>=18'} + + '@jimp/js-png@1.6.0': + resolution: {integrity: sha512-AbQHScy3hDDgMRNfG0tPjL88AV6qKAILGReIa3ATpW5QFjBKpisvUaOqhzJ7Reic1oawx3Riyv152gaPfqsBVg==} + engines: {node: '>=18'} + + '@jimp/js-tiff@1.6.0': + resolution: {integrity: sha512-zhReR8/7KO+adijj3h0ZQUOiun3mXUv79zYEAKvE0O+rP7EhgtKvWJOZfRzdZSNv0Pu1rKtgM72qgtwe2tFvyw==} + engines: {node: '>=18'} + + '@jimp/plugin-blit@1.6.0': + resolution: {integrity: sha512-M+uRWl1csi7qilnSK8uxK4RJMSuVeBiO1AY0+7APnfUbQNZm6hCe0CCFv1Iyw1D/Dhb8ph8fQgm5mwM0eSxgVA==} + engines: {node: '>=18'} + + '@jimp/plugin-blur@1.6.0': + resolution: {integrity: sha512-zrM7iic1OTwUCb0g/rN5y+UnmdEsT3IfuCXCJJNs8SZzP0MkZ1eTvuwK9ZidCuMo4+J3xkzCidRwYXB5CyGZTw==} + engines: {node: '>=18'} + + '@jimp/plugin-circle@1.6.0': + resolution: {integrity: sha512-xt1Gp+LtdMKAXfDp3HNaG30SPZW6AQ7dtAtTnoRKorRi+5yCJjKqXRgkewS5bvj8DEh87Ko1ydJfzqS3P2tdWw==} + engines: {node: '>=18'} + + '@jimp/plugin-color@1.6.0': + resolution: {integrity: sha512-J5q8IVCpkBsxIXM+45XOXTrsyfblyMZg3a9eAo0P7VPH4+CrvyNQwaYatbAIamSIN1YzxmO3DkIZXzRjFSz1SA==} + engines: {node: '>=18'} + + '@jimp/plugin-contain@1.6.0': + resolution: {integrity: sha512-oN/n+Vdq/Qg9bB4yOBOxtY9IPAtEfES8J1n9Ddx+XhGBYT1/QTU/JYkGaAkIGoPnyYvmLEDqMz2SGihqlpqfzQ==} + engines: {node: '>=18'} + + '@jimp/plugin-cover@1.6.0': + resolution: {integrity: sha512-Iow0h6yqSC269YUJ8HC3Q/MpCi2V55sMlbkkTTx4zPvd8mWZlC0ykrNDeAy9IJegrQ7v5E99rJwmQu25lygKLA==} + engines: {node: '>=18'} + + '@jimp/plugin-crop@1.6.0': + resolution: {integrity: sha512-KqZkEhvs+21USdySCUDI+GFa393eDIzbi1smBqkUPTE+pRwSWMAf01D5OC3ZWB+xZsNla93BDS9iCkLHA8wang==} + engines: {node: '>=18'} + + '@jimp/plugin-displace@1.6.0': + resolution: {integrity: sha512-4Y10X9qwr5F+Bo5ME356XSACEF55485j5nGdiyJ9hYzjQP9nGgxNJaZ4SAOqpd+k5sFaIeD7SQ0Occ26uIng5Q==} + engines: {node: '>=18'} + + '@jimp/plugin-dither@1.6.0': + resolution: {integrity: sha512-600d1RxY0pKwgyU0tgMahLNKsqEcxGdbgXadCiVCoGd6V6glyCvkNrnnwC0n5aJ56Htkj88PToSdF88tNVZEEQ==} + engines: {node: '>=18'} + + '@jimp/plugin-fisheye@1.6.0': + resolution: {integrity: sha512-E5QHKWSCBFtpgZarlmN3Q6+rTQxjirFqo44ohoTjzYVrDI6B6beXNnPIThJgPr0Y9GwfzgyarKvQuQuqCnnfbA==} + engines: {node: '>=18'} + + '@jimp/plugin-flip@1.6.0': + resolution: {integrity: sha512-/+rJVDuBIVOgwoyVkBjUFHtP+wmW0r+r5OQ2GpatQofToPVbJw1DdYWXlwviSx7hvixTWLKVgRWQ5Dw862emDg==} + engines: {node: '>=18'} + + '@jimp/plugin-hash@1.6.0': + resolution: {integrity: sha512-wWzl0kTpDJgYVbZdajTf+4NBSKvmI3bRI8q6EH9CVeIHps9VWVsUvEyb7rpbcwVLWYuzDtP2R0lTT6WeBNQH9Q==} + engines: {node: '>=18'} + + '@jimp/plugin-mask@1.6.0': + resolution: {integrity: sha512-Cwy7ExSJMZszvkad8NV8o/Z92X2kFUFM8mcDAhNVxU0Q6tA0op2UKRJY51eoK8r6eds/qak3FQkXakvNabdLnA==} + engines: {node: '>=18'} + + '@jimp/plugin-print@1.6.0': + resolution: {integrity: sha512-zarTIJi8fjoGMSI/M3Xh5yY9T65p03XJmPsuNet19K/Q7mwRU6EV2pfj+28++2PV2NJ+htDF5uecAlnGyxFN2A==} + engines: {node: '>=18'} + + '@jimp/plugin-quantize@1.6.0': + resolution: {integrity: sha512-EmzZ/s9StYQwbpG6rUGBCisc3f64JIhSH+ncTJd+iFGtGo0YvSeMdAd+zqgiHpfZoOL54dNavZNjF4otK+mvlg==} + engines: {node: '>=18'} + + '@jimp/plugin-resize@1.6.0': + resolution: {integrity: sha512-uSUD1mqXN9i1SGSz5ov3keRZ7S9L32/mAQG08wUwZiEi5FpbV0K8A8l1zkazAIZi9IJzLlTauRNU41Mi8IF9fA==} + engines: {node: '>=18'} + + '@jimp/plugin-rotate@1.6.0': + resolution: {integrity: sha512-JagdjBLnUZGSG4xjCLkIpQOZZ3Mjbg8aGCCi4G69qR+OjNpOeGI7N2EQlfK/WE8BEHOW5vdjSyglNqcYbQBWRw==} + engines: {node: '>=18'} + + '@jimp/plugin-threshold@1.6.0': + resolution: {integrity: sha512-M59m5dzLoHOVWdM41O8z9SyySzcDn43xHseOH0HavjsfQsT56GGCC4QzU1banJidbUrePhzoEdS42uFE8Fei8w==} + engines: {node: '>=18'} + + '@jimp/types@1.6.0': + resolution: {integrity: sha512-7UfRsiKo5GZTAATxm2qQ7jqmUXP0DxTArztllTcYdyw6Xi5oT4RaoXynVtCD4UyLK5gJgkZJcwonoijrhYFKfg==} + engines: {node: '>=18'} + + '@jimp/utils@1.6.0': + resolution: {integrity: sha512-gqFTGEosKbOkYF/WFj26jMHOI5OH2jeP1MmC/zbK6BF6VJBf8rIC5898dPfSzZEbSA0wbbV5slbntWVc5PKLFA==} + engines: {node: '>=18'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@manypkg/find-root@1.1.0': resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} @@ -560,6 +722,48 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@opentui/core-darwin-arm64@0.1.72': + resolution: {integrity: sha512-RoU48kOrhLZYDBiXaDu1LXS2bwRdlJlFle8eUQiqJjLRbMIY34J/srBuL0JnAS3qKW4J34NepUQa0l0/S43Q3w==} + cpu: [arm64] + os: [darwin] + + '@opentui/core-darwin-x64@0.1.72': + resolution: {integrity: sha512-hHUQw8i2LWPToRW1rjAiRqmNf34iJPS9ve9CJDygvFs5JOqUxN5yrfLfKfE+1bQjfFDHnpqW1HUk96iLhkPj8Q==} + cpu: [x64] + os: [darwin] + + '@opentui/core-linux-arm64@0.1.72': + resolution: {integrity: sha512-63yml0OQ8tVa0JuDF9lBAWiChX6Q+iDO7lKv7c2n0352n/WyPr3iAgq4uSoH49HXuKeAXY/VwHGjvPzjXD/SDA==} + cpu: [arm64] + os: [linux] + + '@opentui/core-linux-x64@0.1.72': + resolution: {integrity: sha512-51veiQXNLvzDsFzsEvt71uK7WhiRe2DnvlJSGBSe6aRRHHxjCFYHzYi7t6bitJqtDTUj+EaMPbH81oZ6xy7tyg==} + cpu: [x64] + os: [linux] + + '@opentui/core-win32-arm64@0.1.72': + resolution: {integrity: sha512-1Ep6OcaYTy1RlLOln+LNN7DL1iNyLwLjG2M8aO0pVJKFvxeD5P7rdRzY065E4uhkHeJIHuduUqxvUjD0dyuwbw==} + cpu: [arm64] + os: [win32] + + '@opentui/core-win32-x64@0.1.72': + resolution: {integrity: sha512-5QUv91UkOINlkEaPky3kaxmJvshcJMBAX7LZtIroduaKBGpWRA1aogNhPZzp+30WkvgOU7aOtUktAZuFXb9WdQ==} + cpu: [x64] + os: [win32] + + '@opentui/core@0.1.72': + resolution: {integrity: sha512-l4WQzubBJ80Q0n77Lxuodjwwm8qj/sOa7IXxEAzzDDXY/7bsIhdSpVhRTt+KevBRlok5J+w/KMKYr8UzkA4/hA==} + peerDependencies: + web-tree-sitter: 0.25.10 + + '@opentui/react@0.1.72': + resolution: {integrity: sha512-pL1qeByRTamjA3mCfbwagaaw7mRXKDSXQDPYO14s65dILzZ6k+qZlsa6rLHfTNQ3dDb5zKJyVDdyn5z59Pv4Pg==} + peerDependencies: + react: '>=19.0.0' + react-devtools-core: ^7.0.1 + ws: ^8.18.0 + '@rollup/rollup-android-arm-eabi@4.46.2': resolution: {integrity: sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==} cpu: [arm] @@ -663,6 +867,14 @@ packages: '@standard-schema/spec@1.0.0': resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + '@sveltejs/acorn-typescript@1.0.8': + resolution: {integrity: sha512-esgN+54+q0NjB0Y/4BomT9samII7jGwNy/2a3wNZbT2A2RpmXsXwUt24LvLhx6jUq2gVk4cWEvcRO6MFQbOfNA==} + peerDependencies: + acorn: ^8.9.0 + + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + '@tombi-toml/cli-darwin-arm64@0.7.19': resolution: {integrity: sha512-LaeR3PuiX3FULXmQhkxvCMYmCMeu6P3eQWcqQA9RPjc1RCZ8E+GxHbkIGyuYTEwpBCRSv7FF5lhFjpO9VMrTDQ==} engines: {node: '>=14.0.0'} @@ -726,12 +938,21 @@ packages: '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} + '@types/node@16.9.1': + resolution: {integrity: sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==} + + '@types/node@22.19.5': + resolution: {integrity: sha512-HfF8+mYcHPcPypui3w3mvzuIErlNOh2OAG+BCeBZCEwyiD5ls2SiCwEyT47OELtf7M3nHxBdu0FsmzdKxkN52Q==} + '@types/node@24.10.9': resolution: {integrity: sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + '@types/react@19.2.8': + resolution: {integrity: sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==} + '@types/whatwg-mimetype@3.0.2': resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==} @@ -826,6 +1047,13 @@ packages: '@vitest/utils@4.0.17': resolution: {integrity: sha512-RG6iy+IzQpa9SB8HAFHJ9Y+pTzI+h8553MrciN9eC6TFBErqrQaTas4vG+MVj8S4uKk8uTT2p0vgZPnTdxd96w==} + '@webgpu/types@0.1.68': + resolution: {integrity: sha512-3ab1B59Ojb6RwjOspYLsTpCzbNB3ZaamIAxBMmvnNkiDoLTZUOBXZ9p5nAYVEkQlDdf6qAZWi1pqj9+ypiqznA==} + + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -851,23 +1079,44 @@ packages: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + any-base@1.1.0: + resolution: {integrity: sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==} + argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} + await-to-js@3.0.0: + resolution: {integrity: sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g==} + engines: {node: '>=6.0.0'} + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} + bmp-ts@1.0.9: + resolution: {integrity: sha512-cTEHk2jLrPyi+12M3dhpEbnnPOsaZuq7C45ylbbQIiWgDFZq4UVYPEY5mlqjvsj/6gJv9qX5sa+ebDzLXT28Vw==} + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -878,6 +1127,37 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + + bun-ffi-structs@0.1.2: + resolution: {integrity: sha512-Lh1oQAYHDcnesJauieA4UNkWGXY9hYck7OA5IaRwE3Bp6K2F2pJSNYqq+hIy7P3uOvo3km3oxS8304g5gDMl/w==} + peerDependencies: + typescript: ^5 + + bun-webgpu-darwin-arm64@0.1.4: + resolution: {integrity: sha512-eDgLN9teKTfmvrCqgwwmWNsNszxYs7IZdCqk0S1DCarvMhr4wcajoSBlA/nQA0/owwLduPTS8xxCnQp4/N/gDg==} + cpu: [arm64] + os: [darwin] + + bun-webgpu-darwin-x64@0.1.4: + resolution: {integrity: sha512-X+PjwJUWenUmdQBP8EtdItMyieQ6Nlpn+BH518oaouDiSnWj5+b0Y7DNDZJq7Ezom4EaxmqL/uGYZK3aCQ7CXg==} + cpu: [x64] + os: [darwin] + + bun-webgpu-linux-x64@0.1.4: + resolution: {integrity: sha512-zMLs2YIGB+/jxrYFXaFhVKX/GBt05UTF45lc9srcHc9JXGjEj+12CIo1CHLTAWatXMTqt0Jsu6ukWEoWVT/ayA==} + cpu: [x64] + os: [linux] + + bun-webgpu-win32-x64@0.1.4: + resolution: {integrity: sha512-Z5yAK28xrcm8Wb5k7TZ8FJKpOI/r+aVCRdlHYAqI2SDJFN3nD4mJs900X6kNVmG/xFzb5yOuKVYWGg+6ZXWbyA==} + cpu: [x64] + os: [win32] + + bun-webgpu@0.1.4: + resolution: {integrity: sha512-Kw+HoXl1PMWJTh9wvh63SSRofTA8vYBFCw0XEP1V1fFdQEDhI8Sgf73sdndE/oDpN/7CMx0Yv/q8FCvO39ROMQ==} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -897,6 +1177,10 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -911,6 +1195,9 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + dataloader@1.4.0: resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==} @@ -930,6 +1217,13 @@ packages: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} + devalue@5.6.2: + resolution: {integrity: sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==} + + diff@8.0.2: + resolution: {integrity: sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==} + engines: {node: '>=0.3.1'} + dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -984,6 +1278,9 @@ packages: jiti: optional: true + esm-env@1.2.2: + resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==} + espree@10.4.0: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -997,6 +1294,9 @@ packages: resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} + esrap@2.2.1: + resolution: {integrity: sha512-GiYWG34AN/4CUyaWAgunGt0Rxvr1PTMlGC0vvEov/uOQYWne2bpN03Um+k8jT+q3op33mKouP2zeJ6OlM+qeUg==} + esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} @@ -1012,6 +1312,17 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + exif-parser@0.1.12: + resolution: {integrity: sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==} + expect-type@1.2.2: resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} engines: {node: '>=12.0.0'} @@ -1022,8 +1333,8 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} fast-json-stable-stringify@2.1.0: @@ -1048,6 +1359,10 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} + file-type@16.5.4: + resolution: {integrity: sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==} + engines: {node: '>=10'} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -1084,6 +1399,9 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + gifwrap@0.10.1: + resolution: {integrity: sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1123,6 +1441,9 @@ packages: resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} engines: {node: '>=0.10.0'} + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1131,6 +1452,9 @@ packages: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} + image-q@4.0.0: + resolution: {integrity: sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw==} + import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} @@ -1155,6 +1479,9 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-reference@3.0.3: + resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} + is-subdir@1.2.0: resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} engines: {node: '>=4'} @@ -1166,10 +1493,17 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - jiti@1.21.6: - resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} + jimp@1.6.0: + resolution: {integrity: sha512-YcwCHw1kiqEeI5xRpDlPPBGL2EOpBKLwO4yIBJcXWHPj5PnA5urGq0jbyhM5KoNpypQ6VboSoxc9D8HyfvngSg==} + engines: {node: '>=18'} + + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + jpeg-js@0.4.4: + resolution: {integrity: sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -1200,6 +1534,9 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + locate-character@3.0.0: + resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} + locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -1229,6 +1566,11 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mime@3.0.0: + resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} + engines: {node: '>=10.0.0'} + hasBin: true + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -1267,6 +1609,9 @@ packages: obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + omggif@1.0.10: + resolution: {integrity: sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -1305,10 +1650,22 @@ packages: package-manager-detector@0.2.9: resolution: {integrity: sha512-+vYvA/Y31l8Zk8dwxHhL3JfTuHPm6tlxM2A3GeQyl7ovYnSp1+mzAxClxaOr0qO1TtPxbQxetI7v5XqKLJZk7Q==} + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-bmfont-ascii@1.0.6: + resolution: {integrity: sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA==} + + parse-bmfont-binary@1.0.6: + resolution: {integrity: sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA==} + + parse-bmfont-xml@1.1.6: + resolution: {integrity: sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA==} + parse-json@8.3.0: resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==} engines: {node: '>=18'} @@ -1328,6 +1685,10 @@ packages: pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + peek-readable@4.1.0: + resolution: {integrity: sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==} + engines: {node: '>=8'} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1343,6 +1704,24 @@ packages: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} + pixelmatch@5.3.0: + resolution: {integrity: sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q==} + hasBin: true + + planck@1.4.2: + resolution: {integrity: sha512-mNbhnV3g8X2rwGxzcesjmN8BDA6qfXgQxXVMkWau9MCRlQY0RLNEkyHlVp6yFy/X6qrzAXyNONCnZ1cGDLrNew==} + engines: {node: '>=14.0'} + peerDependencies: + stage-js: ^1.0.0-alpha.12 + + pngjs@6.0.0: + resolution: {integrity: sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==} + engines: {node: '>=12.13.0'} + + pngjs@7.0.0: + resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} + engines: {node: '>=14.19.0'} + postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -1351,6 +1730,12 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + prettier-plugin-svelte@3.4.1: + resolution: {integrity: sha512-xL49LCloMoZRvSwa6IEdN2GV6cq2IqpYGstYtMT+5wmml1/dClEoI0MZR78MiVPpu6BdQFfN0/y73yO6+br5Pg==} + peerDependencies: + prettier: ^3.0.0 + svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0 + prettier@2.8.8: resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} engines: {node: '>=10.13.0'} @@ -1361,6 +1746,10 @@ packages: engines: {node: '>=14'} hasBin: true + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -1368,6 +1757,19 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + react-devtools-core@7.0.1: + resolution: {integrity: sha512-C3yNvRHaizlpiASzy7b9vbnBGLrhvdhl1CbdU6EnZgxPNbai60szdLtl+VL76UNOt5bOoVTOz5rNWZxgGt+Gsw==} + + react-reconciler@0.32.0: + resolution: {integrity: sha512-2NPMOzgTlG0ZWdIf3qG+dcbLSoAc/uLfOwckc3ofy5sSK0pLJqnQLpUFxvGcN2rlXSjnVtGeeFLNimCQEj5gOQ==} + engines: {node: '>=0.10.0'} + peerDependencies: + react: ^19.1.0 + + react@19.2.3: + resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} + engines: {node: '>=0.10.0'} + read-package-up@12.0.0: resolution: {integrity: sha512-Q5hMVBYur/eQNWDdbF4/Wqqr9Bjvtrw2kjGxxBbKLbx8bVCL8gcArjTy8zDUuLGQicftpMuU0riQNcAsbtOVsw==} engines: {node: '>=20'} @@ -1380,6 +1782,14 @@ packages: resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} engines: {node: '>=6'} + readable-stream@4.7.0: + resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + readable-web-to-node-stream@3.0.4: + resolution: {integrity: sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw==} + engines: {node: '>=8'} + regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} @@ -1403,14 +1813,29 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sax@1.4.4: + resolution: {integrity: sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==} + engines: {node: '>=11.0.0'} + + scheduler@0.26.0: + resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + semver@7.6.3: resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} hasBin: true + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -1419,6 +1844,10 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + shell-quote@1.8.3: + resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} + engines: {node: '>= 0.4'} + siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -1426,6 +1855,10 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + simple-xml-to-json@1.2.3: + resolution: {integrity: sha512-kWJDCr9EWtZ+/EYYM5MareWj2cRnZGF93YDNpH4jQiHB+hBIZnfPFSQiVMzZOdk+zXWqTZ/9fTeQNu2DqeiudA==} + engines: {node: '>=20.12.2'} + slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -1455,9 +1888,16 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + stage-js@1.0.0-alpha.17: + resolution: {integrity: sha512-AzlMO+t51v6cFvKZ+Oe9DJnL1OXEH5s9bEy6di5aOrUpcP7PCzI/wIeXF0u3zg0L89gwnceoKxrLId0ZpYnNXw==} + engines: {node: '>=18.0'} + std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -1470,10 +1910,18 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + strtok3@6.3.0: + resolution: {integrity: sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==} + engines: {node: '>=10'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + svelte@5.46.4: + resolution: {integrity: sha512-VJwdXrmv9L8L7ZasJeWcCjoIuMRVbhuxbss0fpVnR8yorMmjNDwcjIH08vS6wmSzzzgAG5CADQ1JuXPS2nwt9w==} + engines: {node: '>=18'} + tagged-tag@1.0.0: resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} engines: {node: '>=20'} @@ -1485,9 +1933,15 @@ packages: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} + three@0.177.0: + resolution: {integrity: sha512-EiXv5/qWAaGI+Vz2A+JfavwYCMdGjxVsrn3oBwllUoqYeaBO75J63ZfyaQKoiLrqNHoTlUc6PFgMXnS0kI45zg==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + tinycolor2@1.6.0: + resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} + tinyexec@1.0.2: resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} engines: {node: '>=18'} @@ -1504,6 +1958,10 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + token-types@4.2.1: + resolution: {integrity: sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==} + engines: {node: '>=10'} + tombi@0.7.19: resolution: {integrity: sha512-vYnEUwNVmspYN3rWcsCyMuT6DmYgB0ity01K/WRNJ9qLYgtS1GnV7LB5753ed9jCno2q/8772Jcdy9A7TAxCBw==} engines: {node: '>=14.0.0'} @@ -1530,11 +1988,19 @@ packages: resolution: {integrity: sha512-xxCJm+Bckc6kQBknN7i9fnP/xobQRsRQxR01CztFkp/h++yfVxUUcmMgfR2HttJx/dpWjS9ubVuyspJv24Q9DA==} engines: {node: '>=20'} + typescript@5.7.3: + resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} + engines: {node: '>=14.17'} + hasBin: true + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} @@ -1549,6 +2015,9 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + utif2@4.1.0: + resolution: {integrity: sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w==} + validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} @@ -1626,6 +2095,14 @@ packages: jsdom: optional: true + web-tree-sitter@0.25.10: + resolution: {integrity: sha512-Y09sF44/13XvgVKgO2cNDw5rGk6s26MgoZPXLESvMXeefBf7i6/73eFurre0IsTW6E14Y0ArIzhUMmjoc7xyzA==} + peerDependencies: + '@types/emscripten': ^1.40.0 + peerDependenciesMeta: + '@types/emscripten': + optional: true + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -1650,6 +2127,18 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + ws@7.5.10: + resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + ws@8.19.0: resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} engines: {node: '>=10.0.0'} @@ -1662,10 +2151,35 @@ packages: utf-8-validate: optional: true + xml-parse-from-string@1.0.1: + resolution: {integrity: sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g==} + + xml2js@0.5.0: + resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} + engines: {node: '>=4.0.0'} + + xmlbuilder@11.0.1: + resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} + engines: {node: '>=4.0'} + + yaml@2.8.2: + resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} + engines: {node: '>= 14.6'} + hasBin: true + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yoga-layout@3.2.1: + resolution: {integrity: sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==} + + zimmerframe@1.1.4: + resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==} + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + ignoredOptionalDependencies: - '@biomejs/cli*-' @@ -1697,7 +2211,7 @@ snapshots: outdent: 0.5.0 prettier: 2.8.8 resolve-from: 5.0.0 - semver: 7.6.3 + semver: 7.7.3 '@changesets/assemble-release-plan@6.0.9': dependencies: @@ -1706,7 +2220,7 @@ snapshots: '@changesets/should-skip-package': 0.1.2 '@changesets/types': 6.1.0 '@manypkg/get-packages': 1.1.3 - semver: 7.6.3 + semver: 7.7.3 '@changesets/changelog-git@0.2.1': dependencies: @@ -1772,7 +2286,7 @@ snapshots: '@changesets/types': 6.1.0 '@manypkg/get-packages': 1.1.3 picocolors: 1.1.1 - semver: 7.6.3 + semver: 7.7.3 '@changesets/get-github-info@0.7.0': dependencies: @@ -1842,6 +2356,9 @@ snapshots: human-id: 4.1.1 prettier: 2.8.8 + '@dimforge/rapier2d-simd-compat@0.17.3': + optional: true + '@dprint/darwin-arm64@0.51.1': optional: true @@ -1953,9 +2470,9 @@ snapshots: '@esbuild/win32-x64@0.27.2': optional: true - '@eslint-community/eslint-utils@4.9.0(eslint@9.39.2(jiti@1.21.6))': + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.2(jiti@2.6.1))': dependencies: - eslint: 9.39.2(jiti@1.21.6) + eslint: 9.39.2(jiti@2.6.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} @@ -2019,8 +2536,214 @@ snapshots: optionalDependencies: '@types/node': 24.10.9 + '@jimp/core@1.6.0': + dependencies: + '@jimp/file-ops': 1.6.0 + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + await-to-js: 3.0.0 + exif-parser: 0.1.12 + file-type: 16.5.4 + mime: 3.0.0 + + '@jimp/diff@1.6.0': + dependencies: + '@jimp/plugin-resize': 1.6.0 + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + pixelmatch: 5.3.0 + + '@jimp/file-ops@1.6.0': {} + + '@jimp/js-bmp@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + bmp-ts: 1.0.9 + + '@jimp/js-gif@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/types': 1.6.0 + gifwrap: 0.10.1 + omggif: 1.0.10 + + '@jimp/js-jpeg@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/types': 1.6.0 + jpeg-js: 0.4.4 + + '@jimp/js-png@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/types': 1.6.0 + pngjs: 7.0.0 + + '@jimp/js-tiff@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/types': 1.6.0 + utif2: 4.1.0 + + '@jimp/plugin-blit@1.6.0': + dependencies: + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-blur@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/utils': 1.6.0 + + '@jimp/plugin-circle@1.6.0': + dependencies: + '@jimp/types': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-color@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + tinycolor2: 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-contain@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/plugin-blit': 1.6.0 + '@jimp/plugin-resize': 1.6.0 + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-cover@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/plugin-crop': 1.6.0 + '@jimp/plugin-resize': 1.6.0 + '@jimp/types': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-crop@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-displace@1.6.0': + dependencies: + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-dither@1.6.0': + dependencies: + '@jimp/types': 1.6.0 + + '@jimp/plugin-fisheye@1.6.0': + dependencies: + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-flip@1.6.0': + dependencies: + '@jimp/types': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-hash@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/js-bmp': 1.6.0 + '@jimp/js-jpeg': 1.6.0 + '@jimp/js-png': 1.6.0 + '@jimp/js-tiff': 1.6.0 + '@jimp/plugin-color': 1.6.0 + '@jimp/plugin-resize': 1.6.0 + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + any-base: 1.1.0 + + '@jimp/plugin-mask@1.6.0': + dependencies: + '@jimp/types': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-print@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/js-jpeg': 1.6.0 + '@jimp/js-png': 1.6.0 + '@jimp/plugin-blit': 1.6.0 + '@jimp/types': 1.6.0 + parse-bmfont-ascii: 1.0.6 + parse-bmfont-binary: 1.0.6 + parse-bmfont-xml: 1.1.6 + simple-xml-to-json: 1.2.3 + zod: 3.25.76 + + '@jimp/plugin-quantize@1.6.0': + dependencies: + image-q: 4.0.0 + zod: 3.25.76 + + '@jimp/plugin-resize@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/types': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-rotate@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/plugin-crop': 1.6.0 + '@jimp/plugin-resize': 1.6.0 + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + zod: 3.25.76 + + '@jimp/plugin-threshold@1.6.0': + dependencies: + '@jimp/core': 1.6.0 + '@jimp/plugin-color': 1.6.0 + '@jimp/plugin-hash': 1.6.0 + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + zod: 3.25.76 + + '@jimp/types@1.6.0': + dependencies: + zod: 3.25.76 + + '@jimp/utils@1.6.0': + dependencies: + '@jimp/types': 1.6.0 + tinycolor2: 1.6.0 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + '@jridgewell/sourcemap-codec@1.5.5': {} + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + '@manypkg/find-root@1.1.0': dependencies: '@babel/runtime': 7.26.7 @@ -2049,6 +2772,58 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 + '@opentui/core-darwin-arm64@0.1.72': + optional: true + + '@opentui/core-darwin-x64@0.1.72': + optional: true + + '@opentui/core-linux-arm64@0.1.72': + optional: true + + '@opentui/core-linux-x64@0.1.72': + optional: true + + '@opentui/core-win32-arm64@0.1.72': + optional: true + + '@opentui/core-win32-x64@0.1.72': + optional: true + + '@opentui/core@0.1.72(stage-js@1.0.0-alpha.17)(typescript@5.7.3)(web-tree-sitter@0.25.10)': + dependencies: + bun-ffi-structs: 0.1.2(typescript@5.7.3) + diff: 8.0.2 + jimp: 1.6.0 + web-tree-sitter: 0.25.10 + yoga-layout: 3.2.1 + optionalDependencies: + '@dimforge/rapier2d-simd-compat': 0.17.3 + '@opentui/core-darwin-arm64': 0.1.72 + '@opentui/core-darwin-x64': 0.1.72 + '@opentui/core-linux-arm64': 0.1.72 + '@opentui/core-linux-x64': 0.1.72 + '@opentui/core-win32-arm64': 0.1.72 + '@opentui/core-win32-x64': 0.1.72 + bun-webgpu: 0.1.4 + planck: 1.4.2(stage-js@1.0.0-alpha.17) + three: 0.177.0 + transitivePeerDependencies: + - stage-js + - typescript + + '@opentui/react@0.1.72(react-devtools-core@7.0.1)(react@19.2.3)(stage-js@1.0.0-alpha.17)(typescript@5.7.3)(web-tree-sitter@0.25.10)(ws@8.19.0)': + dependencies: + '@opentui/core': 0.1.72(stage-js@1.0.0-alpha.17)(typescript@5.7.3)(web-tree-sitter@0.25.10) + react: 19.2.3 + react-devtools-core: 7.0.1 + react-reconciler: 0.32.0(react@19.2.3) + ws: 8.19.0 + transitivePeerDependencies: + - stage-js + - typescript + - web-tree-sitter + '@rollup/rollup-android-arm-eabi@4.46.2': optional: true @@ -2111,6 +2886,12 @@ snapshots: '@standard-schema/spec@1.0.0': {} + '@sveltejs/acorn-typescript@1.0.8(acorn@8.15.0)': + dependencies: + acorn: 8.15.0 + + '@tokenizer/token@0.3.0': {} + '@tombi-toml/cli-darwin-arm64@0.7.19': optional: true @@ -2147,27 +2928,37 @@ snapshots: '@types/node@12.20.55': {} + '@types/node@16.9.1': {} + + '@types/node@22.19.5': + dependencies: + undici-types: 6.21.0 + '@types/node@24.10.9': dependencies: undici-types: 7.16.0 '@types/normalize-package-data@2.4.4': {} + '@types/react@19.2.8': + dependencies: + csstype: 3.2.3 + '@types/whatwg-mimetype@3.0.2': {} '@types/ws@8.18.1': dependencies: - '@types/node': 24.10.9 + '@types/node': 22.19.5 - '@typescript-eslint/eslint-plugin@8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@1.21.6))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.6))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.50.1(eslint@9.39.2(jiti@1.21.6))(typescript@5.9.3) + '@typescript-eslint/parser': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.50.1 - '@typescript-eslint/type-utils': 8.50.1(eslint@9.39.2(jiti@1.21.6))(typescript@5.9.3) - '@typescript-eslint/utils': 8.50.1(eslint@9.39.2(jiti@1.21.6))(typescript@5.9.3) + '@typescript-eslint/type-utils': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.50.1 - eslint: 9.39.2(jiti@1.21.6) + eslint: 9.39.2(jiti@2.6.1) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.1.0(typescript@5.9.3) @@ -2175,14 +2966,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@1.21.6))(typescript@5.9.3)': + '@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.50.1 '@typescript-eslint/types': 8.50.1 '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.50.1 debug: 4.4.1 - eslint: 9.39.2(jiti@1.21.6) + eslint: 9.39.2(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -2205,13 +2996,13 @@ snapshots: dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.50.1(eslint@9.39.2(jiti@1.21.6))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.50.1 '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.50.1(eslint@9.39.2(jiti@1.21.6))(typescript@5.9.3) + '@typescript-eslint/utils': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.1 - eslint: 9.39.2(jiti@1.21.6) + eslint: 9.39.2(jiti@2.6.1) ts-api-utils: 2.1.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: @@ -2227,20 +3018,20 @@ snapshots: '@typescript-eslint/visitor-keys': 8.50.1 debug: 4.4.1 minimatch: 9.0.5 - semver: 7.6.3 + semver: 7.7.3 tinyglobby: 0.2.15 ts-api-utils: 2.1.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.50.1(eslint@9.39.2(jiti@1.21.6))(typescript@5.9.3)': + '@typescript-eslint/utils@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@1.21.6)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) '@typescript-eslint/scope-manager': 8.50.1 '@typescript-eslint/types': 8.50.1 '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) - eslint: 9.39.2(jiti@1.21.6) + eslint: 9.39.2(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -2259,13 +3050,13 @@ snapshots: chai: 6.2.1 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.17(vite@7.3.1(@types/node@24.10.9)(jiti@1.21.6))': + '@vitest/mocker@4.0.17(vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.0.17 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@24.10.9)(jiti@1.21.6) + vite: 7.3.1(@types/node@24.10.9)(jiti@2.6.1)(yaml@2.8.2) '@vitest/pretty-format@4.0.17': dependencies: @@ -2289,6 +3080,13 @@ snapshots: '@vitest/pretty-format': 4.0.17 tinyrainbow: 3.0.3 + '@webgpu/types@0.1.68': + optional: true + + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + acorn-jsx@5.3.2(acorn@8.15.0): dependencies: acorn: 8.15.0 @@ -2310,20 +3108,32 @@ snapshots: dependencies: color-convert: 2.0.1 + any-base@1.1.0: {} + argparse@1.0.10: dependencies: sprintf-js: 1.0.3 argparse@2.0.1: {} + aria-query@5.3.2: {} + array-union@2.1.0: {} + await-to-js@3.0.0: {} + + axobject-query@4.1.0: {} + balanced-match@1.0.2: {} + base64-js@1.5.1: {} + better-path-resolve@1.0.0: dependencies: is-windows: 1.0.2 + bmp-ts@1.0.9: {} + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -2337,6 +3147,37 @@ snapshots: dependencies: fill-range: 7.1.1 + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + bun-ffi-structs@0.1.2(typescript@5.7.3): + dependencies: + typescript: 5.7.3 + + bun-webgpu-darwin-arm64@0.1.4: + optional: true + + bun-webgpu-darwin-x64@0.1.4: + optional: true + + bun-webgpu-linux-x64@0.1.4: + optional: true + + bun-webgpu-win32-x64@0.1.4: + optional: true + + bun-webgpu@0.1.4: + dependencies: + '@webgpu/types': 0.1.68 + optionalDependencies: + bun-webgpu-darwin-arm64: 0.1.4 + bun-webgpu-darwin-x64: 0.1.4 + bun-webgpu-linux-x64: 0.1.4 + bun-webgpu-win32-x64: 0.1.4 + optional: true + callsites@3.1.0: {} chai@6.2.1: {} @@ -2350,6 +3191,8 @@ snapshots: ci-info@3.9.0: {} + clsx@2.1.1: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -2364,6 +3207,8 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + csstype@3.2.3: {} + dataloader@1.4.0: {} debug@4.4.1: @@ -2374,6 +3219,10 @@ snapshots: detect-indent@6.1.0: {} + devalue@5.6.2: {} + + diff@8.0.2: {} + dir-glob@3.0.1: dependencies: path-type: 4.0.0 @@ -2443,9 +3292,9 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.39.2(jiti@1.21.6): + eslint@9.39.2(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@1.21.6)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.21.1 '@eslint/config-helpers': 0.4.2 @@ -2480,10 +3329,12 @@ snapshots: natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: - jiti: 1.21.6 + jiti: 2.6.1 transitivePeerDependencies: - supports-color + esm-env@1.2.2: {} + espree@10.4.0: dependencies: acorn: 8.15.0 @@ -2496,6 +3347,10 @@ snapshots: dependencies: estraverse: 5.3.0 + esrap@2.2.1: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + esrecurse@4.3.0: dependencies: estraverse: 5.3.0 @@ -2508,13 +3363,19 @@ snapshots: esutils@2.0.3: {} + event-target-shim@5.0.1: {} + + events@3.3.0: {} + + exif-parser@0.1.12: {} + expect-type@1.2.2: {} extendable-error@0.1.7: {} fast-deep-equal@3.1.3: {} - fast-glob@3.3.2: + fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 @@ -2538,6 +3399,12 @@ snapshots: dependencies: flat-cache: 4.0.1 + file-type@16.5.4: + dependencies: + readable-web-to-node-stream: 3.0.4 + strtok3: 6.3.0 + token-types: 4.2.1 + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -2576,6 +3443,11 @@ snapshots: fsevents@2.3.3: optional: true + gifwrap@0.10.1: + dependencies: + image-q: 4.0.0 + omggif: 1.0.10 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -2590,7 +3462,7 @@ snapshots: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.3.2 + fast-glob: 3.3.3 ignore: 5.3.2 merge2: 1.4.1 slash: 3.0.0 @@ -2621,10 +3493,16 @@ snapshots: dependencies: safer-buffer: 2.1.2 + ieee754@1.2.1: {} + ignore@5.3.2: {} ignore@7.0.5: {} + image-q@4.0.0: + dependencies: + '@types/node': 16.9.1 + import-fresh@3.3.0: dependencies: parent-module: 1.0.1 @@ -2642,6 +3520,10 @@ snapshots: is-number@7.0.0: {} + is-reference@3.0.3: + dependencies: + '@types/estree': 1.0.8 + is-subdir@1.2.0: dependencies: better-path-resolve: 1.0.0 @@ -2650,9 +3532,41 @@ snapshots: isexe@2.0.0: {} - jiti@1.21.6: + jimp@1.6.0: + dependencies: + '@jimp/core': 1.6.0 + '@jimp/diff': 1.6.0 + '@jimp/js-bmp': 1.6.0 + '@jimp/js-gif': 1.6.0 + '@jimp/js-jpeg': 1.6.0 + '@jimp/js-png': 1.6.0 + '@jimp/js-tiff': 1.6.0 + '@jimp/plugin-blit': 1.6.0 + '@jimp/plugin-blur': 1.6.0 + '@jimp/plugin-circle': 1.6.0 + '@jimp/plugin-color': 1.6.0 + '@jimp/plugin-contain': 1.6.0 + '@jimp/plugin-cover': 1.6.0 + '@jimp/plugin-crop': 1.6.0 + '@jimp/plugin-displace': 1.6.0 + '@jimp/plugin-dither': 1.6.0 + '@jimp/plugin-fisheye': 1.6.0 + '@jimp/plugin-flip': 1.6.0 + '@jimp/plugin-hash': 1.6.0 + '@jimp/plugin-mask': 1.6.0 + '@jimp/plugin-print': 1.6.0 + '@jimp/plugin-quantize': 1.6.0 + '@jimp/plugin-resize': 1.6.0 + '@jimp/plugin-rotate': 1.6.0 + '@jimp/plugin-threshold': 1.6.0 + '@jimp/types': 1.6.0 + '@jimp/utils': 1.6.0 + + jiti@2.6.1: optional: true + jpeg-js@0.4.4: {} + js-tokens@4.0.0: {} js-yaml@3.14.1: @@ -2683,6 +3597,8 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + locate-character@3.0.0: {} + locate-path@5.0.0: dependencies: p-locate: 4.1.0 @@ -2708,6 +3624,8 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 + mime@3.0.0: {} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -2731,11 +3649,13 @@ snapshots: normalize-package-data@8.0.0: dependencies: hosted-git-info: 9.0.2 - semver: 7.6.3 + semver: 7.7.3 validate-npm-package-license: 3.0.4 obug@2.1.1: {} + omggif@1.0.10: {} + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -2773,10 +3693,21 @@ snapshots: package-manager-detector@0.2.9: {} + pako@1.0.11: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 + parse-bmfont-ascii@1.0.6: {} + + parse-bmfont-binary@1.0.6: {} + + parse-bmfont-xml@1.1.6: + dependencies: + xml-parse-from-string: 1.0.1 + xml2js: 0.5.0 + parse-json@8.3.0: dependencies: '@babel/code-frame': 7.27.1 @@ -2791,6 +3722,8 @@ snapshots: pathe@2.0.3: {} + peek-readable@4.1.0: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -2799,6 +3732,19 @@ snapshots: pify@4.0.1: {} + pixelmatch@5.3.0: + dependencies: + pngjs: 6.0.0 + + planck@1.4.2(stage-js@1.0.0-alpha.17): + dependencies: + stage-js: 1.0.0-alpha.17 + optional: true + + pngjs@6.0.0: {} + + pngjs@7.0.0: {} + postcss@8.5.6: dependencies: nanoid: 3.3.11 @@ -2807,14 +3753,36 @@ snapshots: prelude-ls@1.2.1: {} + prettier-plugin-svelte@3.4.1(prettier@3.7.4)(svelte@5.46.4): + dependencies: + prettier: 3.7.4 + svelte: 5.46.4 + prettier@2.8.8: {} prettier@3.7.4: {} + process@0.11.10: {} + punycode@2.3.1: {} queue-microtask@1.2.3: {} + react-devtools-core@7.0.1: + dependencies: + shell-quote: 1.8.3 + ws: 7.5.10 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + react-reconciler@0.32.0(react@19.2.3): + dependencies: + react: 19.2.3 + scheduler: 0.26.0 + + react@19.2.3: {} + read-package-up@12.0.0: dependencies: find-up-simple: 1.0.1 @@ -2836,6 +3804,18 @@ snapshots: pify: 4.0.1 strip-bom: 3.0.0 + readable-stream@4.7.0: + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + + readable-web-to-node-stream@3.0.4: + dependencies: + readable-stream: 4.7.0 + regenerator-runtime@0.14.1: {} resolve-from@4.0.0: {} @@ -2874,20 +3854,32 @@ snapshots: dependencies: queue-microtask: 1.2.3 + safe-buffer@5.2.1: {} + safer-buffer@2.1.2: {} + sax@1.4.4: {} + + scheduler@0.26.0: {} + semver@7.6.3: {} + semver@7.7.3: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 shebang-regex@3.0.0: {} + shell-quote@1.8.3: {} + siginfo@2.0.0: {} signal-exit@4.1.0: {} + simple-xml-to-json@1.2.3: {} + slash@3.0.0: {} source-map-js@1.2.1: {} @@ -2915,8 +3907,15 @@ snapshots: stackback@0.0.2: {} + stage-js@1.0.0-alpha.17: + optional: true + std-env@3.10.0: {} + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -2925,18 +3924,46 @@ snapshots: strip-json-comments@3.1.1: {} + strtok3@6.3.0: + dependencies: + '@tokenizer/token': 0.3.0 + peek-readable: 4.1.0 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 + svelte@5.46.4: + dependencies: + '@jridgewell/remapping': 2.3.5 + '@jridgewell/sourcemap-codec': 1.5.5 + '@sveltejs/acorn-typescript': 1.0.8(acorn@8.15.0) + '@types/estree': 1.0.8 + acorn: 8.15.0 + aria-query: 5.3.2 + axobject-query: 4.1.0 + clsx: 2.1.1 + devalue: 5.6.2 + esm-env: 1.2.2 + esrap: 2.2.1 + is-reference: 3.0.3 + locate-character: 3.0.0 + magic-string: 0.30.21 + zimmerframe: 1.1.4 + tagged-tag@1.0.0: {} tailwindcss@4.1.18: {} term-size@2.2.1: {} + three@0.177.0: + optional: true + tinybench@2.9.0: {} + tinycolor2@1.6.0: {} + tinyexec@1.0.2: {} tinyglobby@0.2.15: @@ -2950,6 +3977,11 @@ snapshots: dependencies: is-number: 7.0.0 + token-types@4.2.1: + dependencies: + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + tombi@0.7.19: optionalDependencies: '@tombi-toml/cli-darwin-arm64': 0.7.19 @@ -2977,8 +4009,12 @@ snapshots: dependencies: tagged-tag: 1.0.0 + typescript@5.7.3: {} + typescript@5.9.3: {} + undici-types@6.21.0: {} + undici-types@7.16.0: {} unicorn-magic@0.3.0: {} @@ -2989,12 +4025,16 @@ snapshots: dependencies: punycode: 2.3.1 + utif2@4.1.0: + dependencies: + pako: 1.0.11 + validate-npm-package-license@3.0.4: dependencies: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - vite@7.3.1(@types/node@24.10.9)(jiti@1.21.6): + vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(yaml@2.8.2): dependencies: esbuild: 0.27.2 fdir: 6.5.0(picomatch@4.0.3) @@ -3005,12 +4045,13 @@ snapshots: optionalDependencies: '@types/node': 24.10.9 fsevents: 2.3.3 - jiti: 1.21.6 + jiti: 2.6.1 + yaml: 2.8.2 - vitest@4.0.17(@types/node@24.10.9)(happy-dom@20.3.3)(jiti@1.21.6): + vitest@4.0.17(@types/node@24.10.9)(happy-dom@20.3.3)(jiti@2.6.1)(yaml@2.8.2): dependencies: '@vitest/expect': 4.0.17 - '@vitest/mocker': 4.0.17(vite@7.3.1(@types/node@24.10.9)(jiti@1.21.6)) + '@vitest/mocker': 4.0.17(vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(yaml@2.8.2)) '@vitest/pretty-format': 4.0.17 '@vitest/runner': 4.0.17 '@vitest/snapshot': 4.0.17 @@ -3027,7 +4068,7 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@24.10.9)(jiti@1.21.6) + vite: 7.3.1(@types/node@24.10.9)(jiti@2.6.1)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.10.9 @@ -3045,6 +4086,8 @@ snapshots: - tsx - yaml + web-tree-sitter@0.25.10: {} + webidl-conversions@3.0.1: {} whatwg-mimetype@3.0.0: {} @@ -3065,6 +4108,26 @@ snapshots: word-wrap@1.2.5: {} + ws@7.5.10: {} + ws@8.19.0: {} + xml-parse-from-string@1.0.1: {} + + xml2js@0.5.0: + dependencies: + sax: 1.4.4 + xmlbuilder: 11.0.1 + + xmlbuilder@11.0.1: {} + + yaml@2.8.2: + optional: true + yocto-queue@0.1.0: {} + + yoga-layout@3.2.1: {} + + zimmerframe@1.1.4: {} + + zod@3.25.76: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 9683f3532b80..47515bf0595e 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,6 +2,7 @@ linkWorkspacePackages: true packages: - "packages/aria-data" - "packages/tailwindcss-config-analyzer" + - "packages/prettier-compare" - "crates/biome_formatter_test/src/prettier" - "benchmark" - "packages/@biomejs/*"