diff --git a/.cursorrules b/.cursorrules new file mode 100644 index 0000000..a167dc3 --- /dev/null +++ b/.cursorrules @@ -0,0 +1,20 @@ +# Principles + +- Follow the project's existing conventions and patterns. +- Prefer strong typing throughout the codebase. +- Avoid using `any` or `unknown` types unless absolutely necessary. +- Do not use type assertions; instead, define or refine types as needed. +- Create and use explicit types or interfaces for complex structures. +- Prefer using node-sql-parser's API and types for SQL parsing and analysis. + +# Code Style + +- Prefer concise code changes and minimal extra explanatory text. +- Keep code changes minimal and focused on the requested functionality. + +# Development Workflow + +- Always use `pnpm test` or its variations to run tests. +- Always use `pnpm lint` to run linting. +- Always use `pnpm typecheck` to run typechecking. +- Ensure all code changes pass tests, linting, and typechecking before merging. diff --git a/.github/workflows/demo.yml b/.github/workflows/demo.yml index ac6f902..4c718f0 100644 --- a/.github/workflows/demo.yml +++ b/.github/workflows/demo.yml @@ -16,17 +16,17 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: ⎔ Setup pnpm uses: pnpm/action-setup@v4 with: - version: 9 + version: 10 - name: ⎔ Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: - node-version: 22 + node-version: 24 cache: pnpm - name: 📥 Install dependencies @@ -39,7 +39,7 @@ jobs: uses: actions/configure-pages@v5 - name: 📤 Upload artifact - uses: actions/upload-pages-artifact@v3 + uses: actions/upload-pages-artifact@v4 with: path: './demo/dist' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 52fd9ef..7e610e5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,19 +12,19 @@ jobs: release: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 0 - name: ⎔ Setup pnpm uses: pnpm/action-setup@v4 with: - version: 9 + version: 10 - name: ⎔ Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: - node-version: 22 + node-version: 24 registry-url: 'https://registry.npmjs.org' cache: pnpm diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 47ad0ea..6a1115e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,22 +21,25 @@ jobs: pull-requests: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: ⎔ Setup pnpm uses: pnpm/action-setup@v4 with: - version: 9 + version: 10 - name: ⎔ Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: - node-version: 22 + node-version: 24 cache: pnpm - name: 📥 Install dependencies run: pnpm install --ignore-scripts --frozen-lockfile + - name: 🎭 Install Playwright browsers + run: pnpx playwright install chromium + - name: 🔍 Type Check run: pnpm run typecheck @@ -46,21 +49,21 @@ jobs: security: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: 🔍 Run CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@v4 with: languages: javascript - name: 🔍 Perform Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@v4 spelling: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: 🔍 Spell Check Repo - uses: crate-ci/typos@v1.35.2 + uses: crate-ci/typos@v1.39.0 diff --git a/README.md b/README.md index 3a38902..3c85616 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # codemirror-sql -A CodeMirror extension for SQL linting and visual gutter indicators. +A CodeMirror extension for SQL linting and visual gutter indicators. Built by and used in [marimo](https://github.com/marimo-team/marimo). ## Features @@ -8,6 +8,9 @@ A CodeMirror extension for SQL linting and visual gutter indicators. - 🎨 **Visual gutter** - Color-coded statement indicators and error highlighting - 💡 **Hover tooltips** - Schema info, keywords, and column details on hover - 🔮 **CTE autocomplete** - Auto-complete support for CTEs +- 🎯 **Query-aware resolution** - Context-sensitive schema and column suggestions +- 🔍 **Additional dialects** - DuckDB, BigQuery +- 🛠️ **Custom renderers** - Customizable tooltip rendering for tables, columns, and keywords ## Installation @@ -22,13 +25,13 @@ pnpm add @marimo-team/codemirror-sql ### Basic Setup ```ts -import { sql, StandardSQL } from '@codemirror/lang-sql'; -import { basicSetup, EditorView } from 'codemirror'; -import { sqlExtension, cteCompletionSource } from '@marimo-team/codemirror-sql'; +import { sql, StandardSQL } from "@codemirror/lang-sql"; +import { basicSetup, EditorView } from "codemirror"; +import { sqlExtension, cteCompletionSource } from "@marimo-team/codemirror-sql"; const schema = { users: ["id", "name", "email", "active"], - posts: ["id", "title", "content", "user_id"] + posts: ["id", "title", "content", "user_id"], }; const editor = new EditorView({ @@ -38,19 +41,19 @@ const editor = new EditorView({ sql({ dialect: StandardSQL, schema: schema, - upperCaseKeywords: true + upperCaseKeywords: true, }), StandardSQL.language.data.of({ autocomplete: cteCompletionSource, }), sqlExtension({ linterConfig: { - delay: 250 // Validation delay in ms + delay: 250, // Validation delay in ms }, gutterConfig: { backgroundColor: "#3b82f6", // Current statement color errorBackgroundColor: "#ef4444", // Error highlight color - hideWhenNotFocused: true + hideWhenNotFocused: true, }, enableHover: true, hoverConfig: { @@ -58,14 +61,26 @@ const editor = new EditorView({ hoverTime: 300, enableKeywords: true, enableTables: true, - enableColumns: true - } - }) + enableColumns: true, + }, + }), ], - parent: document.querySelector('#editor') + parent: document.querySelector("#editor"), }); ``` +## Additional Dialects + +This extension adds support for additional dialects: + +- **DuckDB** +- **BigQuery** + +## Keyword Completion + +The extension includes keyword documentation for common **SQL keywords** including used in hover and completion, +which can be found in the `src/data` directory. + ## Demo See the [demo](https://marimo-team.github.io/codemirror-sql/) for a full example. diff --git a/demo/custom-renderers.ts b/demo/custom-renderers.ts index 1949c20..207d9a6 100644 --- a/demo/custom-renderers.ts +++ b/demo/custom-renderers.ts @@ -30,7 +30,7 @@ interface TableMetadata { indexes: IndexMetadata[]; } -export type Schema = "users" | "posts" | "orders" | "customers" | "categories"; +export type Schema = "users" | "posts" | "orders" | "customers" | "categories" | "Users_Posts"; export const tableTooltipRenderer = (data: NamespaceTooltipData) => { // Show table name, columns, description, primary key, foreign key, index, unique, check, default, comment @@ -292,6 +292,24 @@ function getTableMetadata(tableName: string): TableMetadata { { name: "idx_categories_parent", columns: ["parent_id"], unique: false }, ], }, + Users_Posts: { + description: "User-Post relationships", + rowCount: "1,234", + columns: { + user_id: { type: "INT", notNull: true, foreignKey: true, comment: "User who posted" }, + post_id: { + type: "INT", + notNull: true, + foreignKey: true, + comment: "Post being commented on", + }, + }, + foreignKeys: [ + { column: "user_id", referencedTable: "users", referencedColumn: "id" }, + { column: "post_id", referencedTable: "posts", referencedColumn: "id" }, + ], + indexes: [{ name: "idx_users_posts_user", columns: ["user_id"], unique: false }], + }, }; return ( diff --git a/demo/data.ts b/demo/data.ts new file mode 100644 index 0000000..d0d95c7 --- /dev/null +++ b/demo/data.ts @@ -0,0 +1,81 @@ +import type { Schema } from "./custom-renderers"; + +// Default SQL content for the demo +export const defaultSqlDoc = `-- Welcome to the SQL Editor Demo! +-- Try editing the queries below to see real-time validation + +WITH cte_name AS ( + SELECT * FROM users +) + +-- Valid queries (no errors): +SELECT id, name, email +FROM users +WHERE active = true +ORDER BY created_at DESC; + +SELECT + u.name, + p.title, + p.created_at +FROM users u +JOIN posts p ON u.id = p.user_id +WHERE u.status = 'active' + AND p.published = true +LIMIT 10; + +-- Try editing these to create syntax errors: +-- Uncomment the lines below to see error highlighting + +-- SELECT * FROM; -- Missing table name +-- SELECT * FORM users; -- Typo in FROM keyword +-- INSERT INTO VALUES (1, 2); -- Missing table name +-- UPDATE SET name = 'test'; -- Missing table name + +-- Complex example with subquery: +SELECT + customer_id, + order_date, + total_amount, + (SELECT AVG(total_amount) FROM orders) as avg_order_value +FROM orders +WHERE order_date >= '2024-01-01' + AND total_amount > ( + SELECT AVG(total_amount) * 0.8 + FROM orders + WHERE YEAR(order_date) = 2024 + ) +ORDER BY total_amount DESC; +`; + +export const schema: Record = { + // Users table + users: ["id", "name", "email", "active", "status", "created_at", "updated_at", "profile_id"], + // Posts table + posts: [ + "id", + "title", + "content", + "user_id", + "published", + "created_at", + "updated_at", + "category_id", + ], + // Orders table + orders: [ + "id", + "customer_id", + "order_date", + "total_amount", + "status", + "shipping_address", + "created_at", + ], + // Customers table (additional example) + customers: ["id", "first_name", "last_name", "email", "phone", "address", "city", "country"], + // Categories table + categories: ["id", "name", "description", "parent_id"], + // Users_Posts table + Users_Posts: ["user_id", "post_id"], +}; diff --git a/demo/index.html b/demo/index.html index 0dc206b..b038d16 100644 --- a/demo/index.html +++ b/demo/index.html @@ -34,7 +34,7 @@

SQL Editor with Diagnostics

- diff --git a/demo/index.ts b/demo/index.ts index 67915b0..bedebc2 100644 --- a/demo/index.ts +++ b/demo/index.ts @@ -1,93 +1,19 @@ import { acceptCompletion } from "@codemirror/autocomplete"; -import { PostgreSQL, sql } from "@codemirror/lang-sql"; -import { type EditorState, StateEffect, StateField } from "@codemirror/state"; +import { PostgreSQL, type SQLDialect, sql } from "@codemirror/lang-sql"; +import { Compartment, type EditorState, StateEffect, StateField } from "@codemirror/state"; import { keymap } from "@codemirror/view"; import { basicSetup, EditorView } from "codemirror"; import { cteCompletionSource, DefaultSqlTooltipRenders, + defaultSqlHoverTheme, NodeSqlParser, + type SupportedDialects, sqlExtension, } from "../src/index.js"; -import { type Schema, tableTooltipRenderer } from "./custom-renderers.js"; - -// Default SQL content for the demo -const defaultSqlDoc = `-- Welcome to the SQL Editor Demo! --- Try editing the queries below to see real-time validation - -WITH cte_name AS ( - SELECT * FROM users -) - --- Valid queries (no errors): -SELECT id, name, email -FROM users -WHERE active = true -ORDER BY created_at DESC; - -SELECT - u.name, - p.title, - p.created_at -FROM users u -JOIN posts p ON u.id = p.user_id -WHERE u.status = 'active' - AND p.published = true -LIMIT 10; - --- Try editing these to create syntax errors: --- Uncomment the lines below to see error highlighting - --- SELECT * FROM; -- Missing table name --- SELECT * FORM users; -- Typo in FROM keyword --- INSERT INTO VALUES (1, 2); -- Missing table name --- UPDATE SET name = 'test'; -- Missing table name - --- Complex example with subquery: -SELECT - customer_id, - order_date, - total_amount, - (SELECT AVG(total_amount) FROM orders) as avg_order_value -FROM orders -WHERE order_date >= '2024-01-01' - AND total_amount > ( - SELECT AVG(total_amount) * 0.8 - FROM orders - WHERE YEAR(order_date) = 2024 - ) -ORDER BY total_amount DESC; -`; - -const schema: Record = { - // Users table - users: ["id", "name", "email", "active", "status", "created_at", "updated_at", "profile_id"], - // Posts table - posts: [ - "id", - "title", - "content", - "user_id", - "published", - "created_at", - "updated_at", - "category_id", - ], - // Orders table - orders: [ - "id", - "customer_id", - "order_date", - "total_amount", - "status", - "shipping_address", - "created_at", - ], - // Customers table (additional example) - customers: ["id", "first_name", "last_name", "email", "phone", "address", "city", "country"], - // Categories table - categories: ["id", "name", "description", "parent_id"], -}; +import { tableTooltipRenderer } from "./custom-renderers.js"; +import { defaultSqlDoc, schema } from "./data.js"; +import { guessSqlDialect } from "./utils.js"; let editor: EditorView; @@ -102,7 +28,7 @@ const completionKindStyles = { height: "12px", }; -const dialect = PostgreSQL; +const defaultDialect = PostgreSQL; const defaultKeymap = [ { @@ -145,9 +71,8 @@ const getKeywordDocs = async () => { }; }; -const setDatabase = StateEffect.define(); - -const databaseField = StateField.define({ +const setDatabase = StateEffect.define(); +const databaseField = StateField.define({ create: () => "PostgreSQL", update: (prevValue, transaction) => { for (const effect of transaction.effects) { @@ -159,13 +84,45 @@ const databaseField = StateField.define({ }, }); +// Allows us to reconfigure the base sql extension without reloading the editor +const baseSqlCompartment = new Compartment(); + +const baseSqlExtension = (dialect: SQLDialect) => { + return sql({ + dialect: dialect, + // Example schema for autocomplete + schema: schema, + // Enable uppercase keywords for more traditional SQL style + upperCaseKeywords: true, + keywordCompletion: (label, _type) => { + return { + label, + keyword: label, + info: async () => { + const dom = document.createElement("div"); + const keywordDocs = await getKeywordDocs(); + const description = keywordDocs[label.toLocaleLowerCase()]; + if (!description) { + return null; + } + dom.innerHTML = DefaultSqlTooltipRenders.keyword({ + keyword: label, + info: description, + }); + return dom; + }, + }; + }, + }); +}; + // Initialize the SQL editor function initializeEditor() { - // Use the same parser for linter and gutter + // Use the same parser const parser = new NodeSqlParser({ getParserOptions: (state: EditorState) => { return { - database: getDialect(state), + database: getDatabase(state), }; }, }); @@ -175,32 +132,7 @@ function initializeEditor() { EditorView.lineWrapping, keymap.of(defaultKeymap), databaseField, - sql({ - dialect: dialect, - // Example schema for autocomplete - schema: schema, - // Enable uppercase keywords for more traditional SQL style - upperCaseKeywords: true, - keywordCompletion: (label, _type) => { - return { - label, - keyword: label, - info: async () => { - const dom = document.createElement("div"); - const keywordDocs = await getKeywordDocs(); - const description = keywordDocs[label.toLocaleLowerCase()]; - if (!description) { - return null; - } - dom.innerHTML = DefaultSqlTooltipRenders.keyword({ - keyword: label, - info: description, - }); - return dom; - }, - }; - }, - }), + baseSqlCompartment.of(baseSqlExtension(defaultDialect)), sqlExtension({ // Linter extension configuration linterConfig: { @@ -231,9 +163,11 @@ function initializeEditor() { // Custom renderer for tables table: tableTooltipRenderer, }, + theme: defaultSqlHoverTheme("light"), + parser, }, }), - dialect.language.data.of({ + defaultDialect.language.data.of({ autocomplete: cteCompletionSource, }), // Custom theme for better SQL editing @@ -335,15 +269,16 @@ function setupExampleButtons() { }); } -function getDialect(state: EditorState): string { +function getDatabase(state: EditorState): SupportedDialects { return state.field(databaseField); } -function setupDialectSelect() { - const select = document.querySelector("#dialect-select"); +function setupDatabaseSelect() { + const select = document.querySelector("#database-select"); if (select) { select.addEventListener("change", (e) => { - const value = (e.target as HTMLSelectElement).value; + const value = (e.target as HTMLSelectElement).value as SupportedDialects; + updateSqlDialect(editor, guessSqlDialect(value)); editor.dispatch({ effects: [setDatabase.of(value)], }); @@ -351,11 +286,17 @@ function setupDialectSelect() { } } +function updateSqlDialect(view: EditorView, dialect: SQLDialect) { + view.dispatch({ + effects: [baseSqlCompartment.reconfigure(baseSqlExtension(dialect))], + }); +} + // Initialize everything when the page loads document.addEventListener("DOMContentLoaded", () => { initializeEditor(); setupExampleButtons(); - setupDialectSelect(); + setupDatabaseSelect(); console.log("SQL Editor Demo initialized!"); console.log("Features:"); diff --git a/demo/utils.ts b/demo/utils.ts new file mode 100644 index 0000000..be0d14a --- /dev/null +++ b/demo/utils.ts @@ -0,0 +1,19 @@ +import { MySQL, PostgreSQL, type SQLDialect, SQLite } from "@codemirror/lang-sql"; +import { DuckDBDialect } from "../src/dialects/duckdb/duckdb"; +import type { SupportedDialects } from "../src/sql/parser"; + +export function guessSqlDialect(dialect: SupportedDialects): SQLDialect { + // Other supported dialects: Cassandra, MSSQL, MariaSQL, MySQL, PLSQL, PostgreSQL + switch (dialect) { + case "PostgreSQL": + return PostgreSQL; + case "DuckDB": + return DuckDBDialect; + case "MySQL": + return MySQL; + case "Sqlite": + return SQLite; + default: + return PostgreSQL; + } +} diff --git a/package.json b/package.json index 5e88020..70ca1c8 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@marimo-team/codemirror-sql", - "version": "0.1.2", + "version": "0.2.4", "publishConfig": { "access": "public" }, @@ -19,7 +19,8 @@ "demo": "vite build", "build": "tsc", "prepublishOnly": "pnpm run typecheck && pnpm run test && pnpm run build", - "release": "pnpm version" + "release": "pnpm version", + "test:browser": "vitest --config=vitest.browser.config.ts" }, "keywords": [ "codemirror", @@ -28,19 +29,23 @@ ], "license": "Apache-2.0", "peerDependencies": { + "@codemirror/autocomplete": "^6", + "@codemirror/lint": "^6 <6.9.1", "@codemirror/state": "^6", "@codemirror/view": "^6" }, "devDependencies": { - "@biomejs/biome": "^2.1.3", - "@codemirror/lang-sql": "^6.9.1", - "@codemirror/view": "^6.38.1", - "@vitest/coverage-v8": "3.2.4", + "@biomejs/biome": "^2.3.2", + "@codemirror/lang-sql": "^6.10.0", + "@codemirror/view": "^6.38.6", + "@testing-library/dom": "^10.4.1", + "@vitest/browser-playwright": "^4.0.6", + "@vitest/coverage-v8": "4.0.6", "codemirror": "^6.0.2", - "jsdom": "^26.1.0", - "typescript": "^5.9.2", - "vite": "^7.0.6", - "vitest": "^3.2.4" + "jsdom": "^27.1.0", + "typescript": "^5.9.3", + "vite": "^7.1.12", + "vitest": "^4.0.6" }, "files": [ "dist", @@ -54,6 +59,12 @@ "default": "./dist/index.js" } }, + "./dialects": { + "import": { + "types": "./dist/dialects/index.d.ts", + "default": "./dist/dialects/index.js" + } + }, "./data/common-keywords.json": "./src/data/common-keywords.json", "./data/duckdb-keywords.json": "./src/data/duckdb-keywords.json" }, @@ -64,8 +75,6 @@ }, "module": "./dist/index.js", "dependencies": { - "@codemirror/autocomplete": "^6.18.6", - "@codemirror/lint": "^6.8.5", - "node-sql-parser": "^5.3.10" + "node-sql-parser": "^5.3.13" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7a0b047..a8922b0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,143 +9,162 @@ importers: .: dependencies: '@codemirror/autocomplete': - specifier: ^6.18.6 - version: 6.18.6 + specifier: ^6 + version: 6.19.1 '@codemirror/lint': - specifier: ^6.8.5 - version: 6.8.5 + specifier: ^6 <6.9.1 + version: 6.9.0 '@codemirror/state': specifier: ^6 version: 6.5.2 node-sql-parser: - specifier: ^5.3.10 - version: 5.3.11 + specifier: ^5.3.13 + version: 5.3.13 devDependencies: '@biomejs/biome': - specifier: ^2.1.3 - version: 2.1.4 + specifier: ^2.3.2 + version: 2.3.2 '@codemirror/lang-sql': - specifier: ^6.9.1 - version: 6.9.1 + specifier: ^6.10.0 + version: 6.10.0 '@codemirror/view': - specifier: ^6.38.1 - version: 6.38.1 + specifier: ^6.38.6 + version: 6.38.6 + '@testing-library/dom': + specifier: ^10.4.1 + version: 10.4.1 + '@vitest/browser-playwright': + specifier: ^4.0.6 + version: 4.0.6(playwright@1.56.1)(vite@7.1.12(@types/node@22.13.1)(yaml@2.8.0))(vitest@4.0.6) '@vitest/coverage-v8': - specifier: 3.2.4 - version: 3.2.4(vitest@3.2.4(@types/node@22.13.1)(happy-dom@15.11.7)(jsdom@26.1.0)(yaml@2.8.0)) + specifier: 4.0.6 + version: 4.0.6(@vitest/browser@4.0.6(vite@7.1.12(@types/node@22.13.1)(yaml@2.8.0))(vitest@4.0.6))(vitest@4.0.6) codemirror: specifier: ^6.0.2 version: 6.0.2 jsdom: - specifier: ^26.1.0 - version: 26.1.0 + specifier: ^27.1.0 + version: 27.1.0 typescript: - specifier: ^5.9.2 - version: 5.9.2 + specifier: ^5.9.3 + version: 5.9.3 vite: - specifier: ^7.0.6 - version: 7.1.1(@types/node@22.13.1)(yaml@2.8.0) + specifier: ^7.1.12 + version: 7.1.12(@types/node@22.13.1)(yaml@2.8.0) vitest: - specifier: ^3.2.4 - version: 3.2.4(@types/node@22.13.1)(happy-dom@15.11.7)(jsdom@26.1.0)(yaml@2.8.0) + specifier: ^4.0.6 + version: 4.0.6(@types/node@22.13.1)(@vitest/browser-playwright@4.0.6)(happy-dom@15.11.7)(jsdom@27.1.0)(yaml@2.8.0) packages: - '@ampproject/remapping@2.3.0': - resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} - engines: {node: '>=6.0.0'} + '@acemir/cssom@0.9.19': + resolution: {integrity: sha512-Pp2gAQXPZ2o7lt4j0IMwNRXqQ3pagxtDj5wctL5U2Lz4oV0ocDNlkgx4DpxfyKav4S/bePuI+SMqcBSUHLy9kg==} + + '@asamuzakjp/css-color@4.0.5': + resolution: {integrity: sha512-lMrXidNhPGsDjytDy11Vwlb6OIGrT3CmLg3VWNFyWkLWtijKl7xjvForlh8vuj0SHGjgl4qZEQzUmYTeQA2JFQ==} + + '@asamuzakjp/dom-selector@6.7.4': + resolution: {integrity: sha512-buQDjkm+wDPXd6c13534URWZqbz0RP5PAhXZ+LIoa5LgwInT9HVJvGIJivg75vi8I13CxDGdTnz+aY5YUJlIAA==} - '@asamuzakjp/css-color@3.2.0': - resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} + '@asamuzakjp/nwsapi@2.3.9': + resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.27.1': - resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.0': - resolution: {integrity: sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==} + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/types@7.28.2': - resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} + '@babel/runtime@7.28.4': + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} engines: {node: '>=6.9.0'} '@bcoe/v8-coverage@1.0.2': resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} - '@biomejs/biome@2.1.4': - resolution: {integrity: sha512-QWlrqyxsU0FCebuMnkvBIkxvPqH89afiJzjMl+z67ybutse590jgeaFdDurE9XYtzpjRGTI1tlUZPGWmbKsElA==} + '@biomejs/biome@2.3.2': + resolution: {integrity: sha512-8e9tzamuDycx7fdrcJ/F/GDZ8SYukc5ud6tDicjjFqURKYFSWMl0H0iXNXZEGmcmNUmABgGuHThPykcM41INgg==} engines: {node: '>=14.21.3'} hasBin: true - '@biomejs/cli-darwin-arm64@2.1.4': - resolution: {integrity: sha512-sCrNENE74I9MV090Wq/9Dg7EhPudx3+5OiSoQOkIe3DLPzFARuL1dOwCWhKCpA3I5RHmbrsbNSRfZwCabwd8Qg==} + '@biomejs/cli-darwin-arm64@2.3.2': + resolution: {integrity: sha512-4LECm4kc3If0JISai4c3KWQzukoUdpxy4fRzlrPcrdMSRFksR9ZoXK7JBcPuLBmd2SoT4/d7CQS33VnZpgBjew==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] - '@biomejs/cli-darwin-x64@2.1.4': - resolution: {integrity: sha512-gOEICJbTCy6iruBywBDcG4X5rHMbqCPs3clh3UQ+hRKlgvJTk4NHWQAyHOXvaLe+AxD1/TNX1jbZeffBJzcrOw==} + '@biomejs/cli-darwin-x64@2.3.2': + resolution: {integrity: sha512-jNMnfwHT4N3wi+ypRfMTjLGnDmKYGzxVr1EYAPBcauRcDnICFXN81wD6wxJcSUrLynoyyYCdfW6vJHS/IAoTDA==} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] - '@biomejs/cli-linux-arm64-musl@2.1.4': - resolution: {integrity: sha512-nYr7H0CyAJPaLupFE2cH16KZmRC5Z9PEftiA2vWxk+CsFkPZQ6dBRdcC6RuS+zJlPc/JOd8xw3uCCt9Pv41WvQ==} + '@biomejs/cli-linux-arm64-musl@2.3.2': + resolution: {integrity: sha512-2Zz4usDG1GTTPQnliIeNx6eVGGP2ry5vE/v39nT73a3cKN6t5H5XxjcEoZZh62uVZvED7hXXikclvI64vZkYqw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-arm64@2.1.4': - resolution: {integrity: sha512-juhEkdkKR4nbUi5k/KRp1ocGPNWLgFRD4NrHZSveYrD6i98pyvuzmS9yFYgOZa5JhaVqo0HPnci0+YuzSwT2fw==} + '@biomejs/cli-linux-arm64@2.3.2': + resolution: {integrity: sha512-amnqvk+gWybbQleRRq8TMe0rIv7GHss8mFJEaGuEZYWg1Tw14YKOkeo8h6pf1c+d3qR+JU4iT9KXnBKGON4klw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-x64-musl@2.1.4': - resolution: {integrity: sha512-lvwvb2SQQHctHUKvBKptR6PLFCM7JfRjpCCrDaTmvB7EeZ5/dQJPhTYBf36BE/B4CRWR2ZiBLRYhK7hhXBCZAg==} + '@biomejs/cli-linux-x64-musl@2.3.2': + resolution: {integrity: sha512-gzB19MpRdTuOuLtPpFBGrV3Lq424gHyq2lFj8wfX9tvLMLdmA/R9C7k/mqBp/spcbWuHeIEKgEs3RviOPcWGBA==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-linux-x64@2.1.4': - resolution: {integrity: sha512-Eoy9ycbhpJVYuR+LskV9s3uyaIkp89+qqgqhGQsWnp/I02Uqg2fXFblHJOpGZR8AxdB9ADy87oFVxn9MpFKUrw==} + '@biomejs/cli-linux-x64@2.3.2': + resolution: {integrity: sha512-8BG/vRAhFz1pmuyd24FQPhNeueLqPtwvZk6yblABY2gzL2H8fLQAF/Z2OPIc+BPIVPld+8cSiKY/KFh6k81xfA==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-win32-arm64@2.1.4': - resolution: {integrity: sha512-3WRYte7orvyi6TRfIZkDN9Jzoogbv+gSvR+b9VOXUg1We1XrjBg6WljADeVEaKTvOcpVdH0a90TwyOQ6ue4fGw==} + '@biomejs/cli-win32-arm64@2.3.2': + resolution: {integrity: sha512-lCruqQlfWjhMlOdyf5pDHOxoNm4WoyY2vZ4YN33/nuZBRstVDuqPPjS0yBkbUlLEte11FbpW+wWSlfnZfSIZvg==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] - '@biomejs/cli-win32-x64@2.1.4': - resolution: {integrity: sha512-tBc+W7anBPSFXGAoQW+f/+svkpt8/uXfRwDzN1DvnatkRMt16KIYpEi/iw8u9GahJlFv98kgHcIrSsZHZTR0sw==} + '@biomejs/cli-win32-x64@2.3.2': + resolution: {integrity: sha512-6Ee9P26DTb4D8sN9nXxgbi9Dw5vSOfH98M7UlmkjKB2vtUbrRqCbZiNfryGiwnPIpd6YUoTl7rLVD2/x1CyEHQ==} engines: {node: '>=14.21.3'} cpu: [x64] os: [win32] - '@codemirror/autocomplete@6.18.6': - resolution: {integrity: sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==} + '@codemirror/autocomplete@6.19.1': + resolution: {integrity: sha512-q6NenYkEy2fn9+JyjIxMWcNjzTL/IhwqfzOut1/G3PrIFkrbl4AL7Wkse5tLrQUUyqGoAKU5+Pi5jnnXxH5HGw==} - '@codemirror/commands@6.8.1': - resolution: {integrity: sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==} + '@codemirror/commands@6.10.0': + resolution: {integrity: sha512-2xUIc5mHXQzT16JnyOFkh8PvfeXuIut3pslWGfsGOhxP/lpgRm9HOl/mpzLErgt5mXDovqA0d11P21gofRLb9w==} - '@codemirror/lang-sql@6.9.1': - resolution: {integrity: sha512-ecSk3gm/mlINcURMcvkCZmXgdzPSq8r/yfCtTB4vgqGGIbBC2IJIAy7GqYTy5pgBEooTVmHP2GZK6Z7h63CDGg==} + '@codemirror/lang-sql@6.10.0': + resolution: {integrity: sha512-6ayPkEd/yRw0XKBx5uAiToSgGECo/GY2NoJIHXIIQh1EVwLuKoU8BP/qK0qH5NLXAbtJRLuT73hx7P9X34iO4w==} - '@codemirror/language@6.11.2': - resolution: {integrity: sha512-p44TsNArL4IVXDTbapUmEkAlvWs2CFQbcfc0ymDsis1kH2wh0gcY96AS29c/vp2d0y2Tquk1EDSaawpzilUiAw==} + '@codemirror/language@6.11.3': + resolution: {integrity: sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==} - '@codemirror/lint@6.8.5': - resolution: {integrity: sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==} + '@codemirror/lint@6.9.0': + resolution: {integrity: sha512-wZxW+9XDytH3SKvS8cQzMyQCaaazH8XL1EMHleHe00wVzsv7NBQKVW2yzEHrRhmM7ZOhVdItPbvlRBvMp9ej7A==} '@codemirror/search@6.5.11': resolution: {integrity: sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==} @@ -153,11 +172,11 @@ packages: '@codemirror/state@6.5.2': resolution: {integrity: sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==} - '@codemirror/view@6.38.1': - resolution: {integrity: sha512-RmTOkE7hRU3OVREqFVITWHz6ocgBjv08GoePscAakgVQfciA3SGCEk7mb9IzwW61cKKmlTpHXG6DUE5Ubx+MGQ==} + '@codemirror/view@6.38.6': + resolution: {integrity: sha512-qiS0z1bKs5WOvHIAC0Cybmv4AJSkAXgX5aD6Mqd2epSLlVJsQl8NG23jCVouIgkh4All/mrbdsf2UOLFnJw0tw==} - '@csstools/color-helpers@5.0.2': - resolution: {integrity: sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==} + '@csstools/color-helpers@5.1.0': + resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} engines: {node: '>=18'} '@csstools/css-calc@2.1.4': @@ -167,8 +186,8 @@ packages: '@csstools/css-parser-algorithms': ^3.0.5 '@csstools/css-tokenizer': ^3.0.4 - '@csstools/css-color-parser@3.0.10': - resolution: {integrity: sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==} + '@csstools/css-color-parser@3.1.0': + resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} engines: {node: '>=18'} peerDependencies: '@csstools/css-parser-algorithms': ^3.0.5 @@ -180,192 +199,185 @@ packages: peerDependencies: '@csstools/css-tokenizer': ^3.0.4 + '@csstools/css-syntax-patches-for-csstree@1.0.15': + resolution: {integrity: sha512-q0p6zkVq2lJnmzZVPR33doA51G7YOja+FBvRdp5ISIthL0MtFCgYHHhR563z9WFGxcOn0WfjSkPDJ5Qig3H3Sw==} + engines: {node: '>=18'} + '@csstools/css-tokenizer@3.0.4': resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} engines: {node: '>=18'} - '@esbuild/aix-ppc64@0.25.8': - resolution: {integrity: sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==} + '@esbuild/aix-ppc64@0.25.11': + resolution: {integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.8': - resolution: {integrity: sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==} + '@esbuild/android-arm64@0.25.11': + resolution: {integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.8': - resolution: {integrity: sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==} + '@esbuild/android-arm@0.25.11': + resolution: {integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.8': - resolution: {integrity: sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==} + '@esbuild/android-x64@0.25.11': + resolution: {integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.8': - resolution: {integrity: sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==} + '@esbuild/darwin-arm64@0.25.11': + resolution: {integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.8': - resolution: {integrity: sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==} + '@esbuild/darwin-x64@0.25.11': + resolution: {integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.8': - resolution: {integrity: sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==} + '@esbuild/freebsd-arm64@0.25.11': + resolution: {integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.8': - resolution: {integrity: sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==} + '@esbuild/freebsd-x64@0.25.11': + resolution: {integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.8': - resolution: {integrity: sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==} + '@esbuild/linux-arm64@0.25.11': + resolution: {integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.8': - resolution: {integrity: sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==} + '@esbuild/linux-arm@0.25.11': + resolution: {integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.8': - resolution: {integrity: sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==} + '@esbuild/linux-ia32@0.25.11': + resolution: {integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.8': - resolution: {integrity: sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==} + '@esbuild/linux-loong64@0.25.11': + resolution: {integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.8': - resolution: {integrity: sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==} + '@esbuild/linux-mips64el@0.25.11': + resolution: {integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.8': - resolution: {integrity: sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==} + '@esbuild/linux-ppc64@0.25.11': + resolution: {integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.8': - resolution: {integrity: sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==} + '@esbuild/linux-riscv64@0.25.11': + resolution: {integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.8': - resolution: {integrity: sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==} + '@esbuild/linux-s390x@0.25.11': + resolution: {integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.8': - resolution: {integrity: sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==} + '@esbuild/linux-x64@0.25.11': + resolution: {integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.8': - resolution: {integrity: sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==} + '@esbuild/netbsd-arm64@0.25.11': + resolution: {integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.8': - resolution: {integrity: sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==} + '@esbuild/netbsd-x64@0.25.11': + resolution: {integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.8': - resolution: {integrity: sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==} + '@esbuild/openbsd-arm64@0.25.11': + resolution: {integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.8': - resolution: {integrity: sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==} + '@esbuild/openbsd-x64@0.25.11': + resolution: {integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.25.8': - resolution: {integrity: sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==} + '@esbuild/openharmony-arm64@0.25.11': + resolution: {integrity: sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.25.8': - resolution: {integrity: sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==} + '@esbuild/sunos-x64@0.25.11': + resolution: {integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.8': - resolution: {integrity: sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==} + '@esbuild/win32-arm64@0.25.11': + resolution: {integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.8': - resolution: {integrity: sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==} + '@esbuild/win32-ia32@0.25.11': + resolution: {integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.8': - resolution: {integrity: sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==} + '@esbuild/win32-x64@0.25.11': + resolution: {integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==} engines: {node: '>=18'} cpu: [x64] os: [win32] - '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} - - '@istanbuljs/schema@0.1.3': - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} - engines: {node: '>=8'} - - '@jridgewell/gen-mapping@0.3.12': - resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==} - '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - '@jridgewell/sourcemap-codec@1.5.4': - resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==} + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - '@jridgewell/trace-mapping@0.3.29': - resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@lezer/common@1.2.3': - resolution: {integrity: sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==} + '@lezer/common@1.3.0': + resolution: {integrity: sha512-L9X8uHCYU310o99L3/MpJKYxPzXPOS7S0NmBaM7UO/x2Kb2WbmMLSkfvdr1KxRIFYOpbY0Jhn7CfLSUDzL8arQ==} - '@lezer/highlight@1.2.1': - resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==} + '@lezer/highlight@1.2.3': + resolution: {integrity: sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==} '@lezer/lr@1.4.2': resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==} @@ -373,112 +385,131 @@ packages: '@marijn/find-cluster-break@1.0.2': resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==} - '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} + '@polka/url@1.0.0-next.29': + resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} - '@rollup/rollup-android-arm-eabi@4.46.2': - resolution: {integrity: sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==} + '@rollup/rollup-android-arm-eabi@4.52.5': + resolution: {integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.46.2': - resolution: {integrity: sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==} + '@rollup/rollup-android-arm64@4.52.5': + resolution: {integrity: sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.46.2': - resolution: {integrity: sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==} + '@rollup/rollup-darwin-arm64@4.52.5': + resolution: {integrity: sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.46.2': - resolution: {integrity: sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==} + '@rollup/rollup-darwin-x64@4.52.5': + resolution: {integrity: sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.46.2': - resolution: {integrity: sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==} + '@rollup/rollup-freebsd-arm64@4.52.5': + resolution: {integrity: sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.46.2': - resolution: {integrity: sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==} + '@rollup/rollup-freebsd-x64@4.52.5': + resolution: {integrity: sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.46.2': - resolution: {integrity: sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==} + '@rollup/rollup-linux-arm-gnueabihf@4.52.5': + resolution: {integrity: sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.46.2': - resolution: {integrity: sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==} + '@rollup/rollup-linux-arm-musleabihf@4.52.5': + resolution: {integrity: sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.46.2': - resolution: {integrity: sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==} + '@rollup/rollup-linux-arm64-gnu@4.52.5': + resolution: {integrity: sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.46.2': - resolution: {integrity: sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==} + '@rollup/rollup-linux-arm64-musl@4.52.5': + resolution: {integrity: sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loongarch64-gnu@4.46.2': - resolution: {integrity: sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==} + '@rollup/rollup-linux-loong64-gnu@4.52.5': + resolution: {integrity: sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.46.2': - resolution: {integrity: sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==} + '@rollup/rollup-linux-ppc64-gnu@4.52.5': + resolution: {integrity: sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.46.2': - resolution: {integrity: sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==} + '@rollup/rollup-linux-riscv64-gnu@4.52.5': + resolution: {integrity: sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.46.2': - resolution: {integrity: sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==} + '@rollup/rollup-linux-riscv64-musl@4.52.5': + resolution: {integrity: sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.46.2': - resolution: {integrity: sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==} + '@rollup/rollup-linux-s390x-gnu@4.52.5': + resolution: {integrity: sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.46.2': - resolution: {integrity: sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==} + '@rollup/rollup-linux-x64-gnu@4.52.5': + resolution: {integrity: sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.46.2': - resolution: {integrity: sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==} + '@rollup/rollup-linux-x64-musl@4.52.5': + resolution: {integrity: sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.46.2': - resolution: {integrity: sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==} + '@rollup/rollup-openharmony-arm64@4.52.5': + resolution: {integrity: sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.52.5': + resolution: {integrity: sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.46.2': - resolution: {integrity: sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==} + '@rollup/rollup-win32-ia32-msvc@4.52.5': + resolution: {integrity: sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.46.2': - resolution: {integrity: sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==} + '@rollup/rollup-win32-x64-gnu@4.52.5': + resolution: {integrity: sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.52.5': + resolution: {integrity: sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==} cpu: [x64] os: [win32] - '@types/chai@5.2.2': - resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==} + '@standard-schema/spec@1.0.0': + resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + + '@testing-library/dom@10.4.1': + resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} + engines: {node: '>=18'} + + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} @@ -492,43 +523,54 @@ packages: '@types/pegjs@0.10.6': resolution: {integrity: sha512-eLYXDbZWXh2uxf+w8sXS8d6KSoXTswfps6fvCUuVAGN8eRpfe7h9eSRydxiSJvo9Bf+GzifsDOr9TMQlmJdmkw==} - '@vitest/coverage-v8@3.2.4': - resolution: {integrity: sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==} + '@vitest/browser-playwright@4.0.6': + resolution: {integrity: sha512-u6DliDabPQYXz8U4ZwnCvr9q2kJnribkenO6FK0qv5Gu/m1X884JOf0IZ71x7rLrmSsoP3YD3hVnNutAbhEX3A==} + peerDependencies: + playwright: '*' + vitest: 4.0.6 + + '@vitest/browser@4.0.6': + resolution: {integrity: sha512-SdrcvwvP6q8n82cS2BthbZuHGFPHeKkjbpeIRhGaeV8hJ8P0swWFx5lUZ/Vnd7G0CsfL6m4/3lOaqd/n12vtZA==} peerDependencies: - '@vitest/browser': 3.2.4 - vitest: 3.2.4 + vitest: 4.0.6 + + '@vitest/coverage-v8@4.0.6': + resolution: {integrity: sha512-cv6pFXj9/Otk7q1Ocoj8k3BUVVwnFr3jqcqpwYrU5LkKClU9DpaMEdX+zptx/RyIJS+/VpoxMWmfISXchmVDPQ==} + peerDependencies: + '@vitest/browser': 4.0.6 + vitest: 4.0.6 peerDependenciesMeta: '@vitest/browser': optional: true - '@vitest/expect@3.2.4': - resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} + '@vitest/expect@4.0.6': + resolution: {integrity: sha512-5j8UUlBVhOjhj4lR2Nt9sEV8b4WtbcYh8vnfhTNA2Kn5+smtevzjNq+xlBuVhnFGXiyPPNzGrOVvmyHWkS5QGg==} - '@vitest/mocker@3.2.4': - resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} + '@vitest/mocker@4.0.6': + resolution: {integrity: sha512-3COEIew5HqdzBFEYN9+u0dT3i/NCwppLnO1HkjGfAP1Vs3vti1Hxm/MvcbC4DAn3Szo1M7M3otiAaT83jvqIjA==} peerDependencies: msw: ^2.4.9 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + vite: ^6.0.0 || ^7.0.0-0 peerDependenciesMeta: msw: optional: true vite: optional: true - '@vitest/pretty-format@3.2.4': - resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} + '@vitest/pretty-format@4.0.6': + resolution: {integrity: sha512-4vptgNkLIA1W1Nn5X4x8rLJBzPiJwnPc+awKtfBE5hNMVsoAl/JCCPPzNrbf+L4NKgklsis5Yp2gYa+XAS442g==} - '@vitest/runner@3.2.4': - resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} + '@vitest/runner@4.0.6': + resolution: {integrity: sha512-trPk5qpd7Jj+AiLZbV/e+KiiaGXZ8ECsRxtnPnCrJr9OW2mLB72Cb824IXgxVz/mVU3Aj4VebY+tDTPn++j1Og==} - '@vitest/snapshot@3.2.4': - resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} + '@vitest/snapshot@4.0.6': + resolution: {integrity: sha512-PaYLt7n2YzuvxhulDDu6c9EosiRuIE+FI2ECKs6yvHyhoga+2TBWI8dwBjs+IeuQaMtZTfioa9tj3uZb7nev1g==} - '@vitest/spy@3.2.4': - resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} + '@vitest/spy@4.0.6': + resolution: {integrity: sha512-g9jTUYPV1LtRPRCQfhbMintW7BTQz1n6WXYQYRQ25qkyffA4bjVXjkROokZnv7t07OqfaFKw1lPzqKGk1hmNuQ==} - '@vitest/utils@3.2.4': - resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + '@vitest/utils@4.0.6': + resolution: {integrity: sha512-bG43VS3iYKrMIZXBo+y8Pti0O7uNju3KvNn6DrQWhQQKcLavMB+0NZfO1/QBAEbq0MaQ3QjNsnnXlGQvsh0Z6A==} agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} @@ -538,74 +580,51 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - ansi-regex@6.1.0: - resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} - engines: {node: '>=12'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} - ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} - engines: {node: '>=12'} + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - ast-v8-to-istanbul@0.3.3: - resolution: {integrity: sha512-MuXMrSLVVoA6sYN/6Hke18vMzrT4TZNbZIj/hvh0fnYFpO+/kFXcLIaiPwXXWaQUPg4yJD8fj+lfJ7/1EBconw==} + ast-v8-to-istanbul@0.3.8: + resolution: {integrity: sha512-szgSZqUxI5T8mLKvS7WTjF9is+MVbOeLADU73IseOcrqhxr/VAvy6wfoVE39KnKzA7JRhjF5eUagNlHwvZPlKQ==} - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + bidi-js@1.0.3: + resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} big-integer@1.6.52: resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} engines: {node: '>=0.6'} - brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} - - cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} - - chai@5.2.1: - resolution: {integrity: sha512-5nFxhUrX0PqtyogoYOA8IPswy5sZFTOsBFl/9bNsmDLgsxYTzSZQJDPppDnZPTQbzSEm0hqGjWPzRemQCYbD6A==} + chai@6.2.0: + resolution: {integrity: sha512-aUTnJc/JipRzJrNADXVvpVqi6CO0dn3nx4EVPxijri+fj3LUUDyZQOgVeW54Ob3Y1Xh9Iz8f+CgaCl8v0mn9bA==} engines: {node: '>=18'} - check-error@2.1.1: - resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} - engines: {node: '>= 16'} - codemirror@6.0.2: resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==} - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} + css-tree@3.1.0: + resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} - cssstyle@4.6.0: - resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==} - engines: {node: '>=18'} + cssstyle@5.3.2: + resolution: {integrity: sha512-zDMqXh8Vs1CdRYZQ2M633m/SFgcjlu8RB8b/1h82i+6vpArF507NSYIWJHGlJaTWoS+imcnctmEz43txhbVkOw==} + engines: {node: '>=20'} - data-urls@5.0.0: - resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} - engines: {node: '>=18'} + data-urls@6.0.0: + resolution: {integrity: sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==} + engines: {node: '>=20'} - debug@4.4.1: - resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -616,18 +635,12 @@ packages: decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - deep-eql@5.0.2: - resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} @@ -640,8 +653,8 @@ packages: es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - esbuild@0.25.8: - resolution: {integrity: sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==} + esbuild@0.25.11: + resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==} engines: {node: '>=18'} hasBin: true @@ -652,27 +665,25 @@ packages: resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} engines: {node: '>=12.0.0'} - fdir@6.4.6: - resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==} + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} peerDependencies: picomatch: ^3 || ^4 peerDependenciesMeta: picomatch: optional: true - foreground-child@3.3.1: - resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} - engines: {node: '>=14'} + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - glob@10.4.5: - resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} - hasBin: true - happy-dom@15.11.7: resolution: {integrity: sha512-KyrFvnl+J9US63TEzwoiJOQzZBJY7KgBushJA8X61DMbNsH+2ONkDuLDnCnwUiPTF42tLoEmrPyoqbenVA5zrg==} engines: {node: '>=18.0.0'} @@ -700,16 +711,9 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} @@ -722,33 +726,35 @@ packages: resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} engines: {node: '>=10'} - istanbul-reports@3.1.7: - resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} + istanbul-reports@3.2.0: + resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} engines: {node: '>=8'} - jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} js-tokens@9.0.1: resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} - jsdom@26.1.0: - resolution: {integrity: sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==} - engines: {node: '>=18'} + jsdom@27.1.0: + resolution: {integrity: sha512-Pcfm3eZ+eO4JdZCXthW9tCDT3nF4K+9dmeZ+5X39n+Kqz0DDIABRP5CAEOHRFZk8RGuC2efksTJxrjp8EXCunQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: canvas: ^3.0.0 peerDependenciesMeta: canvas: optional: true - loupe@3.2.0: - resolution: {integrity: sha512-2NCfZcT5VGVNX9mSZIxLRkEAegDGBpuQZBy13desuHeVORmBDyAET4TkJr4SjqQy3A8JDofMN6LpkK8Xcm/dlw==} + lru-cache@11.2.2: + resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==} + engines: {node: 20 || >=22} - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true - magic-string@0.30.17: - resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} magicast@0.3.5: resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} @@ -757,13 +763,12 @@ packages: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} + mdn-data@2.12.2: + resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} - minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} - engines: {node: '>=16 || 14 >=14.17'} + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -773,34 +778,16 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - node-sql-parser@5.3.11: - resolution: {integrity: sha512-1ZcXu2qEFZlMkkaYPpMoTkypTunYTvtnInzVjWDhjc1+FS5h/WqT1rbgP2pP42/nXBWfPVN66mEfidWSpYVs1Q==} - engines: {node: '>=8'} - - nwsapi@2.2.21: - resolution: {integrity: sha512-o6nIY3qwiSXl7/LuOU0Dmuctd34Yay0yeuZRLFmDPrrdHpXKFndPj3hM+YEPVHYC5fx2otBx4Ilc/gyYSAUaIA==} - - package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - - parse5@7.3.0: - resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + node-sql-parser@5.3.13: + resolution: {integrity: sha512-heyWv3lLjKHpcBDMUSR+R0DohRYZTYq+Ro3hJ4m9Ia8ccdKbL5UijIaWr2L4co+bmmFuvBVZ4v23QW2PqvBFAA==} engines: {node: '>=8'} - path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} + parse5@8.0.0: + resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==} pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - pathval@2.0.1: - resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} - engines: {node: '>= 14.16'} - picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -808,22 +795,48 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + pixelmatch@7.1.0: + resolution: {integrity: sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng==} + hasBin: true + + playwright-core@1.56.1: + resolution: {integrity: sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.56.1: + resolution: {integrity: sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==} + engines: {node: '>=18'} + hasBin: true + + 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} + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - rollup@4.46.2: - resolution: {integrity: sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==} + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + rollup@4.52.5: + resolution: {integrity: sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - rrweb-cssom@0.8.0: - resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} - safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -831,25 +844,17 @@ packages: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} - semver@7.7.2: - resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + 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'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} + sirv@3.0.2: + resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} + engines: {node: '>=18'} source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} @@ -858,30 +863,11 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - std-env@3.9.0: - resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} - string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} - engines: {node: '>=12'} - - strip-literal@3.0.0: - resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} - - style-mod@4.1.2: - resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==} + style-mod@4.1.3: + resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==} supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} @@ -890,62 +876,49 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - test-exclude@7.0.1: - resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==} - engines: {node: '>=18'} - tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyglobby@0.2.14: - resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} - tinypool@1.1.1: - resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} - engines: {node: ^18.0.0 || >=20.0.0} - - tinyrainbow@2.0.0: - resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} - engines: {node: '>=14.0.0'} - - tinyspy@4.0.3: - resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==} + tinyrainbow@3.0.3: + resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} engines: {node: '>=14.0.0'} - tldts-core@6.1.86: - resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} + tldts-core@7.0.17: + resolution: {integrity: sha512-DieYoGrP78PWKsrXr8MZwtQ7GLCUeLxihtjC1jZsW1DnvSMdKPitJSe8OSYDM2u5H6g3kWJZpePqkp43TfLh0g==} - tldts@6.1.86: - resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} + tldts@7.0.17: + resolution: {integrity: sha512-Y1KQBgDd/NUc+LfOtKS6mNsC9CCaH+m2P1RoIZy7RAPo3C3/t8X45+zgut31cRZtZ3xKPjfn3TkGTrctC2TQIQ==} hasBin: true - tough-cookie@5.1.2: - resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + + tough-cookie@6.0.0: + resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} engines: {node: '>=16'} - tr46@5.1.1: - resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} - engines: {node: '>=18'} + tr46@6.0.0: + resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} + engines: {node: '>=20'} - typescript@5.9.2: - resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} - vite-node@3.2.4: - resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - - vite@7.1.1: - resolution: {integrity: sha512-yJ+Mp7OyV+4S+afWo+QyoL9jFWD11QFH0i5i7JypnfTcA1rmgxCbiA8WwAICDEtZ1Z1hzrVhN8R8rGTqkTY8ZQ==} + vite@7.1.12: + resolution: {integrity: sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -984,16 +957,18 @@ packages: yaml: optional: true - vitest@3.2.4: - resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + vitest@4.0.6: + resolution: {integrity: sha512-gR7INfiVRwnEOkCk47faros/9McCZMp5LM+OMNWGLaDBSvJxIzwjgNFufkuePBNaesGRnLmNfW+ddbUJRZn0nQ==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@types/debug': ^4.1.12 - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - '@vitest/browser': 3.2.4 - '@vitest/ui': 3.2.4 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.0.6 + '@vitest/browser-preview': 4.0.6 + '@vitest/browser-webdriverio': 4.0.6 + '@vitest/ui': 4.0.6 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -1003,7 +978,11 @@ packages: optional: true '@types/node': optional: true - '@vitest/browser': + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': optional: true '@vitest/ui': optional: true @@ -1023,6 +1002,10 @@ packages: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} + webidl-conversions@8.0.0: + resolution: {integrity: sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA==} + engines: {node: '>=20'} + whatwg-encoding@3.1.1: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} @@ -1035,28 +1018,15 @@ packages: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} engines: {node: '>=18'} - whatwg-url@14.2.0: - resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} - engines: {node: '>=18'} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true + whatwg-url@15.1.0: + resolution: {integrity: sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==} + engines: {node: '>=20'} why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} hasBin: true - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} - ws@8.18.3: resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} engines: {node: '>=10.0.0'} @@ -1083,134 +1053,149 @@ packages: snapshots: - '@ampproject/remapping@2.3.0': - dependencies: - '@jridgewell/gen-mapping': 0.3.12 - '@jridgewell/trace-mapping': 0.3.29 + '@acemir/cssom@0.9.19': {} - '@asamuzakjp/css-color@3.2.0': + '@asamuzakjp/css-color@4.0.5': dependencies: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-color-parser': 3.0.10(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - lru-cache: 10.4.3 + lru-cache: 11.2.2 + + '@asamuzakjp/dom-selector@6.7.4': + dependencies: + '@asamuzakjp/nwsapi': 2.3.9 + bidi-js: 1.0.3 + css-tree: 3.1.0 + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.2.2 + + '@asamuzakjp/nwsapi@2.3.9': {} + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 '@babel/helper-string-parser@7.27.1': {} - '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-validator-identifier@7.28.5': {} - '@babel/parser@7.28.0': + '@babel/parser@7.28.5': dependencies: - '@babel/types': 7.28.2 + '@babel/types': 7.28.5 + + '@babel/runtime@7.28.4': {} - '@babel/types@7.28.2': + '@babel/types@7.28.5': dependencies: '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 '@bcoe/v8-coverage@1.0.2': {} - '@biomejs/biome@2.1.4': + '@biomejs/biome@2.3.2': optionalDependencies: - '@biomejs/cli-darwin-arm64': 2.1.4 - '@biomejs/cli-darwin-x64': 2.1.4 - '@biomejs/cli-linux-arm64': 2.1.4 - '@biomejs/cli-linux-arm64-musl': 2.1.4 - '@biomejs/cli-linux-x64': 2.1.4 - '@biomejs/cli-linux-x64-musl': 2.1.4 - '@biomejs/cli-win32-arm64': 2.1.4 - '@biomejs/cli-win32-x64': 2.1.4 - - '@biomejs/cli-darwin-arm64@2.1.4': + '@biomejs/cli-darwin-arm64': 2.3.2 + '@biomejs/cli-darwin-x64': 2.3.2 + '@biomejs/cli-linux-arm64': 2.3.2 + '@biomejs/cli-linux-arm64-musl': 2.3.2 + '@biomejs/cli-linux-x64': 2.3.2 + '@biomejs/cli-linux-x64-musl': 2.3.2 + '@biomejs/cli-win32-arm64': 2.3.2 + '@biomejs/cli-win32-x64': 2.3.2 + + '@biomejs/cli-darwin-arm64@2.3.2': optional: true - '@biomejs/cli-darwin-x64@2.1.4': + '@biomejs/cli-darwin-x64@2.3.2': optional: true - '@biomejs/cli-linux-arm64-musl@2.1.4': + '@biomejs/cli-linux-arm64-musl@2.3.2': optional: true - '@biomejs/cli-linux-arm64@2.1.4': + '@biomejs/cli-linux-arm64@2.3.2': optional: true - '@biomejs/cli-linux-x64-musl@2.1.4': + '@biomejs/cli-linux-x64-musl@2.3.2': optional: true - '@biomejs/cli-linux-x64@2.1.4': + '@biomejs/cli-linux-x64@2.3.2': optional: true - '@biomejs/cli-win32-arm64@2.1.4': + '@biomejs/cli-win32-arm64@2.3.2': optional: true - '@biomejs/cli-win32-x64@2.1.4': + '@biomejs/cli-win32-x64@2.3.2': optional: true - '@codemirror/autocomplete@6.18.6': + '@codemirror/autocomplete@6.19.1': dependencies: - '@codemirror/language': 6.11.2 + '@codemirror/language': 6.11.3 '@codemirror/state': 6.5.2 - '@codemirror/view': 6.38.1 - '@lezer/common': 1.2.3 + '@codemirror/view': 6.38.6 + '@lezer/common': 1.3.0 - '@codemirror/commands@6.8.1': + '@codemirror/commands@6.10.0': dependencies: - '@codemirror/language': 6.11.2 + '@codemirror/language': 6.11.3 '@codemirror/state': 6.5.2 - '@codemirror/view': 6.38.1 - '@lezer/common': 1.2.3 + '@codemirror/view': 6.38.6 + '@lezer/common': 1.3.0 - '@codemirror/lang-sql@6.9.1': + '@codemirror/lang-sql@6.10.0': dependencies: - '@codemirror/autocomplete': 6.18.6 - '@codemirror/language': 6.11.2 + '@codemirror/autocomplete': 6.19.1 + '@codemirror/language': 6.11.3 '@codemirror/state': 6.5.2 - '@lezer/common': 1.2.3 - '@lezer/highlight': 1.2.1 + '@lezer/common': 1.3.0 + '@lezer/highlight': 1.2.3 '@lezer/lr': 1.4.2 - '@codemirror/language@6.11.2': + '@codemirror/language@6.11.3': dependencies: '@codemirror/state': 6.5.2 - '@codemirror/view': 6.38.1 - '@lezer/common': 1.2.3 - '@lezer/highlight': 1.2.1 + '@codemirror/view': 6.38.6 + '@lezer/common': 1.3.0 + '@lezer/highlight': 1.2.3 '@lezer/lr': 1.4.2 - style-mod: 4.1.2 + style-mod: 4.1.3 - '@codemirror/lint@6.8.5': + '@codemirror/lint@6.9.0': dependencies: '@codemirror/state': 6.5.2 - '@codemirror/view': 6.38.1 + '@codemirror/view': 6.38.6 crelt: 1.0.6 '@codemirror/search@6.5.11': dependencies: '@codemirror/state': 6.5.2 - '@codemirror/view': 6.38.1 + '@codemirror/view': 6.38.6 crelt: 1.0.6 '@codemirror/state@6.5.2': dependencies: '@marijn/find-cluster-break': 1.0.2 - '@codemirror/view@6.38.1': + '@codemirror/view@6.38.6': dependencies: '@codemirror/state': 6.5.2 crelt: 1.0.6 - style-mod: 4.1.2 + style-mod: 4.1.3 w3c-keyname: 2.2.8 - '@csstools/color-helpers@5.0.2': {} + '@csstools/color-helpers@5.1.0': {} '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/css-color-parser@3.0.10(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': dependencies: - '@csstools/color-helpers': 5.0.2 + '@csstools/color-helpers': 5.1.0 '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 @@ -1219,189 +1204,196 @@ snapshots: dependencies: '@csstools/css-tokenizer': 3.0.4 + '@csstools/css-syntax-patches-for-csstree@1.0.15': {} + '@csstools/css-tokenizer@3.0.4': {} - '@esbuild/aix-ppc64@0.25.8': + '@esbuild/aix-ppc64@0.25.11': optional: true - '@esbuild/android-arm64@0.25.8': + '@esbuild/android-arm64@0.25.11': optional: true - '@esbuild/android-arm@0.25.8': + '@esbuild/android-arm@0.25.11': optional: true - '@esbuild/android-x64@0.25.8': + '@esbuild/android-x64@0.25.11': optional: true - '@esbuild/darwin-arm64@0.25.8': + '@esbuild/darwin-arm64@0.25.11': optional: true - '@esbuild/darwin-x64@0.25.8': + '@esbuild/darwin-x64@0.25.11': optional: true - '@esbuild/freebsd-arm64@0.25.8': + '@esbuild/freebsd-arm64@0.25.11': optional: true - '@esbuild/freebsd-x64@0.25.8': + '@esbuild/freebsd-x64@0.25.11': optional: true - '@esbuild/linux-arm64@0.25.8': + '@esbuild/linux-arm64@0.25.11': optional: true - '@esbuild/linux-arm@0.25.8': + '@esbuild/linux-arm@0.25.11': optional: true - '@esbuild/linux-ia32@0.25.8': + '@esbuild/linux-ia32@0.25.11': optional: true - '@esbuild/linux-loong64@0.25.8': + '@esbuild/linux-loong64@0.25.11': optional: true - '@esbuild/linux-mips64el@0.25.8': + '@esbuild/linux-mips64el@0.25.11': optional: true - '@esbuild/linux-ppc64@0.25.8': + '@esbuild/linux-ppc64@0.25.11': optional: true - '@esbuild/linux-riscv64@0.25.8': + '@esbuild/linux-riscv64@0.25.11': optional: true - '@esbuild/linux-s390x@0.25.8': + '@esbuild/linux-s390x@0.25.11': optional: true - '@esbuild/linux-x64@0.25.8': + '@esbuild/linux-x64@0.25.11': optional: true - '@esbuild/netbsd-arm64@0.25.8': + '@esbuild/netbsd-arm64@0.25.11': optional: true - '@esbuild/netbsd-x64@0.25.8': + '@esbuild/netbsd-x64@0.25.11': optional: true - '@esbuild/openbsd-arm64@0.25.8': + '@esbuild/openbsd-arm64@0.25.11': optional: true - '@esbuild/openbsd-x64@0.25.8': + '@esbuild/openbsd-x64@0.25.11': optional: true - '@esbuild/openharmony-arm64@0.25.8': + '@esbuild/openharmony-arm64@0.25.11': optional: true - '@esbuild/sunos-x64@0.25.8': + '@esbuild/sunos-x64@0.25.11': optional: true - '@esbuild/win32-arm64@0.25.8': + '@esbuild/win32-arm64@0.25.11': optional: true - '@esbuild/win32-ia32@0.25.8': + '@esbuild/win32-ia32@0.25.11': optional: true - '@esbuild/win32-x64@0.25.8': + '@esbuild/win32-x64@0.25.11': optional: true - '@isaacs/cliui@8.0.2': - dependencies: - string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.0 - strip-ansi-cjs: strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: wrap-ansi@7.0.0 - - '@istanbuljs/schema@0.1.3': {} - - '@jridgewell/gen-mapping@0.3.12': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.4 - '@jridgewell/trace-mapping': 0.3.29 - '@jridgewell/resolve-uri@3.1.2': {} - '@jridgewell/sourcemap-codec@1.5.4': {} + '@jridgewell/sourcemap-codec@1.5.5': {} - '@jridgewell/trace-mapping@0.3.29': + '@jridgewell/trace-mapping@0.3.31': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.4 + '@jridgewell/sourcemap-codec': 1.5.5 - '@lezer/common@1.2.3': {} + '@lezer/common@1.3.0': {} - '@lezer/highlight@1.2.1': + '@lezer/highlight@1.2.3': dependencies: - '@lezer/common': 1.2.3 + '@lezer/common': 1.3.0 '@lezer/lr@1.4.2': dependencies: - '@lezer/common': 1.2.3 + '@lezer/common': 1.3.0 '@marijn/find-cluster-break@1.0.2': {} - '@pkgjs/parseargs@0.11.0': + '@polka/url@1.0.0-next.29': {} + + '@rollup/rollup-android-arm-eabi@4.52.5': optional: true - '@rollup/rollup-android-arm-eabi@4.46.2': + '@rollup/rollup-android-arm64@4.52.5': optional: true - '@rollup/rollup-android-arm64@4.46.2': + '@rollup/rollup-darwin-arm64@4.52.5': optional: true - '@rollup/rollup-darwin-arm64@4.46.2': + '@rollup/rollup-darwin-x64@4.52.5': optional: true - '@rollup/rollup-darwin-x64@4.46.2': + '@rollup/rollup-freebsd-arm64@4.52.5': optional: true - '@rollup/rollup-freebsd-arm64@4.46.2': + '@rollup/rollup-freebsd-x64@4.52.5': optional: true - '@rollup/rollup-freebsd-x64@4.46.2': + '@rollup/rollup-linux-arm-gnueabihf@4.52.5': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.46.2': + '@rollup/rollup-linux-arm-musleabihf@4.52.5': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.46.2': + '@rollup/rollup-linux-arm64-gnu@4.52.5': optional: true - '@rollup/rollup-linux-arm64-gnu@4.46.2': + '@rollup/rollup-linux-arm64-musl@4.52.5': optional: true - '@rollup/rollup-linux-arm64-musl@4.46.2': + '@rollup/rollup-linux-loong64-gnu@4.52.5': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.46.2': + '@rollup/rollup-linux-ppc64-gnu@4.52.5': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.46.2': + '@rollup/rollup-linux-riscv64-gnu@4.52.5': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.46.2': + '@rollup/rollup-linux-riscv64-musl@4.52.5': optional: true - '@rollup/rollup-linux-riscv64-musl@4.46.2': + '@rollup/rollup-linux-s390x-gnu@4.52.5': optional: true - '@rollup/rollup-linux-s390x-gnu@4.46.2': + '@rollup/rollup-linux-x64-gnu@4.52.5': optional: true - '@rollup/rollup-linux-x64-gnu@4.46.2': + '@rollup/rollup-linux-x64-musl@4.52.5': optional: true - '@rollup/rollup-linux-x64-musl@4.46.2': + '@rollup/rollup-openharmony-arm64@4.52.5': optional: true - '@rollup/rollup-win32-arm64-msvc@4.46.2': + '@rollup/rollup-win32-arm64-msvc@4.52.5': optional: true - '@rollup/rollup-win32-ia32-msvc@4.46.2': + '@rollup/rollup-win32-ia32-msvc@4.52.5': optional: true - '@rollup/rollup-win32-x64-msvc@4.46.2': + '@rollup/rollup-win32-x64-gnu@4.52.5': optional: true - '@types/chai@5.2.2': + '@rollup/rollup-win32-x64-msvc@4.52.5': + optional: true + + '@standard-schema/spec@1.0.0': {} + + '@testing-library/dom@10.4.1': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/runtime': 7.28.4 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + picocolors: 1.1.1 + pretty-format: 27.5.1 + + '@types/aria-query@5.0.4': {} + + '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 '@types/deep-eql@4.0.2': {} @@ -1414,154 +1406,157 @@ snapshots: '@types/pegjs@0.10.6': {} - '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/node@22.13.1)(happy-dom@15.11.7)(jsdom@26.1.0)(yaml@2.8.0))': + '@vitest/browser-playwright@4.0.6(playwright@1.56.1)(vite@7.1.12(@types/node@22.13.1)(yaml@2.8.0))(vitest@4.0.6)': + dependencies: + '@vitest/browser': 4.0.6(vite@7.1.12(@types/node@22.13.1)(yaml@2.8.0))(vitest@4.0.6) + '@vitest/mocker': 4.0.6(vite@7.1.12(@types/node@22.13.1)(yaml@2.8.0)) + playwright: 1.56.1 + tinyrainbow: 3.0.3 + vitest: 4.0.6(@types/node@22.13.1)(@vitest/browser-playwright@4.0.6)(happy-dom@15.11.7)(jsdom@27.1.0)(yaml@2.8.0) + transitivePeerDependencies: + - bufferutil + - msw + - utf-8-validate + - vite + + '@vitest/browser@4.0.6(vite@7.1.12(@types/node@22.13.1)(yaml@2.8.0))(vitest@4.0.6)': + dependencies: + '@vitest/mocker': 4.0.6(vite@7.1.12(@types/node@22.13.1)(yaml@2.8.0)) + '@vitest/utils': 4.0.6 + magic-string: 0.30.21 + pixelmatch: 7.1.0 + pngjs: 7.0.0 + sirv: 3.0.2 + tinyrainbow: 3.0.3 + vitest: 4.0.6(@types/node@22.13.1)(@vitest/browser-playwright@4.0.6)(happy-dom@15.11.7)(jsdom@27.1.0)(yaml@2.8.0) + ws: 8.18.3 + transitivePeerDependencies: + - bufferutil + - msw + - utf-8-validate + - vite + + '@vitest/coverage-v8@4.0.6(@vitest/browser@4.0.6(vite@7.1.12(@types/node@22.13.1)(yaml@2.8.0))(vitest@4.0.6))(vitest@4.0.6)': dependencies: - '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 - ast-v8-to-istanbul: 0.3.3 - debug: 4.4.1 + '@vitest/utils': 4.0.6 + ast-v8-to-istanbul: 0.3.8 + debug: 4.4.3 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.6 - istanbul-reports: 3.1.7 - magic-string: 0.30.17 + istanbul-reports: 3.2.0 magicast: 0.3.5 - std-env: 3.9.0 - test-exclude: 7.0.1 - tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/node@22.13.1)(happy-dom@15.11.7)(jsdom@26.1.0)(yaml@2.8.0) + std-env: 3.10.0 + tinyrainbow: 3.0.3 + vitest: 4.0.6(@types/node@22.13.1)(@vitest/browser-playwright@4.0.6)(happy-dom@15.11.7)(jsdom@27.1.0)(yaml@2.8.0) + optionalDependencies: + '@vitest/browser': 4.0.6(vite@7.1.12(@types/node@22.13.1)(yaml@2.8.0))(vitest@4.0.6) transitivePeerDependencies: - supports-color - '@vitest/expect@3.2.4': + '@vitest/expect@4.0.6': dependencies: - '@types/chai': 5.2.2 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.2.1 - tinyrainbow: 2.0.0 + '@standard-schema/spec': 1.0.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.0.6 + '@vitest/utils': 4.0.6 + chai: 6.2.0 + tinyrainbow: 3.0.3 - '@vitest/mocker@3.2.4(vite@7.1.1(@types/node@22.13.1)(yaml@2.8.0))': + '@vitest/mocker@4.0.6(vite@7.1.12(@types/node@22.13.1)(yaml@2.8.0))': dependencies: - '@vitest/spy': 3.2.4 + '@vitest/spy': 4.0.6 estree-walker: 3.0.3 - magic-string: 0.30.17 + magic-string: 0.30.21 optionalDependencies: - vite: 7.1.1(@types/node@22.13.1)(yaml@2.8.0) + vite: 7.1.12(@types/node@22.13.1)(yaml@2.8.0) - '@vitest/pretty-format@3.2.4': + '@vitest/pretty-format@4.0.6': dependencies: - tinyrainbow: 2.0.0 + tinyrainbow: 3.0.3 - '@vitest/runner@3.2.4': + '@vitest/runner@4.0.6': dependencies: - '@vitest/utils': 3.2.4 + '@vitest/utils': 4.0.6 pathe: 2.0.3 - strip-literal: 3.0.0 - '@vitest/snapshot@3.2.4': + '@vitest/snapshot@4.0.6': dependencies: - '@vitest/pretty-format': 3.2.4 - magic-string: 0.30.17 + '@vitest/pretty-format': 4.0.6 + magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@3.2.4': - dependencies: - tinyspy: 4.0.3 + '@vitest/spy@4.0.6': {} - '@vitest/utils@3.2.4': + '@vitest/utils@4.0.6': dependencies: - '@vitest/pretty-format': 3.2.4 - loupe: 3.2.0 - tinyrainbow: 2.0.0 + '@vitest/pretty-format': 4.0.6 + tinyrainbow: 3.0.3 agent-base@7.1.4: {} ansi-regex@5.0.1: {} - ansi-regex@6.1.0: {} + ansi-styles@5.2.0: {} - ansi-styles@4.3.0: + aria-query@5.3.0: dependencies: - color-convert: 2.0.1 - - ansi-styles@6.2.1: {} + dequal: 2.0.3 assertion-error@2.0.1: {} - ast-v8-to-istanbul@0.3.3: + ast-v8-to-istanbul@0.3.8: dependencies: - '@jridgewell/trace-mapping': 0.3.29 + '@jridgewell/trace-mapping': 0.3.31 estree-walker: 3.0.3 js-tokens: 9.0.1 - balanced-match@1.0.2: {} - - big-integer@1.6.52: {} - - brace-expansion@2.0.2: + bidi-js@1.0.3: dependencies: - balanced-match: 1.0.2 + require-from-string: 2.0.2 - cac@6.7.14: {} - - chai@5.2.1: - dependencies: - assertion-error: 2.0.1 - check-error: 2.1.1 - deep-eql: 5.0.2 - loupe: 3.2.0 - pathval: 2.0.1 + big-integer@1.6.52: {} - check-error@2.1.1: {} + chai@6.2.0: {} codemirror@6.0.2: dependencies: - '@codemirror/autocomplete': 6.18.6 - '@codemirror/commands': 6.8.1 - '@codemirror/language': 6.11.2 - '@codemirror/lint': 6.8.5 + '@codemirror/autocomplete': 6.19.1 + '@codemirror/commands': 6.10.0 + '@codemirror/language': 6.11.3 + '@codemirror/lint': 6.9.0 '@codemirror/search': 6.5.11 '@codemirror/state': 6.5.2 - '@codemirror/view': 6.38.1 - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} + '@codemirror/view': 6.38.6 crelt@1.0.6: {} - cross-spawn@7.0.6: + css-tree@3.1.0: dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 + mdn-data: 2.12.2 + source-map-js: 1.2.1 - cssstyle@4.6.0: + cssstyle@5.3.2: dependencies: - '@asamuzakjp/css-color': 3.2.0 - rrweb-cssom: 0.8.0 + '@asamuzakjp/css-color': 4.0.5 + '@csstools/css-syntax-patches-for-csstree': 1.0.15 + css-tree: 3.1.0 - data-urls@5.0.0: + data-urls@6.0.0: dependencies: whatwg-mimetype: 4.0.0 - whatwg-url: 14.2.0 + whatwg-url: 15.1.0 - debug@4.4.1: + debug@4.4.3: dependencies: ms: 2.1.3 decimal.js@10.6.0: {} - deep-eql@5.0.2: {} - - eastasianwidth@0.2.0: {} - - emoji-regex@8.0.0: {} + dequal@2.0.3: {} - emoji-regex@9.2.2: {} + dom-accessibility-api@0.5.16: {} entities@4.5.0: optional: true @@ -1570,34 +1565,34 @@ snapshots: es-module-lexer@1.7.0: {} - esbuild@0.25.8: + esbuild@0.25.11: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.8 - '@esbuild/android-arm': 0.25.8 - '@esbuild/android-arm64': 0.25.8 - '@esbuild/android-x64': 0.25.8 - '@esbuild/darwin-arm64': 0.25.8 - '@esbuild/darwin-x64': 0.25.8 - '@esbuild/freebsd-arm64': 0.25.8 - '@esbuild/freebsd-x64': 0.25.8 - '@esbuild/linux-arm': 0.25.8 - '@esbuild/linux-arm64': 0.25.8 - '@esbuild/linux-ia32': 0.25.8 - '@esbuild/linux-loong64': 0.25.8 - '@esbuild/linux-mips64el': 0.25.8 - '@esbuild/linux-ppc64': 0.25.8 - '@esbuild/linux-riscv64': 0.25.8 - '@esbuild/linux-s390x': 0.25.8 - '@esbuild/linux-x64': 0.25.8 - '@esbuild/netbsd-arm64': 0.25.8 - '@esbuild/netbsd-x64': 0.25.8 - '@esbuild/openbsd-arm64': 0.25.8 - '@esbuild/openbsd-x64': 0.25.8 - '@esbuild/openharmony-arm64': 0.25.8 - '@esbuild/sunos-x64': 0.25.8 - '@esbuild/win32-arm64': 0.25.8 - '@esbuild/win32-ia32': 0.25.8 - '@esbuild/win32-x64': 0.25.8 + '@esbuild/aix-ppc64': 0.25.11 + '@esbuild/android-arm': 0.25.11 + '@esbuild/android-arm64': 0.25.11 + '@esbuild/android-x64': 0.25.11 + '@esbuild/darwin-arm64': 0.25.11 + '@esbuild/darwin-x64': 0.25.11 + '@esbuild/freebsd-arm64': 0.25.11 + '@esbuild/freebsd-x64': 0.25.11 + '@esbuild/linux-arm': 0.25.11 + '@esbuild/linux-arm64': 0.25.11 + '@esbuild/linux-ia32': 0.25.11 + '@esbuild/linux-loong64': 0.25.11 + '@esbuild/linux-mips64el': 0.25.11 + '@esbuild/linux-ppc64': 0.25.11 + '@esbuild/linux-riscv64': 0.25.11 + '@esbuild/linux-s390x': 0.25.11 + '@esbuild/linux-x64': 0.25.11 + '@esbuild/netbsd-arm64': 0.25.11 + '@esbuild/netbsd-x64': 0.25.11 + '@esbuild/openbsd-arm64': 0.25.11 + '@esbuild/openbsd-x64': 0.25.11 + '@esbuild/openharmony-arm64': 0.25.11 + '@esbuild/sunos-x64': 0.25.11 + '@esbuild/win32-arm64': 0.25.11 + '@esbuild/win32-ia32': 0.25.11 + '@esbuild/win32-x64': 0.25.11 estree-walker@3.0.3: dependencies: @@ -1605,27 +1600,16 @@ snapshots: expect-type@1.2.2: {} - fdir@6.4.6(picomatch@4.0.3): + fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 - foreground-child@3.3.1: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 + fsevents@2.3.2: + optional: true fsevents@2.3.3: optional: true - glob@10.4.5: - dependencies: - foreground-child: 3.3.1 - jackspeak: 3.4.3 - minimatch: 9.0.5 - minipass: 7.1.2 - package-json-from-dist: 1.0.1 - path-scurry: 1.11.1 - happy-dom@15.11.7: dependencies: entities: 4.5.0 @@ -1644,14 +1628,14 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -1659,12 +1643,8 @@ snapshots: dependencies: safer-buffer: 2.1.2 - is-fullwidth-code-point@3.0.0: {} - is-potential-custom-element-name@1.0.1: {} - isexe@2.0.0: {} - istanbul-lib-coverage@3.2.2: {} istanbul-lib-report@3.0.1: @@ -1675,45 +1655,41 @@ snapshots: istanbul-lib-source-maps@5.0.6: dependencies: - '@jridgewell/trace-mapping': 0.3.29 - debug: 4.4.1 + '@jridgewell/trace-mapping': 0.3.31 + debug: 4.4.3 istanbul-lib-coverage: 3.2.2 transitivePeerDependencies: - supports-color - istanbul-reports@3.1.7: + istanbul-reports@3.2.0: dependencies: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 - jackspeak@3.4.3: - dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 + js-tokens@4.0.0: {} js-tokens@9.0.1: {} - jsdom@26.1.0: + jsdom@27.1.0: dependencies: - cssstyle: 4.6.0 - data-urls: 5.0.0 + '@acemir/cssom': 0.9.19 + '@asamuzakjp/dom-selector': 6.7.4 + cssstyle: 5.3.2 + data-urls: 6.0.0 decimal.js: 10.6.0 html-encoding-sniffer: 4.0.0 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 is-potential-custom-element-name: 1.0.1 - nwsapi: 2.2.21 - parse5: 7.3.0 - rrweb-cssom: 0.8.0 + parse5: 8.0.0 saxes: 6.0.0 symbol-tree: 3.2.4 - tough-cookie: 5.1.2 + tough-cookie: 6.0.0 w3c-xmlserializer: 5.0.0 - webidl-conversions: 7.0.0 + webidl-conversions: 8.0.0 whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 - whatwg-url: 14.2.0 + whatwg-url: 15.1.0 ws: 8.18.3 xml-name-validator: 5.0.0 transitivePeerDependencies: @@ -1721,147 +1697,130 @@ snapshots: - supports-color - utf-8-validate - loupe@3.2.0: {} + lru-cache@11.2.2: {} - lru-cache@10.4.3: {} + lz-string@1.5.0: {} - magic-string@0.30.17: + magic-string@0.30.21: dependencies: - '@jridgewell/sourcemap-codec': 1.5.4 + '@jridgewell/sourcemap-codec': 1.5.5 magicast@0.3.5: dependencies: - '@babel/parser': 7.28.0 - '@babel/types': 7.28.2 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 source-map-js: 1.2.1 make-dir@4.0.0: dependencies: - semver: 7.7.2 + semver: 7.7.3 - minimatch@9.0.5: - dependencies: - brace-expansion: 2.0.2 + mdn-data@2.12.2: {} - minipass@7.1.2: {} + mrmime@2.0.1: {} ms@2.1.3: {} nanoid@3.3.11: {} - node-sql-parser@5.3.11: + node-sql-parser@5.3.13: dependencies: '@types/pegjs': 0.10.6 big-integer: 1.6.52 - nwsapi@2.2.21: {} - - package-json-from-dist@1.0.1: {} - - parse5@7.3.0: + parse5@8.0.0: dependencies: entities: 6.0.1 - path-key@3.1.1: {} - - path-scurry@1.11.1: - dependencies: - lru-cache: 10.4.3 - minipass: 7.1.2 - pathe@2.0.3: {} - pathval@2.0.1: {} - picocolors@1.1.1: {} picomatch@4.0.3: {} + pixelmatch@7.1.0: + dependencies: + pngjs: 7.0.0 + + playwright-core@1.56.1: {} + + playwright@1.56.1: + dependencies: + playwright-core: 1.56.1 + optionalDependencies: + fsevents: 2.3.2 + + pngjs@7.0.0: {} + postcss@8.5.6: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 source-map-js: 1.2.1 + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + punycode@2.3.1: {} - rollup@4.46.2: + react-is@17.0.2: {} + + require-from-string@2.0.2: {} + + rollup@4.52.5: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.46.2 - '@rollup/rollup-android-arm64': 4.46.2 - '@rollup/rollup-darwin-arm64': 4.46.2 - '@rollup/rollup-darwin-x64': 4.46.2 - '@rollup/rollup-freebsd-arm64': 4.46.2 - '@rollup/rollup-freebsd-x64': 4.46.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.46.2 - '@rollup/rollup-linux-arm-musleabihf': 4.46.2 - '@rollup/rollup-linux-arm64-gnu': 4.46.2 - '@rollup/rollup-linux-arm64-musl': 4.46.2 - '@rollup/rollup-linux-loongarch64-gnu': 4.46.2 - '@rollup/rollup-linux-ppc64-gnu': 4.46.2 - '@rollup/rollup-linux-riscv64-gnu': 4.46.2 - '@rollup/rollup-linux-riscv64-musl': 4.46.2 - '@rollup/rollup-linux-s390x-gnu': 4.46.2 - '@rollup/rollup-linux-x64-gnu': 4.46.2 - '@rollup/rollup-linux-x64-musl': 4.46.2 - '@rollup/rollup-win32-arm64-msvc': 4.46.2 - '@rollup/rollup-win32-ia32-msvc': 4.46.2 - '@rollup/rollup-win32-x64-msvc': 4.46.2 + '@rollup/rollup-android-arm-eabi': 4.52.5 + '@rollup/rollup-android-arm64': 4.52.5 + '@rollup/rollup-darwin-arm64': 4.52.5 + '@rollup/rollup-darwin-x64': 4.52.5 + '@rollup/rollup-freebsd-arm64': 4.52.5 + '@rollup/rollup-freebsd-x64': 4.52.5 + '@rollup/rollup-linux-arm-gnueabihf': 4.52.5 + '@rollup/rollup-linux-arm-musleabihf': 4.52.5 + '@rollup/rollup-linux-arm64-gnu': 4.52.5 + '@rollup/rollup-linux-arm64-musl': 4.52.5 + '@rollup/rollup-linux-loong64-gnu': 4.52.5 + '@rollup/rollup-linux-ppc64-gnu': 4.52.5 + '@rollup/rollup-linux-riscv64-gnu': 4.52.5 + '@rollup/rollup-linux-riscv64-musl': 4.52.5 + '@rollup/rollup-linux-s390x-gnu': 4.52.5 + '@rollup/rollup-linux-x64-gnu': 4.52.5 + '@rollup/rollup-linux-x64-musl': 4.52.5 + '@rollup/rollup-openharmony-arm64': 4.52.5 + '@rollup/rollup-win32-arm64-msvc': 4.52.5 + '@rollup/rollup-win32-ia32-msvc': 4.52.5 + '@rollup/rollup-win32-x64-gnu': 4.52.5 + '@rollup/rollup-win32-x64-msvc': 4.52.5 fsevents: 2.3.3 - rrweb-cssom@0.8.0: {} - safer-buffer@2.1.2: {} saxes@6.0.0: dependencies: xmlchars: 2.2.0 - semver@7.7.2: {} - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} + semver@7.7.3: {} siginfo@2.0.0: {} - signal-exit@4.1.0: {} + sirv@3.0.2: + dependencies: + '@polka/url': 1.0.0-next.29 + mrmime: 2.0.1 + totalist: 3.0.1 source-map-js@1.2.1: {} stackback@0.0.2: {} - std-env@3.9.0: {} + std-env@3.10.0: {} - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - - string-width@5.1.2: - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.1.0 - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - strip-ansi@7.1.0: - dependencies: - ansi-regex: 6.1.0 - - strip-literal@3.0.0: - dependencies: - js-tokens: 9.0.1 - - style-mod@4.1.2: {} + style-mod@4.1.3: {} supports-color@7.2.0: dependencies: @@ -1869,109 +1828,78 @@ snapshots: symbol-tree@3.2.4: {} - test-exclude@7.0.1: - dependencies: - '@istanbuljs/schema': 0.1.3 - glob: 10.4.5 - minimatch: 9.0.5 - tinybench@2.9.0: {} tinyexec@0.3.2: {} - tinyglobby@0.2.14: + tinyglobby@0.2.15: dependencies: - fdir: 6.4.6(picomatch@4.0.3) + fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 - tinypool@1.1.1: {} - - tinyrainbow@2.0.0: {} + tinyrainbow@3.0.3: {} - tinyspy@4.0.3: {} + tldts-core@7.0.17: {} - tldts-core@6.1.86: {} - - tldts@6.1.86: + tldts@7.0.17: dependencies: - tldts-core: 6.1.86 + tldts-core: 7.0.17 + + totalist@3.0.1: {} - tough-cookie@5.1.2: + tough-cookie@6.0.0: dependencies: - tldts: 6.1.86 + tldts: 7.0.17 - tr46@5.1.1: + tr46@6.0.0: dependencies: punycode: 2.3.1 - typescript@5.9.2: {} + typescript@5.9.3: {} undici-types@6.20.0: optional: true - vite-node@3.2.4(@types/node@22.13.1)(yaml@2.8.0): - dependencies: - cac: 6.7.14 - debug: 4.4.1 - es-module-lexer: 1.7.0 - pathe: 2.0.3 - vite: 7.1.1(@types/node@22.13.1)(yaml@2.8.0) - transitivePeerDependencies: - - '@types/node' - - jiti - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - vite@7.1.1(@types/node@22.13.1)(yaml@2.8.0): + vite@7.1.12(@types/node@22.13.1)(yaml@2.8.0): dependencies: - esbuild: 0.25.8 - fdir: 6.4.6(picomatch@4.0.3) + esbuild: 0.25.11 + fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.46.2 - tinyglobby: 0.2.14 + rollup: 4.52.5 + tinyglobby: 0.2.15 optionalDependencies: '@types/node': 22.13.1 fsevents: 2.3.3 yaml: 2.8.0 - vitest@3.2.4(@types/node@22.13.1)(happy-dom@15.11.7)(jsdom@26.1.0)(yaml@2.8.0): - dependencies: - '@types/chai': 5.2.2 - '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.1.1(@types/node@22.13.1)(yaml@2.8.0)) - '@vitest/pretty-format': 3.2.4 - '@vitest/runner': 3.2.4 - '@vitest/snapshot': 3.2.4 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.2.1 - debug: 4.4.1 + vitest@4.0.6(@types/node@22.13.1)(@vitest/browser-playwright@4.0.6)(happy-dom@15.11.7)(jsdom@27.1.0)(yaml@2.8.0): + dependencies: + '@vitest/expect': 4.0.6 + '@vitest/mocker': 4.0.6(vite@7.1.12(@types/node@22.13.1)(yaml@2.8.0)) + '@vitest/pretty-format': 4.0.6 + '@vitest/runner': 4.0.6 + '@vitest/snapshot': 4.0.6 + '@vitest/spy': 4.0.6 + '@vitest/utils': 4.0.6 + debug: 4.4.3 + es-module-lexer: 1.7.0 expect-type: 1.2.2 - magic-string: 0.30.17 + magic-string: 0.30.21 pathe: 2.0.3 picomatch: 4.0.3 - std-env: 3.9.0 + std-env: 3.10.0 tinybench: 2.9.0 tinyexec: 0.3.2 - tinyglobby: 0.2.14 - tinypool: 1.1.1 - tinyrainbow: 2.0.0 - vite: 7.1.1(@types/node@22.13.1)(yaml@2.8.0) - vite-node: 3.2.4(@types/node@22.13.1)(yaml@2.8.0) + tinyglobby: 0.2.15 + tinyrainbow: 3.0.3 + vite: 7.1.12(@types/node@22.13.1)(yaml@2.8.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.13.1 + '@vitest/browser-playwright': 4.0.6(playwright@1.56.1)(vite@7.1.12(@types/node@22.13.1)(yaml@2.8.0))(vitest@4.0.6) happy-dom: 15.11.7 - jsdom: 26.1.0 + jsdom: 27.1.0 transitivePeerDependencies: - jiti - less @@ -1992,7 +1920,10 @@ snapshots: dependencies: xml-name-validator: 5.0.0 - webidl-conversions@7.0.0: {} + webidl-conversions@7.0.0: + optional: true + + webidl-conversions@8.0.0: {} whatwg-encoding@3.1.1: dependencies: @@ -2003,32 +1934,16 @@ snapshots: whatwg-mimetype@4.0.0: {} - whatwg-url@14.2.0: + whatwg-url@15.1.0: dependencies: - tr46: 5.1.1 - webidl-conversions: 7.0.0 - - which@2.0.2: - dependencies: - isexe: 2.0.0 + tr46: 6.0.0 + webidl-conversions: 8.0.0 why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 stackback: 0.0.2 - wrap-ansi@7.0.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - wrap-ansi@8.1.0: - dependencies: - ansi-styles: 6.2.1 - string-width: 5.1.2 - strip-ansi: 7.1.0 - ws@8.18.3: {} xml-name-validator@5.0.0: {} diff --git a/renovate.json b/renovate.json index 22a9943..920a244 100644 --- a/renovate.json +++ b/renovate.json @@ -1,4 +1,14 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": ["config:recommended"] -} + "extends": [ + "config:recommended" + ], + "packageRules": [ + { + "matchPackageNames": [ + "@codemirror/lint" + ], + "allowedVersions": "!6.9.1" + } + ] +} \ No newline at end of file diff --git a/src/__tests__/index.test.ts b/src/__tests__/index.test.ts index 793aced..4ce21fa 100644 --- a/src/__tests__/index.test.ts +++ b/src/__tests__/index.test.ts @@ -1,6 +1,7 @@ import { readdir } from "node:fs/promises"; import { join } from "node:path"; import { describe, expect, it } from "vitest"; +import * as dialects from "../dialects"; import * as exports from "../index"; describe("index.ts exports", () => { @@ -34,3 +35,15 @@ describe("keywords", async () => { } }); }); + +describe("dialects.ts exports", () => { + it("should not change unexpectedly", () => { + const sortedExports = Object.keys(dialects).sort(); + expect(sortedExports).toMatchInlineSnapshot(` + [ + "BigQueryDialect", + "DuckDBDialect", + ] + `); + }); +}); diff --git a/src/browser_tests/sql-editor.test.ts b/src/browser_tests/sql-editor.test.ts new file mode 100644 index 0000000..40744cc --- /dev/null +++ b/src/browser_tests/sql-editor.test.ts @@ -0,0 +1,87 @@ +import { PostgreSQL, sql } from "@codemirror/lang-sql"; +import { basicSetup, EditorView } from "codemirror"; +import { expect, test } from "vitest"; +import { NodeSqlParser, sqlExtension } from "../index.js"; + +const schema: Record = { + users: ["id", "name", "email", "active", "status", "created_at"], + posts: ["id", "title", "content", "user_id", "published", "created_at"], + orders: ["id", "customer_id", "order_date", "total_amount", "status"], + customers: ["id", "first_name", "last_name", "email", "phone"], + categories: ["id", "name", "description", "parent_id"], + tbl: ["id", "name"], +}; + +function initializeEditor(container: HTMLElement) { + const parser = new NodeSqlParser({ + getParserOptions: () => { + return { + database: "PostgreSQL", + }; + }, + }); + + const extensions = [ + basicSetup, + EditorView.lineWrapping, + sql({ + dialect: PostgreSQL, + schema: schema, + upperCaseKeywords: true, + }), + sqlExtension({ + linterConfig: { + delay: 250, + parser, + }, + gutterConfig: { + backgroundColor: "#3b82f6", + errorBackgroundColor: "#ef4444", + hideWhenNotFocused: true, + parser, + }, + enableHover: false, + }), + ]; + + const editor = new EditorView({ + doc: "", + extensions, + parent: container, + }); + + return editor; +} + +test("SQL editor with input", { timeout: 5000 }, async () => { + const container = document.createElement("div"); + container.id = "sql-editor-test"; + container.style.width = "800px"; + container.style.height = "400px"; + document.body.appendChild(container); + + const editor = initializeEditor(container); + + const sqlText = "select * from tbl\n inner join"; + + editor.dispatch({ + changes: { + from: 0, + to: editor.state.doc.length, + insert: sqlText, + }, + selection: { + anchor: sqlText.length, + head: sqlText.length, + }, + }); + + editor.focus(); + + // Wait a moment for potential browser freeze + await new Promise((resolve) => setTimeout(resolve, 2000)); + + // If we get here, test should complete quickly + const content = editor.state.doc.toString(); + expect(content).toBe(sqlText); +}); diff --git a/src/dialects/bigquery.ts b/src/dialects/bigquery.ts new file mode 100644 index 0000000..f1209c4 --- /dev/null +++ b/src/dialects/bigquery.ts @@ -0,0 +1,14 @@ +import { PostgreSQL, SQLDialect, type SQLDialectSpec } from "@codemirror/lang-sql"; + +/** + * There is no custom BigQuery dialect at the moment, + * but we want to provide a light wrapper around PostgreSQL + */ + +const BigQuery: SQLDialectSpec = { + ...PostgreSQL, + caseInsensitiveIdentifiers: true, // Case-insensitive completes + identifierQuotes: "`", // BigQuery uses backticks for identifiers +}; + +export const BigQueryDialect = SQLDialect.define(BigQuery); diff --git a/src/dialects/duckdb/duckdb.ts b/src/dialects/duckdb/duckdb.ts index 81d1aaa..e9814aa 100644 --- a/src/dialects/duckdb/duckdb.ts +++ b/src/dialects/duckdb/duckdb.ts @@ -13,7 +13,8 @@ const DuckDBDialectSpec: SQLDialectSpec = { hashComments: false, spaceAfterDashes: false, specialVar: "@?", - identifierQuotes: "`", + identifierQuotes: '"', + caseInsensitiveIdentifiers: true, keywords: `${otherFunctions} !__postfix !~~ !~~* % & && * ** + - ->> / // <-> << <=> <@ >> @ @> Calendar JSON TimeZone ^ ^@ abort abs absolute access access_mode acos acosh action add add_parquet_key admin after age aggregate alias all all_profiling_output allow_community_extensions allow_extensions_metadata_mismatch allow_persistent_secrets allow_unredacted_secrets allow_unsigned_extensions allowed_directories allowed_paths also alter always analyse analyze and anti any any_value apply approx_count_distinct approx_quantile approx_top_k arbitrary arg_max arg_max_null arg_min arg_min_null argmax argmin array array_agg array_aggr array_aggregate array_append array_apply array_cat array_concat array_contains array_cosine_distance array_cosine_similarity array_cross_product array_distance array_distinct array_dot_product array_extract array_filter array_grade_up array_has array_has_all array_has_any array_indexof array_inner_product array_intersect array_length array_negative_dot_product array_negative_inner_product array_pop_back array_pop_front array_position array_prepend array_push_back array_push_front array_reduce array_resize array_reverse array_reverse_sort array_select array_slice array_sort array_to_json array_to_string array_to_string_comma_default array_transform array_unique array_value array_where array_zip arrow_large_buffer_size arrow_lossless_conversion arrow_output_list_view arrow_output_version arrow_scan arrow_scan_dumb as asc ascii asin asinh asof asof_loop_join_threshold assertion assignment asymmetric at atan atan2 atanh attach attribute authorization autoinstall_extension_repository autoinstall_known_extensions autoload_known_extensions avg backward bar base64 before begin between bigint bin binary binary_as_string bit bit_and bit_count bit_length bit_or bit_position bit_xor bitstring bitstring_agg blob bool bool_and bool_or boolean both bpchar by bytea cache call called can_cast_implicitly cardinality cascade cascaded case cast cast_to_type catalog catalog_error_max_schemas cbrt ceil ceiling centuries century chain char char_length character character_length characteristics check checkpoint checkpoint_threshold chr class close cluster coalesce col_description collate collation collations column columns combine comment comments commit committed compression concat concat_ws concurrently configuration conflict connection constant_or_null constraint constraints contains content continue conversion copy copy_database corr cos cosh cost cot count count_if count_star countif covar_pop covar_samp create create_sort_key cross csv cube current current_catalog current_connection_id current_database current_date current_localtime current_localtimestamp current_query current_query_id current_role current_schema current_schemas current_setting current_transaction_id current_user currval cursor custom_extension_repository custom_profiling_settings custom_user_agent cycle damerau_levenshtein data database database_list database_size date date_add date_diff date_part date_sub date_trunc datediff datepart datesub datetime datetrunc day dayname dayofmonth dayofweek dayofyear days deallocate debug_asof_iejoin debug_checkpoint_abort debug_force_external debug_force_no_cross_product debug_skip_checkpoint_on_commit debug_verify_vector debug_window_mode dec decade decades decimal declare decode default default_block_size default_collation default_null_order default_order default_secret_storage defaults deferrable deferred definer degrees delete delimiter delimiters depends desc describe detach dictionary disable disable_checkpoint_on_shutdown disable_logging disable_object_cache disable_optimizer disable_parquet_prefetching disable_print_progress_bar disable_profile disable_profiling disable_progress_bar disable_timestamptz_casts disable_verification disable_verify_external disable_verify_fetch_row disable_verify_parallelism disable_verify_serializer disabled_compression_methods disabled_filesystems disabled_log_types disabled_optimizers discard distinct divide do document domain double drop duckdb_api duckdb_columns duckdb_constraints duckdb_databases duckdb_dependencies duckdb_extensions duckdb_external_file_cache duckdb_functions duckdb_indexes duckdb_keywords duckdb_log_contexts duckdb_logs duckdb_logs_parsed duckdb_memory duckdb_optimizers duckdb_prepared_statements duckdb_schemas duckdb_secret_types duckdb_secrets duckdb_sequences duckdb_settings duckdb_table_sample duckdb_tables duckdb_temporary_files duckdb_types duckdb_variables duckdb_views dynamic_or_filter_threshold each editdist3 element_at else enable enable_checkpoint_on_shutdown enable_external_access enable_external_file_cache enable_fsst_vectors enable_geoparquet_conversion enable_http_logging enable_http_metadata_cache enable_logging enable_macro_dependencies enable_object_cache enable_optimizer enable_print_progress_bar enable_profile enable_profiling enable_progress_bar enable_progress_bar_print enable_verification enable_view_dependencies enabled_log_types encode encoding encrypted end ends_with entropy enum enum_code enum_first enum_last enum_range enum_range_boundary epoch epoch_ms epoch_ns epoch_us equi_width_bins era error errors_as_json escape even event except exclude excluding exclusive execute exists exp explain explain_output export export_state extension extension_directory extension_versions extensions external external_threads extract factorial false family favg fdiv fetch file_search_path filter finalize first flatten float float4 float8 floor fmod following for force force_bitpacking_mode force_checkpoint force_compression foreign format formatReadableDecimalSize formatReadableSize format_bytes format_pg_type format_type forward freeze from from_base64 from_binary from_hex from_json from_json_strict fsum full function functions gamma gcd gen_random_uuid generate_series generate_subscripts generated geomean geometric_mean get_bit get_block_size get_current_time get_current_timestamp getvariable glob global grade_up grant granted greatest greatest_common_divisor group group_concat grouping grouping_id groups guid hamming handler having header hex histogram histogram_exact histogram_values hold home_directory hour hours http_logging_output http_proxy http_proxy_password http_proxy_username hugeint identity ieee_floating_point_ops if ignore ilike ilike_escape immediate immediate_transaction_mode immutable implicit import import_database in in_search_path include including increment index index_scan_max_count index_scan_percentage indexes inet_client_addr inet_client_port inet_server_addr inet_server_port inherit inherits initially inline inner inout input insensitive insert install instead instr int int1 int128 int16 int2 int32 int4 int64 int8 integer integer_division integral intersect interval into invoker is is_histogram_other_bin isfinite isinf isnan isnull isodow isolation isoyear jaccard jaro_similarity jaro_winkler_similarity join json json_array json_array_length json_contains json_deserialize_sql json_each json_execute_serialized_sql json_exists json_extract json_extract_path json_extract_path_text json_extract_string json_group_array json_group_object json_group_structure json_keys json_merge_patch json_object json_pretty json_quote json_serialize_plan json_serialize_sql json_structure json_transform json_transform_strict json_tree json_type json_valid json_value julian kahan_sum key kurtosis kurtosis_pop label lambda lambda_syntax language large last last_day late_materialization_max_rows lateral lcase lcm leading leakproof least least_common_multiple left left_grapheme len length length_grapheme level levenshtein lgamma like like_escape limit list list_aggr list_aggregate list_any_value list_append list_apply list_approx_count_distinct list_avg list_bit_and list_bit_or list_bit_xor list_bool_and list_bool_or list_cat list_concat list_contains list_cosine_distance list_cosine_similarity list_count list_distance list_distinct list_dot_product list_element list_entropy list_extract list_filter list_first list_grade_up list_has list_has_all list_has_any list_histogram list_indexof list_inner_product list_intersect list_kurtosis list_kurtosis_pop list_last list_mad list_max list_median list_min list_mode list_negative_dot_product list_negative_inner_product list_pack list_position list_prepend list_product list_reduce list_resize list_reverse list_reverse_sort list_select list_sem list_skewness list_slice list_sort list_stddev_pop list_stddev_samp list_string_agg list_sum list_transform list_unique list_value list_var_pop list_var_samp list_where list_zip listagg listen ln load local location lock lock_configuration locked log log10 log2 log_query_path logged logging_level logging_mode logging_storage logical long lower lpad ltrim macro mad make_date make_time make_timestamp make_timestamp_ns make_timestamptz map map_concat map_contains map_contains_entry map_contains_value map_entries map_extract map_extract_value map_from_entries map_keys map_to_pg_oid map_values mapping match materialized max max_by max_expression_depth max_memory max_temp_directory_size max_vacuum_tasks maxvalue md5 md5_number md5_number_lower md5_number_upper mean median memory_limit merge_join_threshold metadata_info method microsecond microseconds millennia millennium millisecond milliseconds min min_by minute minutes minvalue mismatches mod mode month monthname months move multiply name names nanosecond national natural nchar nested_loop_join_threshold new next nextafter nextval nfc_normalize no none normalized_interval not not_ilike_escape not_like_escape nothing notify notnull now nowait null null_order nullif nulls numeric nvarchar obj_description object octet_length of off offset oid oids old old_implicit_casting on only operator option options or ord order order_by_non_integer_literal ordered_aggregate_threshold ordinality others out outer over overlaps overlay overriding owned owner pandas_analyze_sample pandas_scan parallel parquet_bloom_probe parquet_file_metadata parquet_kv_metadata parquet_metadata parquet_metadata_cache parquet_scan parquet_schema parse_dirname parse_dirpath parse_duckdb_log_message parse_filename parse_path parser partial partition partitioned partitioned_write_flush_threshold partitioned_write_max_open_files passing password percent perfect_ht_threshold persistent pi pivot pivot_filter_threshold pivot_limit pivot_longer pivot_wider placing plans platform policy position positional pow power pragma pragma_collations pragma_database_size pragma_metadata_info pragma_platform pragma_show pragma_storage_info pragma_table_info pragma_user_agent pragma_version preceding precision prefer_range_joins prefetch_all_parquet_files prefix prepare prepared preserve preserve_identifier_case preserve_insertion_order primary printf prior privileges procedural procedure produce_arrow_string_view product profile_output profiling_mode profiling_output program progress_bar_time publication python_enable_replacements python_map_function python_scan_all_frames qualify quantile quantile_cont quantile_disc quarter quarters query query_table quote radians random range read read_blob read_csv read_csv_auto read_json read_json_auto read_json_objects read_json_objects_auto read_ndjson read_ndjson_auto read_ndjson_objects read_parquet read_text real reassign recheck recursive reduce ref references referencing refresh regexp_escape regexp_extract regexp_extract_all regexp_full_match regexp_matches regexp_replace regexp_split_to_array regexp_split_to_table regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy regr_syy reindex relative release remap_struct rename repeat repeat_row repeatable replace replica reservoir_quantile reset respect restart restrict returning returns reverse revoke right right_grapheme role rollback rollup round round_even roundbankers row row_to_json rows rpad rtrim rule sample savepoint scalar_subquery_error_on_multiple_rows scheduler_process_partial schema schemas scope scroll search search_path second seconds secret secret_directory security select sem semi seq_scan sequence sequences serializable server session session_user set set_bit setof sets setseed sha1 sha256 share shobj_description short show show_databases show_tables show_tables_expanded sign signbit signed similar simple sin sinh skewness skip smallint snapshot sniff_csv some sorted split split_part sql sqrt stable standalone start starts_with statement statistics stats stddev stddev_pop stddev_samp stdin stdout storage storage_compatibility_version storage_info stored str_split str_split_regex streaming_buffer_size strftime strict string string_agg string_split string_split_regex string_to_array strip strip_accents strlen strpos strptime struct struct_concat struct_extract struct_extract_at struct_insert struct_pack subscription substr substring substring_grapheme subtract suffix sum sum_no_overflow sumkahan summarize summary symmetric sysid system table table_info tables tablesample tablespace tan tanh temp temp_directory template temporary test_all_types test_vector_types text then threads ties time time_bucket timestamp timestamp_ms timestamp_ns timestamp_s timestamp_us timestamptz timetz timetz_byte_comparable timezone timezone_hour timezone_minute tinyint to to_base to_base64 to_binary to_centuries to_days to_decades to_hex to_hours to_json to_microseconds to_millennia to_milliseconds to_minutes to_months to_quarters to_seconds to_timestamp to_weeks to_years today trailing transaction transaction_timestamp transform translate treat trigger trim true trunc truncate truncate_duckdb_logs trusted try_cast try_strptime txid_current type typeof types ubigint ucase uhugeint uint128 uint16 uint32 uint64 uint8 uinteger unbin unbounded uncommitted unencrypted unhex unicode union union_extract union_tag union_value unique unknown unlisten unlogged unnest unpack unpivot unpivot_list until update upper url_decode url_encode use user user_agent username using usmallint utinyint uuid uuid_extract_timestamp uuid_extract_version uuidv4 uuidv7 vacuum valid validate validator value values var_pop var_samp varbinary varchar variable variadic variance varint varying vector_type verbose verify_external verify_fetch_row verify_parallelism verify_serializer version view views virtual volatile wal_autocheckpoint wavg week weekday weekofyear weeks weighted_avg when where which_secret whitespace window with within without work worker_threads wrapper write write_log xml xmlattributes xmlconcat xmlelement xmlexists xmlforest xmlnamespaces xmlparse xmlpi xmlroot xmlserialize xmltable xor year years yearweek yes zone zstd_min_string_length | || ~ ~~ ~~* ~~~`, types: "JSON bigint binary bit bitstring blob bool boolean bpchar bytea char date datetime dec decimal double enum float float4 float8 guid hugeint int int1 int128 int16 int2 int32 int4 int64 int8 integer integral interval list logical long map null numeric nvarchar oid real row short signed smallint string struct text time timestamp timestamp_ms timestamp_ns timestamp_s timestamp_us timestamptz timetz tinyint ubigint uhugeint uint128 uint16 uint32 uint64 uint8 uinteger union usmallint utinyint uuid varbinary varchar varint", diff --git a/src/dialects/index.ts b/src/dialects/index.ts new file mode 100644 index 0000000..c03ed93 --- /dev/null +++ b/src/dialects/index.ts @@ -0,0 +1,2 @@ +export { BigQueryDialect } from "./bigquery.js"; +export { DuckDBDialect } from "./duckdb/duckdb.js"; diff --git a/src/index.ts b/src/index.ts index d5f81d5..ffd9407 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,7 +8,13 @@ export type { SqlKeywordInfo, } from "./sql/hover.js"; export { DefaultSqlTooltipRenders, defaultSqlHoverTheme, sqlHover } from "./sql/hover.js"; -export { NodeSqlParser } from "./sql/parser.js"; +export { + NodeSqlParser, + type NodeSqlParserOptions, + type NodeSqlParserResult, + type ParserOption, + type SupportedDialects, +} from "./sql/parser.js"; export type { SqlStatement } from "./sql/structure-analyzer.js"; export { SqlStructureAnalyzer } from "./sql/structure-analyzer.js"; export type { SqlGutterConfig } from "./sql/structure-extension.js"; diff --git a/src/sql/__tests__/diagnostics.test.ts b/src/sql/__tests__/diagnostics.test.ts index 6394edd..2347c33 100644 --- a/src/sql/__tests__/diagnostics.test.ts +++ b/src/sql/__tests__/diagnostics.test.ts @@ -2,7 +2,7 @@ import { Text } from "@codemirror/state"; import type { EditorView } from "@codemirror/view"; import { describe, expect, it, vi } from "vitest"; import { sqlLinter } from "../diagnostics.js"; -import type { SqlParser } from "../parser.js"; +import type { SqlParser } from "../types.js"; // Mock EditorView const _createMockView = (content: string) => { diff --git a/src/sql/__tests__/hover-integration.test.ts b/src/sql/__tests__/hover-integration.test.ts index e0114ac..aaaeb5d 100644 --- a/src/sql/__tests__/hover-integration.test.ts +++ b/src/sql/__tests__/hover-integration.test.ts @@ -1,5 +1,6 @@ import type { Completion } from "@codemirror/autocomplete"; import type { SQLNamespace } from "@codemirror/lang-sql"; +import { EditorState } from "@codemirror/state"; import { describe, expect, it, vi } from "vitest"; import { defaultSqlHoverTheme, sqlHover } from "../hover.js"; import { resolveNamespaceItem } from "../namespace-utils.js"; @@ -629,6 +630,32 @@ describe("Query-aware hover behavior", () => { const tableList = await parser.extractTableReferences("INVALID SQL QUERY"); expect(tableList).toEqual([]); }); + + it("should handle hierarchical schema references", async () => { + const { NodeSqlParser } = await import("../parser.js"); + const parser = new NodeSqlParser({ + getParserOptions: (_state: EditorState) => ({ database: "PostgreSQL" }), + }); + + let sql = "SELECT * FROM products.users"; + const tableList = await parser.extractTableReferences(sql, { + state: EditorState.create({ doc: sql }), + }); + expect(tableList).toEqual(["users"]); + + sql = "SELECT * FROM products.users.orders"; + const tableList2 = await parser.extractTableReferences(sql, { + state: EditorState.create({ doc: sql }), + }); + expect(tableList2).toEqual(["orders"]); + + sql = + "SELECT * FROM products.users.orders AS o INNER JOIN customers.users AS u ON o.id = u.id"; + const tableList3 = await parser.extractTableReferences(sql, { + state: EditorState.create({ doc: sql }), + }); + expect(tableList3).toEqual(["orders", "users"]); + }); }); describe("Schema filtering based on query", () => { diff --git a/src/sql/__tests__/parser.test.ts b/src/sql/__tests__/parser.test.ts index 7f2d361..155c66e 100644 --- a/src/sql/__tests__/parser.test.ts +++ b/src/sql/__tests__/parser.test.ts @@ -1,6 +1,6 @@ import { EditorState } from "@codemirror/state"; import { describe, expect, it, vi } from "vitest"; -import { NodeSqlParser } from "../parser.js"; +import { exportedForTesting, NodeSqlParser } from "../parser.js"; describe("SqlParser", () => { const parser = new NodeSqlParser(); @@ -112,18 +112,15 @@ describe("SqlParser", () => { }); describe("DuckDB dialect support", () => { - it("should accept DuckDB-specific syntax without parsing", async () => { + it("should accept FROM queries syntax without parsing", async () => { const duckdbParser = new NodeSqlParser({ getParserOptions: () => ({ database: "DuckDB", }), }); - const state = EditorState.create({ - doc: "from nyc.rideshare select * limit 100", - }); - - const result = await duckdbParser.parse("from nyc.rideshare select * limit 100", { state }); + const sql = "from nyc.rideshare select * limit 100"; + const result = await duckdbParser.parse(sql, { state }); expect(result.success).toBe(true); expect(result.errors).toHaveLength(0); @@ -147,43 +144,231 @@ describe("SqlParser", () => { expect(result.errors).toHaveLength(0); }); - it("should accept complex DuckDB queries without parsing", async () => { + it("should treat CREATE OR REPLACE TABLE as a normal SQL query", async () => { + const duckdbParser = new NodeSqlParser({ + getParserOptions: () => ({ + database: "DuckDB", + }), + }); + + const queries = [ + "CREATE OR REPLACE TABLE users (id INT, name VARCHAR(255))", + "create or replace VIEW v1 AS SELECT 1", + ]; + + for (const sql of queries) { + const state = EditorState.create({ + doc: sql, + }); + const result = await duckdbParser.parse(sql, { state }); + expect(result.success).toBe(true); + expect(result.errors).toHaveLength(0); + expect(result.ast).toBeDefined(); + } + }); + + it("should handle error offsets correctly when replacing CREATE OR REPLACE TABLE", async () => { const duckdbParser = new NodeSqlParser({ getParserOptions: () => ({ database: "DuckDB", }), }); + // This SQL has a syntax error at the end - missing closing parenthesis + const sql = "CREATE OR REPLACE TABLE users (id INT, name VARCHAR(255), invalid_syntax"; + const state = EditorState.create({ - doc: "from nyc.rideshare select pickup_datetime, dropoff_datetime limit 50", + doc: sql, }); - const result = await duckdbParser.parse( - "from nyc.rideshare select pickup_datetime, dropoff_datetime limit 50", - { state }, - ); + const result = await duckdbParser.parse(sql, { state }); + expect(result.success).toBe(false); + expect(result.errors).toHaveLength(1); - expect(result.success).toBe(true); - expect(result.errors).toHaveLength(0); - expect(result.ast).toBeUndefined(); + const error = result.errors[0]; + + // The offset should be at the original position of the error + const expectedColumn = sql.length; + expect(error.column).toBe(expectedColumn); + }); + + it("should be successful with macro keyword", async () => { + const duckdbParser = new NodeSqlParser({ + getParserOptions: () => ({ + database: "DuckDB", + }), + }); + + const queries = ["CREATE macro test1(a) as 1"]; + + for (const sql of queries) { + const state = EditorState.create({ + doc: sql, + }); + const result = await duckdbParser.parse(sql, { state }); + expect(result.success).toBe(true); + expect(result.errors).toHaveLength(0); + } }); - it("should accept DuckDB queries with semicolons without parsing", async () => { + it("should quote {} in quotes", async () => { const duckdbParser = new NodeSqlParser({ getParserOptions: () => ({ database: "DuckDB", + ignoreBrackets: true, }), }); const state = EditorState.create({ - doc: "from posts select title, name;", + doc: "SELECT {id} FROM users WHERE id = {id} and name = {name}", }); - const result = await duckdbParser.parse("from posts select title, name;", { state }); + const sql = "SELECT {id} FROM users WHERE id = {id} and name = {name}"; + const result = await duckdbParser.parse(sql, { state }); expect(result.success).toBe(true); expect(result.errors).toHaveLength(0); - expect(result.ast).toBeUndefined(); }); }); }); + +const { removeCommentsFromStart, replaceBracketsWithQuotes } = exportedForTesting; + +describe("removeComments", () => { + it("should remove comments from the start of the query", () => { + const sql = "/* comment */ SELECT * FROM users"; + const result = removeCommentsFromStart(sql).trim(); + expect(result).toBe("SELECT * FROM users"); + }); + + it("should remove comments from the start of the query with multiple lines", () => { + const sql = ` + /* comment */ + SELECT * FROM users + `; + const result = removeCommentsFromStart(sql).trim(); + expect(result).toBe("SELECT * FROM users"); + }); + + it("should remove single line comments", () => { + const sql = ` + -- comment + SELECT * FROM users + `; + const result2 = removeCommentsFromStart(sql).trim(); + expect(result2).toBe("SELECT * FROM users"); + }); + + it("should remove comments from the start of the query with multiple lines and single line comments", () => { + const sql = ` + /* comment */ + -- comment + SELECT * FROM users + + `; + const result = removeCommentsFromStart(sql).trim(); + expect(result).toBe("SELECT * FROM users"); + }); +}); + +describe("replaceBracketsWithQuotes", () => { + it("should replace brackets with quotes", () => { + const sql = "SELECT {id} FROM users WHERE id = {id}"; + const result = replaceBracketsWithQuotes(sql); + expect(result.sql).toBe("SELECT '{id}' FROM users WHERE id = '{id}'"); + expect(result.offsetRecord).toEqual({ 7: 2, 34: 2 }); + }); + + it("should not replace brackets that are already inside quotes", () => { + const sql = "SELECT '{id}' FROM users WHERE id = '{id}'"; + const result = replaceBracketsWithQuotes(sql); + expect(result.sql).toBe("SELECT '{id}' FROM users WHERE id = '{id}'"); + expect(result.offsetRecord).toEqual({}); + }); + + it("should replace multiple brackets", () => { + const sql = "SELECT {id} FROM users WHERE id = {id} and name = {name}"; + const result = replaceBracketsWithQuotes(sql); + expect(result.sql).toBe("SELECT '{id}' FROM users WHERE id = '{id}' and name = '{name}'"); + expect(result.offsetRecord).toEqual({ 50: 2, 7: 2, 34: 2 }); + }); + + it("should not replace multiple brackets that are already inside quotes", () => { + const sql = "SELECT '{id}' FROM users WHERE id = '{id}' and name = '{name}'"; + const result = replaceBracketsWithQuotes(sql); + expect(result.sql).toBe("SELECT '{id}' FROM users WHERE id = '{id}' and name = '{name}'"); + expect(result.offsetRecord).toEqual({}); + }); + + it("should handle multiple brackets in quotes", () => { + const sql = "SELECT '{id} {name}' FROM users WHERE id = '{id} {name}'"; + const result = replaceBracketsWithQuotes(sql); + expect(result.sql).toBe("SELECT '{id} {name}' FROM users WHERE id = '{id} {name}'"); + expect(result.offsetRecord).toEqual({}); + }); + + it("should handle mixed quotes", () => { + const sql = "SELECT '{id}' FROM users WHERE id = \"{id}\""; + const result = replaceBracketsWithQuotes(sql); + expect(result.sql).toBe("SELECT '{id}' FROM users WHERE id = \"{id}\""); + expect(result.offsetRecord).toEqual({}); + }); + + it.fails("should handle escaped quotes", () => { + const sql = "SELECT \\'{id}\\' FROM users WHERE id = \\'{id}\\'"; + const result = replaceBracketsWithQuotes(sql); + expect(result.sql).toBe("SELECT \\'{id}\\' FROM users WHERE id = \\'{id}\\'"); + }); + + it("should handle brackets at the beginning of string", () => { + const sql = "{id} FROM users"; + const result = replaceBracketsWithQuotes(sql); + expect(result.sql).toBe("'{id}' FROM users"); + expect(result.offsetRecord).toEqual({ 0: 2 }); + }); + + it("should handle brackets at the end of string", () => { + const sql = "SELECT * FROM users WHERE id = {id}"; + const result = replaceBracketsWithQuotes(sql); + expect(result.sql).toBe("SELECT * FROM users WHERE id = '{id}'"); + }); + + it("should handle empty brackets", () => { + const sql = "SELECT {} FROM users"; + const result = replaceBracketsWithQuotes(sql); + expect(result.sql).toBe("SELECT '{}' FROM users"); + }); + + it("should handle brackets with spaces", () => { + const sql = "SELECT { user id } FROM users WHERE id = { user id }"; + const result = replaceBracketsWithQuotes(sql); + expect(result.sql).toBe("SELECT '{ user id }' FROM users WHERE id = '{ user id }'"); + }); + + it("should handle complex nested structures", () => { + const sql = + "SELECT {user.profile.name} FROM users WHERE id = '{user.id}' AND name = \"{user.name}\""; + const result = replaceBracketsWithQuotes(sql); + expect(result.sql).toBe( + "SELECT '{user.profile.name}' FROM users WHERE id = '{user.id}' AND name = \"{user.name}\"", + ); + }); + + it("should handle unclosed brackets", () => { + const sql = "SELECT {id FROM users"; + const result = replaceBracketsWithQuotes(sql); + expect(result.sql).toBe("SELECT {id FROM users"); + }); + + it("should handle multiple unquoted brackets in sequence", () => { + const sql = "SELECT {id}{name}{email} FROM users"; + const result = replaceBracketsWithQuotes(sql); + expect(result.sql).toBe("SELECT '{id}''{name}''{email}' FROM users"); + }); + + it("should handle brackets inside string literals with escaped quotes", () => { + const sql = "SELECT 'user\\'s {id}' FROM users"; + const result = replaceBracketsWithQuotes(sql); + expect(result.sql).toBe("SELECT 'user\\'s {id}' FROM users"); + }); +}); diff --git a/src/sql/hover.ts b/src/sql/hover.ts index ee401e6..83f9706 100644 --- a/src/sql/hover.ts +++ b/src/sql/hover.ts @@ -90,6 +90,18 @@ export interface NamespaceTooltipData { resolvedSchema: SQLNamespace; } +/** + * Internal data structure for passing parsed tooltip information to create function + */ +interface TooltipCreateData { + word: string; + view: EditorView; + pos: number; + tooltipType: "keyword" | "namespace"; + keywordData?: KeywordTooltipData; + namespaceData?: NamespaceTooltipData; +} + /** * Configuration for SQL hover tooltips */ @@ -114,6 +126,8 @@ export interface SqlHoverConfig { enableFuzzySearch?: boolean; /** Custom SQL parser instance to use for query analysis */ parser?: SqlParser; + /** Custom tooltip render function - highest priority, returns HTMLElement or null for fallback */ + tooltipRender?: (word: string, view: EditorView, pos: number) => HTMLElement | null; /** Custom tooltip renderers for different item types */ tooltipRenderers?: { /** Custom renderer for SQL keywords */ @@ -142,6 +156,7 @@ export function sqlHover(config: SqlHoverConfig = {}): Extension { enableColumns = true, enableFuzzySearch = true, parser = new NodeSqlParser(), + tooltipRender, tooltipRenderers = {}, } = config; @@ -176,7 +191,7 @@ export function sqlHover(config: SqlHoverConfig = {}): Extension { const resolvedSchema = typeof schema === "function" ? schema(view) : schema; - let tooltipContent: string | null = null; + let createData: TooltipCreateData | null = null; debug(`hover word: '${word}'`); @@ -186,16 +201,20 @@ export function sqlHover(config: SqlHoverConfig = {}): Extension { // 3. If neither, look in SQLNamespace and try to guess (fuzzy match) // Step 1: If no namespace match, try keywords - if (!tooltipContent && enableKeywords && resolvedKeywords[word]) { + if (!createData && enableKeywords && resolvedKeywords[word]) { debug("keywordResult", word, resolvedKeywords[word]); const keywordData: KeywordTooltipData = { keyword: word, info: resolvedKeywords[word] }; - tooltipContent = tooltipRenderers.keyword - ? tooltipRenderers.keyword(keywordData) - : createKeywordTooltip(keywordData); + createData = { + word, + view, + pos, + tooltipType: "keyword", + keywordData, + }; } // Step 2: Try to resolve directly in SQLNamespace (query-aware) - if (!tooltipContent && (enableTables || enableColumns) && resolvedSchema) { + if (!createData && (enableTables || enableColumns) && resolvedSchema) { // Get the current SQL query to filter schema by referenced tables const currentQuery = view.state.doc.toString(); const tableList = await parser.extractTableReferences(currentQuery); @@ -231,23 +250,13 @@ export function sqlHover(config: SqlHoverConfig = {}): Extension { resolvedSchema: tableRefs.size > 0 ? filteredSchema : resolvedSchema, }; - // Use custom renderer based on semantic type, fallback to default - const { semanticType } = namespaceResult; - if (semanticType === "table" && tooltipRenderers.table) { - tooltipContent = tooltipRenderers.table(namespaceData); - } else if (semanticType === "column" && tooltipRenderers.column) { - tooltipContent = tooltipRenderers.column(namespaceData); - } else if ( - (semanticType === "database" || - semanticType === "schema" || - semanticType === "namespace") && - tooltipRenderers.namespace - ) { - tooltipContent = tooltipRenderers.namespace(namespaceData); - } else { - // Fallback to default renderer - tooltipContent = createNamespaceTooltip(namespaceResult); - } + createData = { + word, + view, + pos, + tooltipType: "namespace", + namespaceData, + }; } else { debug("No namespace item found for:", word); } @@ -255,7 +264,7 @@ export function sqlHover(config: SqlHoverConfig = {}): Extension { // Step 3: Fuzzy matching is handled by resolveNamespaceItem if enableFuzzySearch is true - if (!tooltipContent) { + if (!createData) { return null; } @@ -263,7 +272,47 @@ export function sqlHover(config: SqlHoverConfig = {}): Extension { pos: start, end, above: true, - create(_view: EditorView) { + create(createView: EditorView) { + // Priority 1: Custom tooltipRender function + if (tooltipRender) { + const customElement = tooltipRender(word, createView, pos); + if (customElement) { + return { dom: customElement }; + } + } + + // Priority 2: Custom renderers and default renderers + let tooltipContent: string | null = null; + + if (createData.tooltipType === "keyword" && createData.keywordData) { + tooltipContent = tooltipRenderers.keyword + ? tooltipRenderers.keyword(createData.keywordData) + : createKeywordTooltip(createData.keywordData); + } else if (createData.tooltipType === "namespace" && createData.namespaceData) { + const namespaceData = createData.namespaceData; + const { semanticType } = namespaceData.item; + + if (semanticType === "table" && tooltipRenderers.table) { + tooltipContent = tooltipRenderers.table(namespaceData); + } else if (semanticType === "column" && tooltipRenderers.column) { + tooltipContent = tooltipRenderers.column(namespaceData); + } else if ( + (semanticType === "database" || + semanticType === "schema" || + semanticType === "namespace") && + tooltipRenderers.namespace + ) { + tooltipContent = tooltipRenderers.namespace(namespaceData); + } else { + // Fallback to default renderer + tooltipContent = createNamespaceTooltip(namespaceData.item); + } + } + + if (!tooltipContent) { + return { dom: document.createElement("div") }; + } + const dom = document.createElement("div"); dom.className = "cm-sql-hover-tooltip"; dom.innerHTML = tooltipContent; @@ -362,7 +411,7 @@ function createNamespaceTooltip(item: ResolvedNamespaceItem): string { } // Add completion-specific info if available - if (item.completion?.info) { + if (item.completion?.info && typeof item.completion.info === "string") { html += `
${item.completion.info}
`; } @@ -553,8 +602,8 @@ export const defaultSqlHoverTheme = (theme: "light" | "dark" = "light"): Extensi return EditorView.theme({ ".cm-sql-hover-tooltip": { padding: "8px 12px", - backgroundColor: "#ffffff", - border: "1px solid #e5e7eb", + backgroundColor: colors.tooltipBg, + border: `1px solid ${colors.tooltipBorder}`, borderRadius: "6px", boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)", fontSize: "13px", diff --git a/src/sql/parser.ts b/src/sql/parser.ts index 9a67fcd..91ed4ab 100644 --- a/src/sql/parser.ts +++ b/src/sql/parser.ts @@ -4,11 +4,27 @@ import { debug } from "../debug.js"; import { lazy } from "../utils.js"; import type { SqlParseError, SqlParseResult, SqlParser } from "./types.js"; -interface NodeSqlParserOptions { - getParserOptions?: (state: EditorState) => Option; +export interface ParserOption extends Option { + database: SupportedDialects; + /** + * If true, the parser will quote brackets in the SQL query which will satisfy the parser. + * This is useful if you want to interpolate variables in f-strings. + * + * @example + * ```sql + * SELECT {id} -> SELECT '{id}' + * ``` + * + * @experimental This is an experimental feature and may break parsing. + */ + ignoreBrackets?: boolean; } -interface NodeSqlParserResult extends SqlParseResult { +export interface NodeSqlParserOptions { + getParserOptions?: (state: EditorState) => ParserOption; +} + +export interface NodeSqlParserResult extends SqlParseResult { ast?: AST | AST[]; } @@ -34,6 +50,9 @@ export class NodeSqlParser implements SqlParser { private opts: NodeSqlParserOptions; private parser: Parser | null = null; + // Record the column number to the offset amount + private offsetRecord: Record = {}; + constructor(opts: NodeSqlParserOptions = {}) { this.opts = opts; } @@ -45,22 +64,29 @@ export class NodeSqlParser implements SqlParser { if (this.parser) { return this.parser; } - const { Parser } = await import("node-sql-parser"); + const module = await import("node-sql-parser"); + // Support for ESM and CJS + const { Parser } = module.default || module; this.parser = new Parser(); return this.parser; }); async parse(sql: string, opts: { state: EditorState }): Promise { + // Reset the offset map on each parse + this.offsetRecord = {}; + + const parserOptions = this.opts.getParserOptions?.(opts.state); + const sanitizedSql = await this.sanitizeSql(sql, parserOptions); + try { - const parserOptions = this.opts.getParserOptions?.(opts.state); const parser = await this.getParser(); // Check if this is DuckDB dialect and apply custom processing if (parserOptions?.database === "DuckDB") { - return this.parseWithDuckDBSupport(sql, parserOptions); + return this.parseWithDuckDBSupport(sanitizedSql, parserOptions); } - const ast = parser.astify(sql, parserOptions); + const ast = parser.astify(sanitizedSql, parserOptions); return { success: true, @@ -68,7 +94,7 @@ export class NodeSqlParser implements SqlParser { ast, }; } catch (error: unknown) { - const parseError = this.extractErrorInfo(error, sql); + const parseError = this.extractErrorInfo(error, sanitizedSql); return { success: false, errors: [parseError], @@ -76,8 +102,18 @@ export class NodeSqlParser implements SqlParser { } } + async sanitizeSql(sql: string, parserOptions?: ParserOption): Promise { + if (parserOptions?.ignoreBrackets) { + const { sql: replacedSql, offsetRecord } = replaceBracketsWithQuotes(sql); + this.offsetRecord = offsetRecord; + return replacedSql; + } + return sql; + } + /** - * Parse SQL with DuckDB-specific syntax support + * Parse SQL with DuckDB syntax support + * This is not robust, we catch main cases. */ private async parseWithDuckDBSupport( sql: string, @@ -85,35 +121,42 @@ export class NodeSqlParser implements SqlParser { ): Promise { const parser = await this.getParser(); - // If the query starts with "from", it's DuckDB-specific syntax - // Just return success without parsing to avoid errors - if (sql.trim().toLowerCase().startsWith("from")) { - debug("From syntax is not supported"); - return { - success: true, - errors: [], - }; + // Remove comments and normalize for pattern checking + const sqlToCheck = removeCommentsFromStart(sql).trimStart().toLowerCase(); + + // Handle unsupported DuckDB syntax patterns + if (sqlToCheck.startsWith("from") || sqlToCheck.includes("macro")) { + debug("Unsupported DuckDB syntax"); + return { success: true, errors: [] }; } - // Otherwise, try standard parsing with PostgreSQL dialect + let modifiedSql = sql; + // Postgres does not support `CREATE OR REPLACE` for tables + if (sqlToCheck.includes("create or replace table")) { + const offset = "create or replace table".length - "create table".length; + this.offsetRecord[sql.indexOf("create or replace table")] = -offset; + modifiedSql = sql.replace(/create or replace table/i, "create table"); + } + + // Try standard parsing with PostgreSQL dialect try { - const postgresOptions = { ...parserOptions, database: "PostgresQL" }; - const ast = parser.astify(sql, postgresOptions); - return { - success: true, - errors: [], - ast, - }; + const postgresOptions = { ...parserOptions, database: "PostgreSQL" }; + const ast = parser.astify(modifiedSql, postgresOptions); + return { success: true, errors: [], ast }; } catch (error) { + // Use the original sql since we manually apply the offset const parseError = this.extractErrorInfo(error, sql); - return { - success: false, - errors: [parseError], - }; + return { success: false, errors: [parseError] }; } } - private extractErrorInfo(error: unknown, _sql: string): SqlParseError { + /** + * @param error - The error object + * @param sql - The SQL string + * @param offset - The offset to add to the column position. Default is 0. + * @returns The parsed error information + */ + private extractErrorInfo(error: unknown, sql: string): SqlParseError { let line = 1; let column = 1; const message = (error as Error)?.message || "SQL parsing error"; @@ -140,10 +183,33 @@ export class NodeSqlParser implements SqlParser { } } + /** + * Add offset to the column position to get the correct position of the error + * SELECT {id} FRO users + * ^ error position should be here + * + * SELECT {id} FRO users + * ^ user sees this + * So in this case, we subtract the offset from the column position. + * + * If the error is before the brackets, we don't need to add the offset because it just increases the string length + * Column position will be the same as the user sees. + */ + for (const [position, offset] of Object.entries(this.offsetRecord)) { + if (column > parseInt(position, 10)) { + column -= offset; + } + } + + // Ensure we don't exceed the sql length + if (column > sql.length) { + column = sql.length; + } + return { message: this.cleanErrorMessage(message), line: Math.max(1, line), - column: Math.max(1, column), + column: column, severity: "error" as const, }; } @@ -167,10 +233,12 @@ export class NodeSqlParser implements SqlParser { * @param sql The SQL query to analyze * @returns Array of table names referenced in the query */ - async extractTableReferences(sql: string): Promise { + async extractTableReferences(sql: string, opts?: { state: EditorState }): Promise { + const parserOptions = opts ? this.opts.getParserOptions?.(opts.state) : undefined; + try { const parser = await this.getParser(); - const tableList = parser.tableList(sql); + const tableList = parser.tableList(sql, parserOptions); // Clean up table names - node-sql-parser returns format like "select::null::users" return tableList.map((table: string) => { const parts = table.split("::"); @@ -186,10 +254,12 @@ export class NodeSqlParser implements SqlParser { * @param sql The SQL query to analyze * @returns Array of column names referenced in the query */ - async extractColumnReferences(sql: string): Promise { + async extractColumnReferences(sql: string, opts?: { state: EditorState }): Promise { + const parserOptions = opts?.state ? this.opts.getParserOptions?.(opts.state) : undefined; + try { const parser = await this.getParser(); - const columnList = parser.columnList(sql); + const columnList = parser.columnList(sql, parserOptions); // Clean up column names - node-sql-parser returns format like "select::null::users" const cleanColumnList = columnList.map((column: string) => { @@ -202,3 +272,98 @@ export class NodeSqlParser implements SqlParser { } } } + +type CommentType = "--" | "/*"; + +function removeCommentsFromStart(sql: string, commentTypes: CommentType[] = ["/*", "--"]): string { + const regexPatterns: string[] = []; + + // Multi-line comments + if (commentTypes.includes("/*")) { + regexPatterns.push("/\\*[\\s\\S]*?\\*/"); + } + // Single-line comments + if (commentTypes.includes("--")) { + regexPatterns.push("--[^\\n]*"); + } + + if (regexPatterns.length === 0) return sql; + + const commentRegex = new RegExp(`^\\s*(${regexPatterns.join("|")})\\s*`, ""); + + // Keep removing comments from the start until no more are found + let result = sql; + let prevResult = ""; + + while (result !== prevResult) { + prevResult = result; + result = result.replace(commentRegex, ""); + } + + return result; +} + +const QUOTE_LENGTH = "''".length; + +/** + * Replaces unquoted curly bracket expressions (e.g., {id}) with quoted strings (e.g., '{id}'), + * ignoring brackets already inside single or double quotes. + * + * Returns the modified SQL and a record mapping the index of each replaced bracket to the + * number of characters added (for offset tracking). + * + * @example + * replaceBracketsWithQuotes("SELECT {id}, '{name}' FROM users"); + * // => { + * // sql: "SELECT '{id}', '{name}' FROM users", + * // offsetRecord: { 7: 2 } + * // } + */ +function replaceBracketsWithQuotes(sql: string): { + sql: string; + offsetRecord: Record; +} { + const offsetRecord: Record = {}; + + const replacedSql = sql.replace( + /("(?:[^"\\]|\\.)*")|('(?:[^'\\]|\\.)*')|(\{[^}]*\})/g, + (match, doubleQuoted, singleQuoted, bracket, offset) => { + // If it's a quoted string, return it as-is + if (doubleQuoted || singleQuoted) { + return match; + } + + // If it's a bracket, quote it and record the offset + if (bracket) { + offsetRecord[offset] = QUOTE_LENGTH; + return `'${bracket}'`; + } + + return match; + }, + ); + + return { sql: replacedSql, offsetRecord }; +} + +export const exportedForTesting = { replaceBracketsWithQuotes, removeCommentsFromStart }; + +/** + * https://github.com/taozhi8833998/node-sql-parser?tab=readme-ov-file#supported-database-sql-syntax + * While DuckDB is not supported in the library, we perform some special handling for it and treat it as PostgreSQL. + */ +export type SupportedDialects = + | "Athena" + | "BigQuery" + | "DB2" + | "Hive" + | "MariaDB" + | "MySQL" + | "PostgreSQL" + | "DuckDB" + | "Redshift" + | "Sqlite" + | "TransactSQL" + | "FlinkSQL" + | "Snowflake" + | "Noql"; diff --git a/src/sql/types.ts b/src/sql/types.ts index 03c857d..bbbf491 100644 --- a/src/sql/types.ts +++ b/src/sql/types.ts @@ -30,27 +30,29 @@ export interface SqlParser { /** * Parse a SQL statement and return the AST * @param sql - The SQL statement to parse - * @param opts - The options for the parser + * @param opts - The state of the editor * @returns The parsed AST */ parse(sql: string, opts: { state: EditorState }): Promise; /** * Validate a SQL statement and return any errors * @param sql - The SQL statement to validate - * @param opts - The options for the parser + * @param opts - The state of the editor * @returns An array of errors */ validateSql(sql: string, opts: { state: EditorState }): Promise; /** * Extract table references from a SQL query * @param sql - The SQL query to analyze + * @param opts - The state of the editor * @returns Array of table names referenced in the query */ - extractTableReferences(sql: string): Promise; + extractTableReferences(sql: string, opts?: { state: EditorState }): Promise; /** * Extract column references from a SQL query * @param sql - The SQL query to analyze + * @param opts - The state of the editor * @returns Array of column names referenced in the query */ - extractColumnReferences(sql: string): Promise; + extractColumnReferences(sql: string, opts?: { state: EditorState }): Promise; } diff --git a/vite.config.ts b/vite.config.ts index a8a0b35..93ee2e8 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,9 +1,9 @@ +import { playwright } from "@vitest/browser-playwright"; import { defineConfig } from "vitest/config"; export default defineConfig({ root: process.env.VITEST ? "." : "demo", test: { - environment: "jsdom", watch: false, coverage: { provider: "v8", @@ -11,6 +11,32 @@ export default defineConfig({ include: ["src/**/*.ts"], exclude: ["src/**/*.test.ts", "src/**/__tests__/**", "src/debug.ts"], }, + projects: [ + { + test: { + environment: "jsdom", + exclude: ["src/**/browser_tests/**/*.test.ts"], + include: ["src/**/*.test.ts", "src/**/__tests__/**/*.ts",], + } + }, + { + test: { + name: "browser", + browser: { + enabled: true, + provider: playwright(), + // https://vitest.dev/guide/browser/playwright + instances: [ + { browser: 'chromium' }, + ], + ui: false, + headless: true, + }, + include: ["src/**/browser_tests/**/*.test.ts"], + testTimeout: 5000, + }, + } + ] }, base: "/codemirror-sql/", });