diff --git a/README.md b/README.md index 9de1b04..a9ab5b0 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,13 @@ # Token-Oriented Object Notation (TOON) -[![CI](https://github.com/johannschopplich/toon/actions/workflows/ci.yml/badge.svg)](https://github.com/johannschopplich/toon/actions) +[![CI](https://github.com/toon-format/toon/actions/workflows/ci.yml/badge.svg)](https://github.com/toon-format/toon/actions) [![npm version](https://img.shields.io/npm/v/@toon-format/toon.svg)](https://www.npmjs.com/package/@toon-format/toon) -[![SPEC v1.3](https://img.shields.io/badge/spec-v1.3-lightgrey)](./SPEC.md) +[![SPEC v1.3](https://img.shields.io/badge/spec-v1.3-lightgrey)](https://github.com/toon-format/spec) [![npm downloads (total)](https://img.shields.io/npm/dt/@toon-format/toon.svg)](https://www.npmjs.com/package/@toon-format/toon) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) -**Token-Oriented Object Notation** is a compact, human-readable format designed for passing structured data to Large Language Models with significantly reduced token usage. It's intended for LLM input, not output. +**Token-Oriented Object Notation** is a compact, human-readable serialization format designed for passing structured data to Large Language Models with significantly reduced token usage. It's intended for LLM input, not output. TOON's sweet spot is **uniform arrays of objects** – multiple fields per row, same structure across items. It borrows YAML's indentation-based structure for nested objects and CSV's tabular format for uniform data rows, then optimizes both for token efficiency in LLM contexts. For deeply nested or non-uniform data, JSON may be more efficient. @@ -20,7 +20,7 @@ TOON's sweet spot is **uniform arrays of objects** – multiple fields per row, - [Why TOON?](#why-toon) - [Key Features](#key-features) - [Benchmarks](#benchmarks) -- [📋 Full Specification](./SPEC.md) +- [📋 Full Specification](https://github.com/toon-format/spec/blob/main/SPEC.md) - [Installation & Quick Start](#installation--quick-start) - [CLI](#cli) - [Format Overview](#format-overview) @@ -521,7 +521,7 @@ npx @toon-format/cli data.toon --no-strict -o output.json ## Format Overview > [!NOTE] -> For precise formatting rules and implementation details, see the [SPEC.md](./SPEC.md). +> For precise formatting rules and implementation details, see the [full specification](https://github.com/toon-format/spec). ### Objects @@ -980,7 +980,7 @@ Task: Return only users with role "user" as TOON. Use the same header. Set [N] t ## Other Implementations > [!NOTE] -> When implementing TOON in other languages, please follow the [SPEC.md](./SPEC.md) (currently v1.3) to ensure compatibility across implementations. The [TypeScript test suite](./packages/toon/test) provides comprehensive examples of encoding and decoding behavior that can serve as a reference implementation. +> When implementing TOON in other languages, please follow the [specification](https://github.com/toon-format/spec/blob/main/SPEC.md) (currently v1.3) to ensure compatibility across implementations. The [conformance tests](https://github.com/toon-format/spec/tree/main/tests) provide language-agnostic test fixtures that validate implementations across any language. - **.NET:** [ToonSharp](https://github.com/0xZunia/ToonSharp) - **Crystal:** [toon-crystal](https://github.com/mamantoha/toon-crystal) diff --git a/benchmarks/package.json b/benchmarks/package.json index 44f3fb2..17ff9ad 100644 --- a/benchmarks/package.json +++ b/benchmarks/package.json @@ -8,21 +8,21 @@ "fetch:github-repos": "tsx scripts/fetch-github-repos.ts" }, "devDependencies": { - "@ai-sdk/anthropic": "^2.0.37", - "@ai-sdk/google": "^2.0.23", - "@ai-sdk/openai": "^2.0.53", + "@ai-sdk/anthropic": "^2.0.40", + "@ai-sdk/google": "^2.0.26", + "@ai-sdk/openai": "^2.0.59", "@ai-sdk/provider": "^2.0.0", - "@ai-sdk/xai": "^2.0.28", + "@ai-sdk/xai": "^2.0.30", "@clack/prompts": "^0.11.0", "@faker-js/faker": "^10.1.0", - "ai": "^5.0.80", + "ai": "^5.0.86", "csv-stringify": "^6.6.0", "fast-xml-parser": "^5.3.0", "gpt-tokenizer": "^3.2.0", - "ofetch": "^1.4.1", + "ofetch": "^1.5.1", "p-map": "^7.0.3", "p-queue": "^9.0.0", - "unstorage": "^1.17.1", + "unstorage": "^1.17.2", "yaml": "^2.8.1" } } diff --git a/package.json b/package.json index 1e13123..525e1d4 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "type": "module", "version": "0.7.0", "private": true, - "packageManager": "pnpm@10.19.0", + "packageManager": "pnpm@10.20.0", "scripts": { "build": "pnpm -r --filter=./packages/** run build", "automd": "automd", @@ -14,14 +14,14 @@ "release": "bumpp -r" }, "devDependencies": { - "@antfu/eslint-config": "^6.1.0", - "@types/node": "^24.9.1", + "@antfu/eslint-config": "^6.2.0", + "@types/node": "^24.9.2", "automd": "^0.4.2", "bumpp": "^10.3.1", - "eslint": "^9.38.0", - "tsdown": "^0.15.10", + "eslint": "^9.39.0", + "tsdown": "^0.15.12", "tsx": "^4.20.6", "typescript": "^5.9.3", - "vitest": "^4.0.3" + "vitest": "^4.0.6" } } diff --git a/packages/cli/package.json b/packages/cli/package.json index c87fa6f..4e40c8b 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -2,17 +2,17 @@ "name": "@toon-format/cli", "type": "module", "version": "0.7.0", - "packageManager": "pnpm@10.19.0", - "description": "CLI for encoding and decoding Token-Oriented Object Notation (TOON)", + "packageManager": "pnpm@10.20.0", + "description": "CLI for JSON ↔ TOON conversion using @toon-format/toon", "author": "Johann Schopplich ", "license": "MIT", "homepage": "https://toonformat.dev", "repository": { "type": "git", - "url": "git+https://github.com/johannschopplich/toon.git" + "url": "git+https://github.com/toon-format/toon.git" }, "bugs": { - "url": "https://github.com/johannschopplich/toon/issues" + "url": "https://github.com/toon-format/toon/issues" }, "sideEffects": false, "exports": { diff --git a/packages/toon/package.json b/packages/toon/package.json index 138aa14..b039236 100644 --- a/packages/toon/package.json +++ b/packages/toon/package.json @@ -2,18 +2,26 @@ "name": "@toon-format/toon", "type": "module", "version": "0.7.0", - "packageManager": "pnpm@10.19.0", + "packageManager": "pnpm@10.20.0", "description": "Token-Oriented Object Notation (TOON) – a token-efficient JSON alternative for LLM prompts", "author": "Johann Schopplich ", "license": "MIT", "homepage": "https://toonformat.dev", "repository": { "type": "git", - "url": "git+https://github.com/johannschopplich/toon.git" + "url": "git+https://github.com/toon-format/toon.git" }, "bugs": { - "url": "https://github.com/johannschopplich/toon/issues" + "url": "https://github.com/toon-format/toon/issues" }, + "keywords": [ + "toon", + "format", + "specification", + "llm", + "token-efficiency", + "data-format" + ], "sideEffects": false, "exports": { ".": { @@ -28,5 +36,8 @@ "scripts": { "build": "tsdown", "test": "vitest" + }, + "devDependencies": { + "@toon-format/spec": "^1.3.0" } } diff --git a/packages/toon/test/decode.test.ts b/packages/toon/test/decode.test.ts index a611766..e5ff0e5 100644 --- a/packages/toon/test/decode.test.ts +++ b/packages/toon/test/decode.test.ts @@ -1,686 +1,42 @@ +import type { Fixtures } from './types' +import arraysNested from '@toon-format/spec/tests/fixtures/decode/arrays-nested.json' +import arraysPrimitive from '@toon-format/spec/tests/fixtures/decode/arrays-primitive.json' +import arraysTabular from '@toon-format/spec/tests/fixtures/decode/arrays-tabular.json' +import blankLines from '@toon-format/spec/tests/fixtures/decode/blank-lines.json' +import delimiters from '@toon-format/spec/tests/fixtures/decode/delimiters.json' +import indentationErrors from '@toon-format/spec/tests/fixtures/decode/indentation-errors.json' +import objects from '@toon-format/spec/tests/fixtures/decode/objects.json' +import primitives from '@toon-format/spec/tests/fixtures/decode/primitives.json' +import validationErrors from '@toon-format/spec/tests/fixtures/decode/validation-errors.json' import { describe, expect, it } from 'vitest' import { decode } from '../src/index' -describe('primitives', () => { - it('decodes safe unquoted strings', () => { - expect(decode('hello')).toBe('hello') - expect(decode('Ada_99')).toBe('Ada_99') - }) +const fixtureFiles = [ + primitives, + objects, + arraysPrimitive, + arraysTabular, + arraysNested, + delimiters, + validationErrors, + indentationErrors, + blankLines, +] as Fixtures[] - it('decodes quoted strings and unescapes control characters', () => { - expect(decode('""')).toBe('') - expect(decode('"line1\\nline2"')).toBe('line1\nline2') - expect(decode('"tab\\there"')).toBe('tab\there') - expect(decode('"return\\rcarriage"')).toBe('return\rcarriage') - expect(decode('"C:\\\\Users\\\\path"')).toBe('C:\\Users\\path') - expect(decode('"say \\"hello\\""')).toBe('say "hello"') - }) - - it('decodes unicode and emoji', () => { - expect(decode('café')).toBe('café') - expect(decode('你好')).toBe('你好') - expect(decode('🚀')).toBe('🚀') - expect(decode('hello 👋 world')).toBe('hello 👋 world') - }) - - it('decodes numbers, booleans and null', () => { - expect(decode('42')).toBe(42) - expect(decode('3.14')).toBe(3.14) - expect(decode('-7')).toBe(-7) - expect(decode('true')).toBe(true) - expect(decode('false')).toBe(false) - expect(decode('null')).toBe(null) - }) - - it('treats unquoted invalid numeric formats as strings', () => { - expect(decode('05')).toBe('05') - expect(decode('007')).toBe('007') - expect(decode('0123')).toBe('0123') - expect(decode('a: 05')).toEqual({ a: '05' }) - expect(decode('nums[3]: 05,007,0123')).toEqual({ nums: ['05', '007', '0123'] }) - }) - - it('respects ambiguity quoting (quoted primitives remain strings)', () => { - expect(decode('"true"')).toBe('true') - expect(decode('"false"')).toBe('false') - expect(decode('"null"')).toBe('null') - expect(decode('"42"')).toBe('42') - expect(decode('"-3.14"')).toBe('-3.14') - expect(decode('"1e-6"')).toBe('1e-6') - expect(decode('"05"')).toBe('05') - }) -}) - -describe('objects (simple)', () => { - it('parses objects with primitive values', () => { - const toon = 'id: 123\nname: Ada\nactive: true' - expect(decode(toon)).toEqual({ id: 123, name: 'Ada', active: true }) - }) - - it('parses null values in objects', () => { - const toon = 'id: 123\nvalue: null' - expect(decode(toon)).toEqual({ id: 123, value: null }) - }) - - it('parses empty nested object header', () => { - expect(decode('user:')).toEqual({ user: {} }) - }) - - it('parses quoted object values with special characters and escapes', () => { - expect(decode('note: "a:b"')).toEqual({ note: 'a:b' }) - expect(decode('note: "a,b"')).toEqual({ note: 'a,b' }) - expect(decode('text: "line1\\nline2"')).toEqual({ text: 'line1\nline2' }) - expect(decode('text: "say \\"hello\\""')).toEqual({ text: 'say "hello"' }) - expect(decode('text: " padded "')).toEqual({ text: ' padded ' }) - expect(decode('text: " "')).toEqual({ text: ' ' }) - expect(decode('v: "true"')).toEqual({ v: 'true' }) - expect(decode('v: "42"')).toEqual({ v: '42' }) - expect(decode('v: "-7.5"')).toEqual({ v: '-7.5' }) - }) -}) - -describe('objects (keys)', () => { - it('parses quoted keys with special characters and escapes', () => { - expect(decode('"order:id": 7')).toEqual({ 'order:id': 7 }) - expect(decode('"[index]": 5')).toEqual({ '[index]': 5 }) - expect(decode('"{key}": 5')).toEqual({ '{key}': 5 }) - expect(decode('"a,b": 1')).toEqual({ 'a,b': 1 }) - expect(decode('"full name": Ada')).toEqual({ 'full name': 'Ada' }) - expect(decode('"-lead": 1')).toEqual({ '-lead': 1 }) - expect(decode('" a ": 1')).toEqual({ ' a ': 1 }) - expect(decode('"123": x')).toEqual({ 123: 'x' }) - expect(decode('"": 1')).toEqual({ '': 1 }) - }) - - it('parses dotted keys as identifiers', () => { - expect(decode('user.name: Ada')).toEqual({ 'user.name': 'Ada' }) - expect(decode('_private: 1')).toEqual({ _private: 1 }) - expect(decode('user_name: 1')).toEqual({ user_name: 1 }) - }) - - it('unescapes control characters and quotes in keys', () => { - expect(decode('"line\\nbreak": 1')).toEqual({ 'line\nbreak': 1 }) - expect(decode('"tab\\there": 2')).toEqual({ 'tab\there': 2 }) - expect(decode('"he said \\"hi\\"": 1')).toEqual({ 'he said "hi"': 1 }) - }) -}) - -describe('nested objects', () => { - it('parses deeply nested objects with indentation', () => { - const toon = 'a:\n b:\n c: deep' - expect(decode(toon)).toEqual({ a: { b: { c: 'deep' } } }) - }) -}) - -describe('arrays of primitives', () => { - it('parses string arrays inline', () => { - const toon = 'tags[3]: reading,gaming,coding' - expect(decode(toon)).toEqual({ tags: ['reading', 'gaming', 'coding'] }) - }) - - it('parses number arrays inline', () => { - const toon = 'nums[3]: 1,2,3' - expect(decode(toon)).toEqual({ nums: [1, 2, 3] }) - }) - - it('parses mixed primitive arrays inline', () => { - const toon = 'data[4]: x,y,true,10' - expect(decode(toon)).toEqual({ data: ['x', 'y', true, 10] }) - }) - - it('parses empty arrays', () => { - expect(decode('items[0]:')).toEqual({ items: [] }) - }) - - it('parses quoted strings in arrays including empty and whitespace-only', () => { - expect(decode('items[1]: ""')).toEqual({ items: [''] }) - expect(decode('items[3]: a,"",b')).toEqual({ items: ['a', '', 'b'] }) - expect(decode('items[2]: " "," "')).toEqual({ items: [' ', ' '] }) - }) - - it('parses strings with delimiters and structural tokens in arrays', () => { - expect(decode('items[3]: a,"b,c","d:e"')).toEqual({ items: ['a', 'b,c', 'd:e'] }) - expect(decode('items[4]: x,"true","42","-3.14"')).toEqual({ items: ['x', 'true', '42', '-3.14'] }) - expect(decode('items[3]: "[5]","- item","{key}"')).toEqual({ items: ['[5]', '- item', '{key}'] }) - }) -}) - -describe('arrays of objects (tabular and list items)', () => { - it('parses tabular arrays of uniform objects', () => { - const toon = 'items[2]{sku,qty,price}:\n A1,2,9.99\n B2,1,14.5' - expect(decode(toon)).toEqual({ - items: [ - { sku: 'A1', qty: 2, price: 9.99 }, - { sku: 'B2', qty: 1, price: 14.5 }, - ], - }) - }) - - it('parses nulls and quoted values in tabular rows', () => { - const toon = 'items[2]{id,value}:\n 1,null\n 2,"test"' - expect(decode(toon)).toEqual({ - items: [ - { id: 1, value: null }, - { id: 2, value: 'test' }, - ], - }) - }) - - it('parses quoted header keys in tabular arrays', () => { - const toon = 'items[2]{"order:id","full name"}:\n 1,Ada\n 2,Bob' - expect(decode(toon)).toEqual({ - items: [ - { 'order:id': 1, 'full name': 'Ada' }, - { 'order:id': 2, 'full name': 'Bob' }, - ], - }) - }) - - it('parses list arrays for non-uniform objects', () => { - const toon - = 'items[2]:\n' - + ' - id: 1\n' - + ' name: First\n' - + ' - id: 2\n' - + ' name: Second\n' - + ' extra: true' - expect(decode(toon)).toEqual({ - items: [ - { id: 1, name: 'First' }, - { id: 2, name: 'Second', extra: true }, - ], - }) - }) - - it('parses objects with nested values inside list items', () => { - const toon - = 'items[1]:\n' - + ' - id: 1\n' - + ' nested:\n' - + ' x: 1' - expect(decode(toon)).toEqual({ - items: [{ id: 1, nested: { x: 1 } }], - }) - }) - - it('parses nested tabular arrays as first field on hyphen line', () => { - const toon - = 'items[1]:\n' - + ' - users[2]{id,name}:\n' - + ' 1,Ada\n' - + ' 2,Bob\n' - + ' status: active' - expect(decode(toon)).toEqual({ - items: [ - { - users: [ - { id: 1, name: 'Ada' }, - { id: 2, name: 'Bob' }, - ], - status: 'active', - }, - ], - }) - }) - - it('parses objects containing arrays (including empty arrays) in list format', () => { - const toon - = 'items[1]:\n' - + ' - name: test\n' - + ' data[0]:' - expect(decode(toon)).toEqual({ - items: [{ name: 'test', data: [] }], - }) - }) - - it('parses arrays of arrays within objects', () => { - const toon - = 'items[1]:\n' - + ' - matrix[2]:\n' - + ' - [2]: 1,2\n' - + ' - [2]: 3,4\n' - + ' name: grid' - expect(decode(toon)).toEqual({ - items: [{ matrix: [[1, 2], [3, 4]], name: 'grid' }], - }) - }) -}) - -describe('arrays of arrays (primitives only)', () => { - it('parses nested arrays of primitives', () => { - const toon = 'pairs[2]:\n - [2]: a,b\n - [2]: c,d' - expect(decode(toon)).toEqual({ pairs: [['a', 'b'], ['c', 'd']] }) - }) - - it('parses quoted strings and mixed lengths in nested arrays', () => { - const toon = 'pairs[2]:\n - [2]: a,b\n - [3]: "c,d","e:f","true"' - expect(decode(toon)).toEqual({ pairs: [['a', 'b'], ['c,d', 'e:f', 'true']] }) - }) - - it('parses empty inner arrays', () => { - const toon = 'pairs[2]:\n - [0]:\n - [0]:' - expect(decode(toon)).toEqual({ pairs: [[], []] }) - }) - - it('parses mixed-length inner arrays', () => { - const toon = 'pairs[2]:\n - [1]: 1\n - [2]: 2,3' - expect(decode(toon)).toEqual({ pairs: [[1], [2, 3]] }) - }) -}) - -describe('root arrays', () => { - it('parses root arrays of primitives (inline)', () => { - const toon = '[5]: x,y,"true",true,10' - expect(decode(toon)).toEqual(['x', 'y', 'true', true, 10]) - }) - - it('parses root arrays of uniform objects in tabular format', () => { - const toon = '[2]{id}:\n 1\n 2' - expect(decode(toon)).toEqual([{ id: 1 }, { id: 2 }]) - }) - - it('parses root arrays of non-uniform objects in list format', () => { - const toon = '[2]:\n - id: 1\n - id: 2\n name: Ada' - expect(decode(toon)).toEqual([{ id: 1 }, { id: 2, name: 'Ada' }]) - }) - - it('parses empty root arrays', () => { - expect(decode('[0]:')).toEqual([]) - }) - - it('parses root arrays of arrays', () => { - const toon = '[2]:\n - [2]: 1,2\n - [0]:' - expect(decode(toon)).toEqual([[1, 2], []]) - }) -}) - -describe('complex structures', () => { - it('parses mixed objects with arrays and nested objects', () => { - const toon - = 'user:\n' - + ' id: 123\n' - + ' name: Ada\n' - + ' tags[2]: reading,gaming\n' - + ' active: true\n' - + ' prefs[0]:' - expect(decode(toon)).toEqual({ - user: { - id: 123, - name: 'Ada', - tags: ['reading', 'gaming'], - active: true, - prefs: [], - }, - }) - }) -}) - -describe('mixed arrays', () => { - it('parses arrays mixing primitives, objects and strings (list format)', () => { - const toon - = 'items[3]:\n' - + ' - 1\n' - + ' - a: 1\n' - + ' - text' - expect(decode(toon)).toEqual({ items: [1, { a: 1 }, 'text'] }) - }) - - it('parses arrays mixing objects and arrays', () => { - const toon - = 'items[2]:\n' - + ' - a: 1\n' - + ' - [2]: 1,2' - expect(decode(toon)).toEqual({ items: [{ a: 1 }, [1, 2]] }) - }) -}) - -describe('delimiter options', () => { - describe('basic delimiter usage', () => { - it.each([ - { delimiter: '\t' as const, name: 'tab', header: '[3\t]', joined: 'reading\tgaming\tcoding' }, - { delimiter: '|' as const, name: 'pipe', header: '[3|]', joined: 'reading|gaming|coding' }, - { delimiter: ',' as const, name: 'comma', header: '[3]', joined: 'reading,gaming,coding' }, - ])('parses primitive arrays with $name delimiter', ({ header, joined }) => { - const toon = `tags${header}: ${joined}` - expect(decode(toon)).toEqual({ tags: ['reading', 'gaming', 'coding'] }) - }) - - it.each([ - { delimiter: '\t' as const, name: 'tab', header: '[2\t]{sku\tqty\tprice}', rows: ['A1\t2\t9.99', 'B2\t1\t14.5'] }, - { delimiter: '|' as const, name: 'pipe', header: '[2|]{sku|qty|price}', rows: ['A1|2|9.99', 'B2|1|14.5'] }, - ])('parses tabular arrays with $name delimiter', ({ header, rows }) => { - const toon = `items${header}:\n ${rows[0]}\n ${rows[1]}` - expect(decode(toon)).toEqual({ - items: [ - { sku: 'A1', qty: 2, price: 9.99 }, - { sku: 'B2', qty: 1, price: 14.5 }, - ], +// Run all fixture-based tests +for (const fixtures of fixtureFiles) { + describe(fixtures.description, () => { + for (const test of fixtures.tests) { + it(test.name, () => { + if (test.shouldError) { + expect(() => decode(test.input as string, test.options)) + .toThrow() + } + else { + const result = decode(test.input as string, test.options) + expect(result).toEqual(test.expected) + } }) - }) - - it.each([ - { header: '[2\t]', inner: '[2\t]', a: 'a\tb', b: 'c\td' }, - { header: '[2|]', inner: '[2|]', a: 'a|b', b: 'c|d' }, - ])('parses nested arrays with custom delimiters', ({ header, inner, a, b }) => { - const toon = `pairs${header}:\n - ${inner}: ${a}\n - ${inner}: ${b}` - expect(decode(toon)).toEqual({ pairs: [['a', 'b'], ['c', 'd']] }) - }) - - it.each([ - { parent: '[1\t]', nested: '[3]', values: 'a,b,c' }, - { parent: '[1|]', nested: '[3]', values: 'a,b,c' }, - ])('nested arrays inside list items default to comma delimiter', ({ parent, nested, values }) => { - const toon = `items${parent}:\n - tags${nested}: ${values}` - expect(decode(toon)).toEqual({ items: [{ tags: ['a', 'b', 'c'] }] }) - }) - - it.each([ - { header: '[3\t]', joined: 'x\ty\tz' }, - { header: '[3|]', joined: 'x|y|z' }, - ])('parses root arrays of primitives with custom delimiters', ({ header, joined }) => { - const toon = `${header}: ${joined}` - expect(decode(toon)).toEqual(['x', 'y', 'z']) - }) - - it.each([ - { header: '[2\t]{id}', rows: ['1', '2'] }, - { header: '[2|]{id}', rows: ['1', '2'] }, - ])('parses root arrays of objects with custom delimiters', ({ header, rows }) => { - const toon = `${header}:\n ${rows[0]}\n ${rows[1]}` - expect(decode(toon)).toEqual([{ id: 1 }, { id: 2 }]) - }) + } }) - - describe('delimiter-aware quoting', () => { - it.each([ - { header: '[3\t]', joined: 'a\t"b\\tc"\td', expected: ['a', 'b\tc', 'd'] }, - { header: '[3|]', joined: 'a|"b|c"|d', expected: ['a', 'b|c', 'd'] }, - ])('parses values containing the active delimiter when quoted', ({ header, joined, expected }) => { - const toon = `items${header}: ${joined}` - expect(decode(toon)).toEqual({ items: expected }) - }) - - it.each([ - { header: '[2\t]', joined: 'a,b\tc,d' }, - { header: '[2|]', joined: 'a,b|c,d' }, - ])('does not split on commas when using non-comma delimiter', ({ header, joined }) => { - const toon = `items${header}: ${joined}` - expect(decode(toon)).toEqual({ items: ['a,b', 'c,d'] }) - }) - - it('parses tabular values containing the active delimiter correctly', () => { - const comma = 'items[2]{id,note}:\n 1,"a,b"\n 2,"c,d"' - expect(decode(comma)).toEqual({ items: [{ id: 1, note: 'a,b' }, { id: 2, note: 'c,d' }] }) - - const tab = 'items[2\t]{id\tnote}:\n 1\ta,b\n 2\tc,d' - expect(decode(tab)).toEqual({ items: [{ id: 1, note: 'a,b' }, { id: 2, note: 'c,d' }] }) - }) - - it('does not require quoting commas in object values when using non-comma delimiter elsewhere', () => { - expect(decode('note: a,b')).toEqual({ note: 'a,b' }) - }) - - it('parses nested array values containing the active delimiter', () => { - expect(decode('pairs[1|]:\n - [2|]: a|"b|c"')).toEqual({ pairs: [['a', 'b|c']] }) - expect(decode('pairs[1\t]:\n - [2\t]: a\t"b\\tc"')).toEqual({ pairs: [['a', 'b\tc']] }) - }) - }) - - describe('delimiter-independent quoting rules', () => { - it('preserves quoted ambiguity regardless of delimiter', () => { - expect(decode('items[3|]: "true"|"42"|"-3.14"')).toEqual({ items: ['true', '42', '-3.14'] }) - expect(decode('items[3\t]: "true"\t"42"\t"-3.14"')).toEqual({ items: ['true', '42', '-3.14'] }) - }) - - it('parses structural-looking strings when quoted', () => { - expect(decode('items[3|]: "[5]"|"{key}"|"- item"')).toEqual({ items: ['[5]', '{key}', '- item'] }) - expect(decode('items[3\t]: "[5]"\t"{key}"\t"- item"')).toEqual({ items: ['[5]', '{key}', '- item'] }) - }) - - it('parses tabular headers with keys containing the active delimiter', () => { - const toon = 'items[2|]{"a|b"}:\n 1\n 2' - expect(decode(toon)).toEqual({ items: [{ 'a|b': 1 }, { 'a|b': 2 }] }) - }) - }) -}) - -describe('length marker option', () => { - it('accepts length marker on primitive arrays', () => { - expect(decode('tags[#3]: reading,gaming,coding')).toEqual({ tags: ['reading', 'gaming', 'coding'] }) - }) - - it('accepts length marker on empty arrays', () => { - expect(decode('items[#0]:')).toEqual({ items: [] }) - }) - - it('accepts length marker on tabular arrays', () => { - const toon = 'items[#2]{sku,qty,price}:\n A1,2,9.99\n B2,1,14.5' - expect(decode(toon)).toEqual({ - items: [ - { sku: 'A1', qty: 2, price: 9.99 }, - { sku: 'B2', qty: 1, price: 14.5 }, - ], - }) - }) - - it('accepts length marker on nested arrays', () => { - const toon = 'pairs[#2]:\n - [#2]: a,b\n - [#2]: c,d' - expect(decode(toon)).toEqual({ pairs: [['a', 'b'], ['c', 'd']] }) - }) - - it('works with custom delimiters and length marker', () => { - expect(decode('tags[#3|]: reading|gaming|coding')).toEqual({ tags: ['reading', 'gaming', 'coding'] }) - }) -}) - -describe('validation and error handling', () => { - describe('length and structure errors', () => { - it('throws on array length mismatch (inline primitives)', () => { - const toon = 'tags[2]: a,b,c' - expect(() => decode(toon)).toThrow() - }) - - it('throws on array length mismatch (list format)', () => { - const toon = 'items[1]:\n - 1\n - 2' - expect(() => decode(toon)).toThrow() - }) - - it('throws when tabular row value count does not match header field count', () => { - const toon = 'items[2]{id,name}:\n 1,Ada\n 2' - expect(() => decode(toon)).toThrow() - }) - - it('throws when tabular row count does not match header length', () => { - const toon = '[1]{id}:\n 1\n 2' - expect(() => decode(toon)).toThrow() - }) - - it('throws on invalid escape sequences', () => { - expect(() => decode('"a\\x"')).toThrow() - expect(() => decode('"unterminated')).toThrow() - }) - - it('throws on missing colon in key-value context', () => { - expect(() => decode('a:\n user')).toThrow() - }) - - it('throws on delimiter mismatch', () => { - const toon = 'items[2\t]{a\tb}:\n 1,2\n 3,4' - expect(() => decode(toon)).toThrow() - }) - }) - - describe('strict mode: indentation validation', () => { - describe('non-multiple indentation errors', () => { - it('throws when object field has non-multiple indentation', () => { - const toon = 'a:\n b: 1' // 3 spaces with indent=2 - expect(() => decode(toon)).toThrow(/indentation/i) - expect(() => decode(toon)).toThrow(/exact multiple/i) - }) - - it('throws when list item has non-multiple indentation', () => { - const toon = 'items[2]:\n - id: 1\n - id: 2' // 3 spaces - expect(() => decode(toon)).toThrow(/indentation/i) - }) - - it('throws with custom indent size when non-multiple', () => { - const toon = 'a:\n b: 1' // 3 spaces with indent=4 - expect(() => decode(toon, { indent: 4 })).toThrow(/exact multiple of 4/i) - }) - - it('accepts correct indentation with custom indent size', () => { - const toon = 'a:\n b: 1' // 4 spaces with indent=4 - expect(decode(toon, { indent: 4 })).toEqual({ a: { b: 1 } }) - }) - }) - - describe('tab character errors', () => { - it('throws when tab character used in indentation', () => { - const toon = 'a:\n\tb: 1' - expect(() => decode(toon)).toThrow(/tab/i) - }) - - it('throws when mixed tabs and spaces in indentation', () => { - const toon = 'a:\n \tb: 1' // space + tab - expect(() => decode(toon)).toThrow(/tab/i) - }) - - it('throws when tab at start of line', () => { - const toon = '\ta: 1' - expect(() => decode(toon)).toThrow(/tab/i) - }) - }) - - describe('tabs in quoted strings are allowed', () => { - it('accepts tabs in quoted string values', () => { - const toon = 'text: "hello\tworld"' - expect(decode(toon)).toEqual({ text: 'hello\tworld' }) - }) - - it('accepts tabs in quoted keys', () => { - const toon = '"key\ttab": value' - expect(decode(toon)).toEqual({ 'key\ttab': 'value' }) - }) - - it('accepts tabs in quoted array elements', () => { - const toon = 'items[2]: "a\tb","c\td"' - expect(decode(toon)).toEqual({ items: ['a\tb', 'c\td'] }) - }) - }) - - describe('non-strict mode', () => { - it('accepts non-multiple indentation when strict=false', () => { - const toon = 'a:\n b: 1' // 3 spaces with indent=2 - expect(decode(toon, { strict: false })).toEqual({ a: { b: 1 } }) - }) - - it('accepts tab indentation when strict=false', () => { - const toon = 'a:\n\tb: 1' - // Tabs are ignored in indentation counting, so depth=0, "b: 1" at root - expect(decode(toon, { strict: false })).toEqual({ a: {}, b: 1 }) - }) - - it('accepts deeply nested non-multiples when strict=false', () => { - const toon = 'a:\n b:\n c: 1' // 3 and 5 spaces - expect(decode(toon, { strict: false })).toEqual({ a: { b: { c: 1 } } }) - }) - }) - - describe('edge cases', () => { - it('empty lines do not trigger validation errors', () => { - const toon = 'a: 1\n\nb: 2' - expect(decode(toon)).toEqual({ a: 1, b: 2 }) - }) - - it('root-level content (0 indentation) is always valid', () => { - const toon = 'a: 1\nb: 2\nc: 3' - expect(decode(toon)).toEqual({ a: 1, b: 2, c: 3 }) - }) - - it('lines with only spaces are not validated if empty', () => { - const toon = 'a: 1\n \nb: 2' - expect(decode(toon)).toEqual({ a: 1, b: 2 }) - }) - }) - }) - - describe('strict mode: blank lines in arrays', () => { - describe('errors on blank lines inside arrays', () => { - it('throws on blank line inside list array', () => { - const teon = 'items[3]:\n - a\n\n - b\n - c' - expect(() => decode(teon)).toThrow(/blank line/i) - expect(() => decode(teon)).toThrow(/list array/i) - }) - - it('throws on blank line inside tabular array', () => { - const teon = 'items[2]{id}:\n 1\n\n 2' - expect(() => decode(teon)).toThrow(/blank line/i) - expect(() => decode(teon)).toThrow(/tabular array/i) - }) - - it('throws on multiple blank lines inside array', () => { - const teon = 'items[2]:\n - a\n\n\n - b' - expect(() => decode(teon)).toThrow(/blank line/i) - }) - - it('throws on blank line with spaces inside array', () => { - const teon = 'items[2]:\n - a\n \n - b' - expect(() => decode(teon)).toThrow(/blank line/i) - }) - - it('throws on blank line in nested list array', () => { - const teon = 'outer[2]:\n - inner[2]:\n - a\n\n - b\n - x' - expect(() => decode(teon)).toThrow(/blank line/i) - }) - }) - - describe('accepts blank lines outside arrays', () => { - it('accepts blank line between root-level fields', () => { - const teon = 'a: 1\n\nb: 2' - expect(decode(teon)).toEqual({ a: 1, b: 2 }) - }) - - it('accepts trailing newline at end of file', () => { - const teon = 'a: 1\n' - expect(decode(teon)).toEqual({ a: 1 }) - }) - - it('accepts multiple trailing newlines', () => { - const teon = 'a: 1\n\n\n' - expect(decode(teon)).toEqual({ a: 1 }) - }) - - it('accepts blank line after array ends', () => { - const teon = 'items[1]:\n - a\n\nb: 2' - expect(decode(teon)).toEqual({ items: ['a'], b: 2 }) - }) - - it('accepts blank line between nested object fields', () => { - const teon = 'a:\n b: 1\n\n c: 2' - expect(decode(teon)).toEqual({ a: { b: 1, c: 2 } }) - }) - }) - - describe('non-strict mode: ignores blank lines', () => { - it('ignores blank lines inside list array', () => { - const teon = 'items[3]:\n - a\n\n - b\n - c' - expect(decode(teon, { strict: false })).toEqual({ items: ['a', 'b', 'c'] }) - }) - - it('ignores blank lines inside tabular array', () => { - const teon = 'items[2]{id,name}:\n 1,Alice\n\n 2,Bob' - expect(decode(teon, { strict: false })).toEqual({ - items: [ - { id: 1, name: 'Alice' }, - { id: 2, name: 'Bob' }, - ], - }) - }) - - it('ignores multiple blank lines in arrays', () => { - const teon = 'items[2]:\n - a\n\n\n - b' - expect(decode(teon, { strict: false })).toEqual({ items: ['a', 'b'] }) - }) - }) - }) -}) +} diff --git a/packages/toon/test/encode.test.ts b/packages/toon/test/encode.test.ts index 679f0db..5d24b12 100644 --- a/packages/toon/test/encode.test.ts +++ b/packages/toon/test/encode.test.ts @@ -1,62 +1,33 @@ +import type { ResolvedEncodeOptions } from '../src/types' +import type { Fixtures, TestCase } from './types' +import arraysNested from '@toon-format/spec/tests/fixtures/encode/arrays-nested.json' +import arraysObjects from '@toon-format/spec/tests/fixtures/encode/arrays-objects.json' +import arraysPrimitive from '@toon-format/spec/tests/fixtures/encode/arrays-primitive.json' +import arraysTabular from '@toon-format/spec/tests/fixtures/encode/arrays-tabular.json' +import delimiters from '@toon-format/spec/tests/fixtures/encode/delimiters.json' +import normalization from '@toon-format/spec/tests/fixtures/encode/normalization.json' +import objects from '@toon-format/spec/tests/fixtures/encode/objects.json' +import options from '@toon-format/spec/tests/fixtures/encode/options.json' +import primitives from '@toon-format/spec/tests/fixtures/encode/primitives.json' +import whitespace from '@toon-format/spec/tests/fixtures/encode/whitespace.json' import { describe, expect, it } from 'vitest' -import { decode, encode } from '../src/index' +import { decode, DEFAULT_DELIMITER, encode } from '../src/index' -describe('primitives', () => { - it('encodes safe strings without quotes', () => { - expect(encode('hello')).toBe('hello') - expect(encode('Ada_99')).toBe('Ada_99') - }) - - it('quotes empty string', () => { - expect(encode('')).toBe('""') - }) - - it('quotes strings that look like booleans or numbers', () => { - expect(encode('true')).toBe('"true"') - expect(encode('false')).toBe('"false"') - expect(encode('null')).toBe('"null"') - expect(encode('42')).toBe('"42"') - expect(encode('-3.14')).toBe('"-3.14"') - expect(encode('1e-6')).toBe('"1e-6"') - expect(encode('05')).toBe('"05"') - }) - - it('escapes control characters in strings', () => { - expect(encode('line1\nline2')).toBe('"line1\\nline2"') - expect(encode('tab\there')).toBe('"tab\\there"') - expect(encode('return\rcarriage')).toBe('"return\\rcarriage"') - expect(encode('C:\\Users\\path')).toBe('"C:\\\\Users\\\\path"') - }) - - it('quotes strings with structural characters', () => { - expect(encode('[3]: x,y')).toBe('"[3]: x,y"') - expect(encode('- item')).toBe('"- item"') - expect(encode('[test]')).toBe('"[test]"') - expect(encode('{key}')).toBe('"{key}"') - }) - - it('handles Unicode and emoji', () => { - expect(encode('café')).toBe('café') - expect(encode('你好')).toBe('你好') - expect(encode('🚀')).toBe('🚀') - expect(encode('hello 👋 world')).toBe('hello 👋 world') - }) - - it('encodes numbers', () => { - expect(encode(42)).toBe('42') - expect(encode(3.14)).toBe('3.14') - expect(encode(-7)).toBe('-7') - expect(encode(0)).toBe('0') - }) - - it('handles special numeric values', () => { - expect(encode(-0)).toBe('0') - expect(encode(1e6)).toBe('1000000') - expect(encode(1e-6)).toBe('0.000001') - expect(encode(1e20)).toBe('100000000000000000000') - expect(encode(Number.MAX_SAFE_INTEGER)).toBe('9007199254740991') - }) +const fixtureFiles = [ + primitives, + objects, + arraysPrimitive, + arraysTabular, + arraysNested, + arraysObjects, + delimiters, + normalization, + whitespace, + options, +] as Fixtures[] +// Special test for round-trip fidelity (not in JSON fixtures) +describe('round-trip fidelity', () => { it('preserves precision for repeating decimals', () => { const value = 1 / 3 const encodedValue = encode({ value }) @@ -64,714 +35,32 @@ describe('primitives', () => { expect((decodedValue as Record)?.value).toBe(value) // Round-trip fidelity expect(encodedValue).toContain('0.3333333333333333') // Default JS precision }) - - it('encodes booleans', () => { - expect(encode(true)).toBe('true') - expect(encode(false)).toBe('false') - }) - - it('encodes null', () => { - expect(encode(null)).toBe('null') - }) }) -describe('objects (simple)', () => { - it('preserves key order in objects', () => { - const obj = { - id: 123, - name: 'Ada', - active: true, - } - expect(encode(obj)).toBe('id: 123\nname: Ada\nactive: true') - }) +// Run all fixture-based tests +for (const fixtures of fixtureFiles) { + describe(fixtures.description, () => { + for (const test of fixtures.tests) { + it(test.name, () => { + const resolvedOptions = resolveEncodeOptions(test.options) - it('encodes null values in objects', () => { - const obj = { id: 123, value: null } - expect(encode(obj)).toBe('id: 123\nvalue: null') - }) - - it('encodes empty objects as empty string', () => { - expect(encode({})).toBe('') - }) - - it('quotes string values with special characters', () => { - expect(encode({ note: 'a:b' })).toBe('note: "a:b"') - expect(encode({ note: 'a,b' })).toBe('note: "a,b"') - expect(encode({ text: 'line1\nline2' })).toBe('text: "line1\\nline2"') - expect(encode({ text: 'say "hello"' })).toBe('text: "say \\"hello\\""') - }) - - it('quotes string values with leading/trailing spaces', () => { - expect(encode({ text: ' padded ' })).toBe('text: " padded "') - expect(encode({ text: ' ' })).toBe('text: " "') - }) - - it('quotes string values that look like booleans/numbers', () => { - expect(encode({ v: 'true' })).toBe('v: "true"') - expect(encode({ v: '42' })).toBe('v: "42"') - expect(encode({ v: '-7.5' })).toBe('v: "-7.5"') - }) -}) - -describe('objects (keys)', () => { - it('quotes keys with special characters', () => { - expect(encode({ 'order:id': 7 })).toBe('"order:id": 7') - expect(encode({ '[index]': 5 })).toBe('"[index]": 5') - expect(encode({ '{key}': 5 })).toBe('"{key}": 5') - expect(encode({ 'a,b': 1 })).toBe('"a,b": 1') - }) - - it('quotes keys with spaces or leading hyphens', () => { - expect(encode({ 'full name': 'Ada' })).toBe('"full name": Ada') - expect(encode({ '-lead': 1 })).toBe('"-lead": 1') - expect(encode({ ' a ': 1 })).toBe('" a ": 1') - }) - - it('quotes numeric keys', () => { - expect(encode({ 123: 'x' })).toBe('"123": x') - }) - - it('quotes empty string key', () => { - expect(encode({ '': 1 })).toBe('"": 1') - }) - - it('escapes control characters in keys', () => { - expect(encode({ 'line\nbreak': 1 })).toBe('"line\\nbreak": 1') - expect(encode({ 'tab\there': 2 })).toBe('"tab\\there": 2') - }) - - it('escapes quotes in keys', () => { - expect(encode({ 'he said "hi"': 1 })).toBe('"he said \\"hi\\"": 1') - }) -}) - -describe('nested objects', () => { - it('encodes deeply nested objects', () => { - const obj = { - a: { - b: { - c: 'deep', - }, - }, - } - expect(encode(obj)).toBe('a:\n b:\n c: deep') - }) - - it('encodes empty nested object', () => { - expect(encode({ user: {} })).toBe('user:') - }) -}) - -describe('arrays of primitives', () => { - it('encodes string arrays inline', () => { - const obj = { tags: ['reading', 'gaming'] } - expect(encode(obj)).toBe('tags[2]: reading,gaming') - }) - - it('encodes number arrays inline', () => { - const obj = { nums: [1, 2, 3] } - expect(encode(obj)).toBe('nums[3]: 1,2,3') - }) - - it('encodes mixed primitive arrays inline', () => { - const obj = { data: ['x', 'y', true, 10] } - expect(encode(obj)).toBe('data[4]: x,y,true,10') - }) - - it('encodes empty arrays', () => { - const obj = { items: [] } - expect(encode(obj)).toBe('items[0]:') - }) - - it('handles empty string in arrays', () => { - const obj = { items: [''] } - expect(encode(obj)).toBe('items[1]: ""') - const obj2 = { items: ['a', '', 'b'] } - expect(encode(obj2)).toBe('items[3]: a,"",b') - }) - - it('handles whitespace-only strings in arrays', () => { - const obj = { items: [' ', ' '] } - expect(encode(obj)).toBe('items[2]: " "," "') - }) - - it('quotes array strings with special characters', () => { - const obj = { items: ['a', 'b,c', 'd:e'] } - expect(encode(obj)).toBe('items[3]: a,"b,c","d:e"') - }) - - it('quotes strings that look like booleans/numbers in arrays', () => { - const obj = { items: ['x', 'true', '42', '-3.14'] } - expect(encode(obj)).toBe('items[4]: x,"true","42","-3.14"') - }) - - it('quotes strings with structural meanings in arrays', () => { - const obj = { items: ['[5]', '- item', '{key}'] } - expect(encode(obj)).toBe('items[3]: "[5]","- item","{key}"') - }) -}) - -describe('arrays of objects (tabular and list items)', () => { - it('encodes arrays of similar objects in tabular format', () => { - const obj = { - items: [ - { sku: 'A1', qty: 2, price: 9.99 }, - { sku: 'B2', qty: 1, price: 14.5 }, - ], - } - expect(encode(obj)).toBe('items[2]{sku,qty,price}:\n A1,2,9.99\n B2,1,14.5') - }) - - it('handles null values in tabular format', () => { - const obj = { - items: [ - { id: 1, value: null }, - { id: 2, value: 'test' }, - ], - } - expect(encode(obj)).toBe('items[2]{id,value}:\n 1,null\n 2,test') - }) - - it('quotes strings containing delimiters in tabular rows', () => { - const obj = { - items: [ - { sku: 'A,1', desc: 'cool', qty: 2 }, - { sku: 'B2', desc: 'wip: test', qty: 1 }, - ], - } - expect(encode(obj)).toBe('items[2]{sku,desc,qty}:\n "A,1",cool,2\n B2,"wip: test",1') - }) - - it('quotes ambiguous strings in tabular rows', () => { - const obj = { - items: [ - { id: 1, status: 'true' }, - { id: 2, status: 'false' }, - ], - } - expect(encode(obj)).toBe('items[2]{id,status}:\n 1,"true"\n 2,"false"') - }) - - it('handles tabular arrays with keys needing quotes', () => { - const obj = { - items: [ - { 'order:id': 1, 'full name': 'Ada' }, - { 'order:id': 2, 'full name': 'Bob' }, - ], - } - expect(encode(obj)).toBe('items[2]{"order:id","full name"}:\n 1,Ada\n 2,Bob') - }) - - it('uses list format for objects with different fields', () => { - const obj = { - items: [ - { id: 1, name: 'First' }, - { id: 2, name: 'Second', extra: true }, - ], - } - expect(encode(obj)).toBe( - 'items[2]:\n' - + ' - id: 1\n' - + ' name: First\n' - + ' - id: 2\n' - + ' name: Second\n' - + ' extra: true', - ) - }) - - it('uses list format for objects with nested values', () => { - const obj = { - items: [ - { id: 1, nested: { x: 1 } }, - ], - } - expect(encode(obj)).toBe( - 'items[1]:\n' - + ' - id: 1\n' - + ' nested:\n' - + ' x: 1', - ) - }) - - it('preserves field order in list items', () => { - const obj = { items: [{ nums: [1, 2, 3], name: 'test' }] } - expect(encode(obj)).toBe( - 'items[1]:\n' - + ' - nums[3]: 1,2,3\n' - + ' name: test', - ) - }) - - it('preserves field order when primitive appears first', () => { - const obj = { items: [{ name: 'test', nums: [1, 2, 3] }] } - expect(encode(obj)).toBe( - 'items[1]:\n' - + ' - name: test\n' - + ' nums[3]: 1,2,3', - ) - }) - - it('uses list format for objects containing arrays of arrays', () => { - const obj = { - items: [ - { matrix: [[1, 2], [3, 4]], name: 'grid' }, - ], - } - expect(encode(obj)).toBe( - 'items[1]:\n' - + ' - matrix[2]:\n' - + ' - [2]: 1,2\n' - + ' - [2]: 3,4\n' - + ' name: grid', - ) - }) - - it('uses tabular format for nested uniform object arrays', () => { - const obj = { - items: [ - { users: [{ id: 1, name: 'Ada' }, { id: 2, name: 'Bob' }], status: 'active' }, - ], - } - expect(encode(obj)).toBe( - 'items[1]:\n' - + ' - users[2]{id,name}:\n' - + ' 1,Ada\n' - + ' 2,Bob\n' - + ' status: active', - ) - }) - - it('uses list format for nested object arrays with mismatched keys', () => { - const obj = { - items: [ - { users: [{ id: 1, name: 'Ada' }, { id: 2 }], status: 'active' }, - ], - } - expect(encode(obj)).toBe( - 'items[1]:\n' - + ' - users[2]:\n' - + ' - id: 1\n' - + ' name: Ada\n' - + ' - id: 2\n' - + ' status: active', - ) - }) - - it('uses list format for objects with multiple array fields', () => { - const obj = { items: [{ nums: [1, 2], tags: ['a', 'b'], name: 'test' }] } - expect(encode(obj)).toBe( - 'items[1]:\n' - + ' - nums[2]: 1,2\n' - + ' tags[2]: a,b\n' - + ' name: test', - ) - }) - - it('uses list format for objects with only array fields', () => { - const obj = { items: [{ nums: [1, 2, 3], tags: ['a', 'b'] }] } - expect(encode(obj)).toBe( - 'items[1]:\n' - + ' - nums[3]: 1,2,3\n' - + ' tags[2]: a,b', - ) - }) - - it('handles objects with empty arrays in list format', () => { - const obj = { - items: [ - { name: 'test', data: [] }, - ], - } - expect(encode(obj)).toBe( - 'items[1]:\n' - + ' - name: test\n' - + ' data[0]:', - ) - }) - - it('places first field of nested tabular arrays on hyphen line', () => { - const obj = { items: [{ users: [{ id: 1 }, { id: 2 }], note: 'x' }] } - expect(encode(obj)).toBe( - 'items[1]:\n' - + ' - users[2]{id}:\n' - + ' 1\n' - + ' 2\n' - + ' note: x', - ) - }) - - it('places empty arrays on hyphen line when first', () => { - const obj = { items: [{ data: [], name: 'x' }] } - expect(encode(obj)).toBe( - 'items[1]:\n' - + ' - data[0]:\n' - + ' name: x', - ) - }) - - it('uses field order from first object for tabular headers', () => { - const obj = { - items: [ - { a: 1, b: 2, c: 3 }, - { c: 30, b: 20, a: 10 }, - ], - } - expect(encode(obj)).toBe('items[2]{a,b,c}:\n 1,2,3\n 10,20,30') - }) - - it('uses list format for one object with nested column', () => { - const obj = { - items: [ - { id: 1, data: 'string' }, - { id: 2, data: { nested: true } }, - ], - } - expect(encode(obj)).toBe( - 'items[2]:\n' - + ' - id: 1\n' - + ' data: string\n' - + ' - id: 2\n' - + ' data:\n' - + ' nested: true', - ) - }) -}) - -describe('arrays of arrays (primitives only)', () => { - it('encodes nested arrays of primitives', () => { - const obj = { - pairs: [['a', 'b'], ['c', 'd']], - } - expect(encode(obj)).toBe('pairs[2]:\n - [2]: a,b\n - [2]: c,d') - }) - - it('quotes strings containing delimiters in nested arrays', () => { - const obj = { - pairs: [['a', 'b'], ['c,d', 'e:f', 'true']], - } - expect(encode(obj)).toBe('pairs[2]:\n - [2]: a,b\n - [3]: "c,d","e:f","true"') - }) - - it('handles empty inner arrays', () => { - const obj = { - pairs: [[], []], - } - expect(encode(obj)).toBe('pairs[2]:\n - [0]:\n - [0]:') - }) - - it('handles mixed-length inner arrays', () => { - const obj = { - pairs: [[1], [2, 3]], - } - expect(encode(obj)).toBe('pairs[2]:\n - [1]: 1\n - [2]: 2,3') - }) -}) - -describe('root arrays', () => { - it('encodes arrays of primitives at root level', () => { - const arr = ['x', 'y', 'true', true, 10] - expect(encode(arr)).toBe('[5]: x,y,"true",true,10') - }) - - it('encodes arrays of similar objects in tabular format', () => { - const arr = [{ id: 1 }, { id: 2 }] - expect(encode(arr)).toBe('[2]{id}:\n 1\n 2') - }) - - it('encodes arrays of different objects in list format', () => { - const arr = [{ id: 1 }, { id: 2, name: 'Ada' }] - expect(encode(arr)).toBe('[2]:\n - id: 1\n - id: 2\n name: Ada') - }) - - it('encodes empty arrays at root level', () => { - expect(encode([])).toBe('[0]:') - }) - - it('encodes arrays of arrays at root level', () => { - const arr = [[1, 2], []] - expect(encode(arr)).toBe('[2]:\n - [2]: 1,2\n - [0]:') - }) -}) - -describe('complex structures', () => { - it('encodes objects with mixed arrays and nested objects', () => { - const obj = { - user: { - id: 123, - name: 'Ada', - tags: ['reading', 'gaming'], - active: true, - prefs: [], - }, - } - expect(encode(obj)).toBe( - 'user:\n' - + ' id: 123\n' - + ' name: Ada\n' - + ' tags[2]: reading,gaming\n' - + ' active: true\n' - + ' prefs[0]:', - ) - }) -}) - -describe('mixed arrays', () => { - it('uses list format for arrays mixing primitives and objects', () => { - const obj = { - items: [1, { a: 1 }, 'text'], - } - expect(encode(obj)).toBe( - 'items[3]:\n' - + ' - 1\n' - + ' - a: 1\n' - + ' - text', - ) - }) - - it('uses list format for arrays mixing objects and arrays', () => { - const obj = { - items: [{ a: 1 }, [1, 2]], - } - expect(encode(obj)).toBe( - 'items[2]:\n' - + ' - a: 1\n' - + ' - [2]: 1,2', - ) - }) -}) - -describe('whitespace and formatting invariants', () => { - it('produces no trailing spaces at end of lines', () => { - const obj = { - user: { - id: 123, - name: 'Ada', - }, - items: ['a', 'b'], - } - const result = encode(obj) - const lines = result.split('\n') - for (const line of lines) { - expect(line).not.toMatch(/ $/) + if (test.shouldError) { + expect(() => encode(test.input, resolvedOptions)) + .toThrow() + } + else { + const result = encode(test.input, resolvedOptions) + expect(result).toBe(test.expected) + } + }) } }) +} - it('produces no trailing newline at end of output', () => { - const obj = { id: 123 } - const result = encode(obj) - expect(result).not.toMatch(/\n$/) - }) -}) - -describe('non-JSON-serializable values', () => { - it('converts BigInt to string', () => { - expect(encode(BigInt(123))).toBe('123') - expect(encode({ id: BigInt(456) })).toBe('id: 456') - }) - - it('converts Date to ISO string', () => { - const date = new Date('2025-01-01T00:00:00.000Z') - expect(encode(date)).toBe('"2025-01-01T00:00:00.000Z"') - expect(encode({ created: date })).toBe('created: "2025-01-01T00:00:00.000Z"') - }) - - it('converts undefined to null', () => { - expect(encode(undefined)).toBe('null') - expect(encode({ value: undefined })).toBe('value: null') - }) - - it('converts non-finite numbers to null', () => { - expect(encode(Infinity)).toBe('null') - expect(encode(-Infinity)).toBe('null') - expect(encode(Number.NaN)).toBe('null') - }) - - it('converts functions to null', () => { - expect(encode(() => {})).toBe('null') - expect(encode({ fn: () => {} })).toBe('fn: null') - }) - - it('converts symbols to null', () => { - expect(encode(Symbol('test'))).toBe('null') - expect(encode({ sym: Symbol('test') })).toBe('sym: null') - }) -}) - -describe('delimiter options', () => { - describe('basic delimiter usage', () => { - it.each([ - { delimiter: '\t' as const, name: 'tab', expected: 'reading\tgaming\tcoding' }, - { delimiter: '|' as const, name: 'pipe', expected: 'reading|gaming|coding' }, - { delimiter: ',' as const, name: 'comma', expected: 'reading,gaming,coding' }, - ])('encodes primitive arrays with $name', ({ delimiter, expected }) => { - const obj = { tags: ['reading', 'gaming', 'coding'] } - expect(encode(obj, { delimiter })).toBe(`tags[3${delimiter !== ',' ? delimiter : ''}]: ${expected}`) - }) - - it.each([ - { delimiter: '\t' as const, name: 'tab', expected: 'items[2\t]{sku\tqty\tprice}:\n A1\t2\t9.99\n B2\t1\t14.5' }, - { delimiter: '|' as const, name: 'pipe', expected: 'items[2|]{sku|qty|price}:\n A1|2|9.99\n B2|1|14.5' }, - ])('encodes tabular arrays with $name', ({ delimiter, expected }) => { - const obj = { - items: [ - { sku: 'A1', qty: 2, price: 9.99 }, - { sku: 'B2', qty: 1, price: 14.5 }, - ], - } - expect(encode(obj, { delimiter })).toBe(expected) - }) - - it.each([ - { delimiter: '\t' as const, name: 'tab', expected: 'pairs[2\t]:\n - [2\t]: a\tb\n - [2\t]: c\td' }, - { delimiter: '|' as const, name: 'pipe', expected: 'pairs[2|]:\n - [2|]: a|b\n - [2|]: c|d' }, - ])('encodes nested arrays with $name', ({ delimiter, expected }) => { - const obj = { pairs: [['a', 'b'], ['c', 'd']] } - expect(encode(obj, { delimiter })).toBe(expected) - }) - - it.each([ - { delimiter: '\t' as const, name: 'tab' }, - { delimiter: '|' as const, name: 'pipe' }, - ])('encodes root arrays with $name', ({ delimiter }) => { - const arr = ['x', 'y', 'z'] - expect(encode(arr, { delimiter })).toBe(`[3${delimiter}]: x${delimiter}y${delimiter}z`) - }) - - it.each([ - { delimiter: '\t' as const, name: 'tab', expected: '[2\t]{id}:\n 1\n 2' }, - { delimiter: '|' as const, name: 'pipe', expected: '[2|]{id}:\n 1\n 2' }, - ])('encodes root arrays of objects with $name', ({ delimiter, expected }) => { - const arr = [{ id: 1 }, { id: 2 }] - expect(encode(arr, { delimiter })).toBe(expected) - }) - }) - - describe('delimiter-aware quoting', () => { - it.each([ - { delimiter: '\t' as const, name: 'tab', char: '\t', input: ['a', 'b\tc', 'd'], expected: 'a\t"b\\tc"\td' }, - { delimiter: '|' as const, name: 'pipe', char: '|', input: ['a', 'b|c', 'd'], expected: 'a|"b|c"|d' }, - ])('quotes strings containing $name', ({ delimiter, input, expected }) => { - expect(encode({ items: input }, { delimiter })).toBe(`items[${input.length}${delimiter}]: ${expected}`) - }) - - it.each([ - { delimiter: '\t' as const, name: 'tab', input: ['a,b', 'c,d'], expected: 'a,b\tc,d' }, - { delimiter: '|' as const, name: 'pipe', input: ['a,b', 'c,d'], expected: 'a,b|c,d' }, - ])('does not quote commas with $name', ({ delimiter, input, expected }) => { - expect(encode({ items: input }, { delimiter })).toBe(`items[${input.length}${delimiter}]: ${expected}`) - }) - - it('quotes tabular values containing the delimiter', () => { - const obj = { - items: [ - { id: 1, note: 'a,b' }, - { id: 2, note: 'c,d' }, - ], - } - expect(encode(obj, { delimiter: ',' })).toBe('items[2]{id,note}:\n 1,"a,b"\n 2,"c,d"') - expect(encode(obj, { delimiter: '\t' })).toBe('items[2\t]{id\tnote}:\n 1\ta,b\n 2\tc,d') - }) - - it('does not quote commas in object values with non-comma delimiter', () => { - expect(encode({ note: 'a,b' }, { delimiter: '|' })).toBe('note: a,b') - expect(encode({ note: 'a,b' }, { delimiter: '\t' })).toBe('note: a,b') - }) - - it('quotes nested array values containing the delimiter', () => { - expect(encode({ pairs: [['a', 'b|c']] }, { delimiter: '|' })).toBe('pairs[1|]:\n - [2|]: a|"b|c"') - expect(encode({ pairs: [['a', 'b\tc']] }, { delimiter: '\t' })).toBe('pairs[1\t]:\n - [2\t]: a\t"b\\tc"') - }) - }) - - describe('delimiter-independent quoting rules', () => { - it('preserves ambiguity quoting regardless of delimiter', () => { - const obj = { items: ['true', '42', '-3.14'] } - expect(encode(obj, { delimiter: '|' })).toBe('items[3|]: "true"|"42"|"-3.14"') - expect(encode(obj, { delimiter: '\t' })).toBe('items[3\t]: "true"\t"42"\t"-3.14"') - }) - - it('preserves structural quoting regardless of delimiter', () => { - const obj = { items: ['[5]', '{key}', '- item'] } - expect(encode(obj, { delimiter: '|' })).toBe('items[3|]: "[5]"|"{key}"|"- item"') - expect(encode(obj, { delimiter: '\t' })).toBe('items[3\t]: "[5]"\t"{key}"\t"- item"') - }) - - it('quotes keys containing the delimiter', () => { - expect(encode({ 'a|b': 1 }, { delimiter: '|' })).toBe('"a|b": 1') - expect(encode({ 'a\tb': 1 }, { delimiter: '\t' })).toBe('"a\\tb": 1') - }) - - it('quotes tabular headers containing the delimiter', () => { - const obj = { items: [{ 'a|b': 1 }, { 'a|b': 2 }] } - expect(encode(obj, { delimiter: '|' })).toBe('items[2|]{"a|b"}:\n 1\n 2') - }) - - it('header uses the active delimiter', () => { - const obj = { items: [{ a: 1, b: 2 }, { a: 3, b: 4 }] } - expect(encode(obj, { delimiter: '|' })).toBe('items[2|]{a|b}:\n 1|2\n 3|4') - expect(encode(obj, { delimiter: '\t' })).toBe('items[2\t]{a\tb}:\n 1\t2\n 3\t4') - }) - }) - - describe('formatting invariants with delimiters', () => { - it.each([ - { delimiter: '\t' as const, name: 'tab' }, - { delimiter: '|' as const, name: 'pipe' }, - ])('produces no trailing spaces with $name', ({ delimiter }) => { - const obj = { - user: { id: 123, name: 'Ada' }, - items: ['a', 'b'], - } - const result = encode(obj, { delimiter }) - const lines = result.split('\n') - for (const line of lines) { - expect(line).not.toMatch(/ $/) - } - }) - - it.each([ - { delimiter: '\t' as const, name: 'tab' }, - { delimiter: '|' as const, name: 'pipe' }, - ])('produces no trailing newline with $name', ({ delimiter }) => { - const obj = { id: 123 } - const result = encode(obj, { delimiter }) - expect(result).not.toMatch(/\n$/) - }) - }) -}) - -describe('length marker option', () => { - it('adds length marker to primitive arrays', () => { - const obj = { tags: ['reading', 'gaming', 'coding'] } - expect(encode(obj, { lengthMarker: '#' })).toBe('tags[#3]: reading,gaming,coding') - }) - - it('handles empty arrays', () => { - expect(encode({ items: [] }, { lengthMarker: '#' })).toBe('items[#0]:') - }) - - it('adds length marker to tabular arrays', () => { - const obj = { - items: [ - { sku: 'A1', qty: 2, price: 9.99 }, - { sku: 'B2', qty: 1, price: 14.5 }, - ], - } - expect(encode(obj, { lengthMarker: '#' })).toBe('items[#2]{sku,qty,price}:\n A1,2,9.99\n B2,1,14.5') - }) - - it('adds length marker to nested arrays', () => { - const obj = { pairs: [['a', 'b'], ['c', 'd']] } - expect(encode(obj, { lengthMarker: '#' })).toBe('pairs[#2]:\n - [#2]: a,b\n - [#2]: c,d') - }) - - it('works with delimiter option', () => { - const obj = { tags: ['reading', 'gaming', 'coding'] } - expect(encode(obj, { lengthMarker: '#', delimiter: '|' })).toBe('tags[#3|]: reading|gaming|coding') - }) - - it('default is false (no length marker)', () => { - const obj = { tags: ['reading', 'gaming', 'coding'] } - expect(encode(obj)).toBe('tags[3]: reading,gaming,coding') - }) -}) +function resolveEncodeOptions(options?: TestCase['options']): ResolvedEncodeOptions { + return { + indent: options?.indent ?? 2, + delimiter: options?.delimiter ?? DEFAULT_DELIMITER, + lengthMarker: options?.lengthMarker === '#' ? '#' : false, + } +} diff --git a/packages/toon/test/types.ts b/packages/toon/test/types.ts new file mode 100644 index 0000000..2783676 --- /dev/null +++ b/packages/toon/test/types.ts @@ -0,0 +1,29 @@ +/** + * Type definitions for TOON test fixtures + * + * @remarks + * Matches the JSON schema at https://github.com/toon-format/spec/blob/main/tests/fixtures.schema.json. + */ + +export interface TestCase { + name: string + input: unknown + expected: unknown + shouldError?: boolean + options?: { + delimiter?: ',' | '\t' | '|' + indent?: number + lengthMarker?: '#' | '' + strict?: boolean + } + specSection?: string + note?: string + minSpecVersion?: string +} + +export interface Fixtures { + version: string + category: 'encode' | 'decode' + description: string + tests: TestCase[] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d986688..49aa280 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,11 +9,11 @@ importers: .: devDependencies: '@antfu/eslint-config': - specifier: ^6.1.0 - version: 6.1.0(@vue/compiler-sfc@3.5.22)(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.3(@types/debug@4.1.12)(@types/node@24.9.1)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1)) + specifier: ^6.2.0 + version: 6.2.0(@vue/compiler-sfc@3.5.22)(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.6(@types/debug@4.1.12)(@types/node@24.9.2)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1)) '@types/node': - specifier: ^24.9.1 - version: 24.9.1 + specifier: ^24.9.2 + version: 24.9.2 automd: specifier: ^0.4.2 version: 0.4.2 @@ -21,11 +21,11 @@ importers: specifier: ^10.3.1 version: 10.3.1 eslint: - specifier: ^9.38.0 - version: 9.38.0(jiti@2.6.1) + specifier: ^9.39.0 + version: 9.39.0(jiti@2.6.1) tsdown: - specifier: ^0.15.10 - version: 0.15.10(typescript@5.9.3) + specifier: ^0.15.12 + version: 0.15.12(typescript@5.9.3) tsx: specifier: ^4.20.6 version: 4.20.6 @@ -33,26 +33,26 @@ importers: specifier: ^5.9.3 version: 5.9.3 vitest: - specifier: ^4.0.3 - version: 4.0.3(@types/debug@4.1.12)(@types/node@24.9.1)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1) + specifier: ^4.0.6 + version: 4.0.6(@types/debug@4.1.12)(@types/node@24.9.2)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1) benchmarks: devDependencies: '@ai-sdk/anthropic': - specifier: ^2.0.37 - version: 2.0.37(zod@4.1.12) + specifier: ^2.0.40 + version: 2.0.40(zod@4.1.12) '@ai-sdk/google': - specifier: ^2.0.23 - version: 2.0.23(zod@4.1.12) + specifier: ^2.0.26 + version: 2.0.26(zod@4.1.12) '@ai-sdk/openai': - specifier: ^2.0.53 - version: 2.0.53(zod@4.1.12) + specifier: ^2.0.59 + version: 2.0.59(zod@4.1.12) '@ai-sdk/provider': specifier: ^2.0.0 version: 2.0.0 '@ai-sdk/xai': - specifier: ^2.0.28 - version: 2.0.28(zod@4.1.12) + specifier: ^2.0.30 + version: 2.0.30(zod@4.1.12) '@clack/prompts': specifier: ^0.11.0 version: 0.11.0 @@ -60,8 +60,8 @@ importers: specifier: ^10.1.0 version: 10.1.0 ai: - specifier: ^5.0.80 - version: 5.0.80(zod@4.1.12) + specifier: ^5.0.86 + version: 5.0.86(zod@4.1.12) csv-stringify: specifier: ^6.6.0 version: 6.6.0 @@ -72,8 +72,8 @@ importers: specifier: ^3.2.0 version: 3.2.0 ofetch: - specifier: ^1.4.1 - version: 1.4.1 + specifier: ^1.5.1 + version: 1.5.1 p-map: specifier: ^7.0.3 version: 7.0.3 @@ -81,8 +81,8 @@ importers: specifier: ^9.0.0 version: 9.0.0 unstorage: - specifier: ^1.17.1 - version: 1.17.1 + specifier: ^1.17.2 + version: 1.17.2 yaml: specifier: ^2.8.1 version: 2.8.1 @@ -99,48 +99,46 @@ importers: specifier: ^1.2.0 version: 1.2.0 - packages/toon: {} + packages/toon: + devDependencies: + '@toon-format/spec': + specifier: ^1.3.0 + version: 1.3.0 packages: - '@ai-sdk/anthropic@2.0.37': - resolution: {integrity: sha512-r2e9BWoobisH9B5b7x3yYG/k9WlsZqa4D94o7gkwktReqrjjv83zNMop4KmlJsh/zBhbsaP8S8SUfiwK+ESxgg==} + '@ai-sdk/anthropic@2.0.40': + resolution: {integrity: sha512-aHtqlIIS8lyesSNFxevLGWozCCZ1xQ4Wy2HfQSVVQu3dWtndfPzF6hbWof2Way+qNrvRtjnBpRQyaVeu6Js4pQ==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/gateway@2.0.1': - resolution: {integrity: sha512-vPVIbnP35ZnayS937XLo85vynR85fpBQWHCdUweq7apzqFOTU2YkUd4V3msebEHbQ2Zro60ZShDDy9SMiyWTqA==} + '@ai-sdk/gateway@2.0.5': + resolution: {integrity: sha512-5TTDSl0USWY6YGnb4QmJGplFZhk+p9OT7hZevAaER6OGiZ17LB1GypsGYDpNo/MiVMklk8kX4gk6p1/R/EiJ8Q==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/google@2.0.23': - resolution: {integrity: sha512-VbCnKR+6aWUVLkAiSW5gUEtST7KueEmlt+d6qwDikxlLnFG9pzy59je8MiDVeM5G2tuSXbvZQF78PGIfXDBmow==} + '@ai-sdk/google@2.0.26': + resolution: {integrity: sha512-LMCT8TDwj1ww4W34f1YJHfk2LggsMV4dqF8qSolJIopdERCclA+S+LzaIaiyeoYDD+slUrf3FXvi1t+yd21jxQ==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/openai-compatible@1.0.23': - resolution: {integrity: sha512-nCmdy8/LqaaUQhV4b6LcTFbmdGVy+aAwFCmQWHEyTAwaGfuqrWIwphhFVqqAZwqB+j8Ymy350IpKk1M5P5uuEw==} + '@ai-sdk/openai-compatible@1.0.25': + resolution: {integrity: sha512-VPylb5ytkOu9Bs1UnVmz4x0wr1VtS30Pw6ghh6GxpGH6lo4GOWqVnYuB+8M755dkof74c5LULZq5C1n/1J4Kvg==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/openai@2.0.53': - resolution: {integrity: sha512-GIkR3+Fyif516ftXv+YPSPstnAHhcZxNoR2s8uSHhQ1yBT7I7aQYTVwpjAuYoT3GR+TeP50q7onj2/nDRbT2FQ==} + '@ai-sdk/openai@2.0.59': + resolution: {integrity: sha512-ylaL91BrMyqHsprEI0+brvvGwDjRlKxsJTRL1kpzx6AhG37JqpECQwuqNk7aq+T5Qww9w7dqn1JMUuVPvyZtsA==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/provider-utils@3.0.12': - resolution: {integrity: sha512-ZtbdvYxdMoria+2SlNarEk6Hlgyf+zzcznlD55EAl+7VZvJaSg2sqPvwArY7L6TfDEDJsnCq0fdhBSkYo0Xqdg==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - - '@ai-sdk/provider-utils@3.0.13': - resolution: {integrity: sha512-aXFLBLRPTUYA853MJliItefSXeJPl+mg0KSjbToP41kJ+banBmHO8ZPGLJhNqGlCU82o11TYN7G05EREKX8CkA==} + '@ai-sdk/provider-utils@3.0.15': + resolution: {integrity: sha512-kOc6Pxb7CsRlNt+sLZKL7/VGQUd7ccl3/tIK+Bqf5/QhHR0Qm3qRBMz1IwU1RmjJEZA73x+KB5cUckbDl2WF7Q==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 @@ -149,14 +147,14 @@ packages: resolution: {integrity: sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==} engines: {node: '>=18'} - '@ai-sdk/xai@2.0.28': - resolution: {integrity: sha512-iVrrX/A3YVzCltW7eO3rYB+QtyIFZYEIllWiE7oM48AO/GX2LJcCd2IBCFY820bu2ZXzlOtGty9JQEJIzP5Gug==} + '@ai-sdk/xai@2.0.30': + resolution: {integrity: sha512-dVnt57hX4n8NCjmQ++Bfq5PFdTy4yToOWK2hrs6AsrRfHWsT+7BKecTorsDyX85C4h6yIoB6k1AboDYKsxCpeQ==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@antfu/eslint-config@6.1.0': - resolution: {integrity: sha512-m/L9TGvtG3r4tkfq5BY6THz7pk0g6yuJwwA0SkLEDHJJpt0upuABhs8v3SU8yaPtCGUxq8k2QTLMZ3WPg4vSdw==} + '@antfu/eslint-config@6.2.0': + resolution: {integrity: sha512-ksasd+mJk441HHodwPh3Nhmwo9jSHUmgQyfTxMQM05U7SjDS0fy2KnXnPx0Vhc/CqKiJnx8wGpQCCJibyASX9Q==} hasBin: true peerDependencies: '@eslint-react/eslint-plugin': ^2.0.1 @@ -261,162 +259,162 @@ packages: resolution: {integrity: sha512-g+RihtzFgGTx2WYCuTHbdOXJeAlGnROws0TeALx9ow/ZmOROOZkVg5wp/B44n0WJgI4SQFP1eWM2iRPlU2Y14w==} engines: {node: '>=20.11.0'} - '@es-joy/resolve.exports@1.0.0': - resolution: {integrity: sha512-bbrmzsAZ9GA/3oBS6r8PWMtZarEhKHr413hak8ArwMEZ5DtaLErnkcyEWUsXy7urBcmVu/TpDzHPDVM5uIbx9A==} + '@es-joy/resolve.exports@1.2.0': + resolution: {integrity: sha512-Q9hjxWI5xBM+qW2enxfe8wDKdFWMfd0Z29k5ZJnuBqD/CasY5Zryj09aCA6owbGATWz+39p5uIdaHXpopOcG8g==} engines: {node: '>=10'} - '@esbuild/aix-ppc64@0.25.11': - resolution: {integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==} + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.11': - resolution: {integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==} + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.11': - resolution: {integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==} + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.11': - resolution: {integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==} + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.11': - resolution: {integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==} + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.11': - resolution: {integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==} + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.11': - resolution: {integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==} + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.11': - resolution: {integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==} + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.11': - resolution: {integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==} + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.11': - resolution: {integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==} + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.11': - resolution: {integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==} + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.11': - resolution: {integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==} + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.11': - resolution: {integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==} + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.11': - resolution: {integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==} + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.11': - resolution: {integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==} + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.11': - resolution: {integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==} + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.11': - resolution: {integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==} + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.11': - resolution: {integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==} + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.11': - resolution: {integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==} + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.11': - resolution: {integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==} + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.11': - resolution: {integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==} + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.25.11': - resolution: {integrity: sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==} + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.25.11': - resolution: {integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==} + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.11': - resolution: {integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==} + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.11': - resolution: {integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==} + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.11': - resolution: {integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==} + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -437,8 +435,8 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/compat@1.4.0': - resolution: {integrity: sha512-DEzm5dKeDBPm3r08Ixli/0cmxr8LkRdwxMRUIJBlSCpAwSrvFEJpVBzV+66JhDxiaqKxnRzCXhtiMiczF7Hglg==} + '@eslint/compat@1.4.1': + resolution: {integrity: sha512-cfO82V9zxxGBxcQDr1lfaYB7wykTa0b00mGa36FrJl7iTFd0Z2cHfEYuxcBRP/iNijCsWsEkA+jzT8hGYmv33w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.40 || 9 @@ -450,24 +448,24 @@ packages: resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/config-helpers@0.4.1': - resolution: {integrity: sha512-csZAzkNhsgwb0I/UAV6/RGFTbiakPCf0ZrGmrIxQpYvGZ00PhTkSnyKNolphgIvmnJeGw6rcGVEXfTzUnFuEvw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/core@0.15.2': - resolution: {integrity: sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==} + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/core@0.16.0': resolution: {integrity: sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/eslintrc@3.3.1': resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.38.0': - resolution: {integrity: sha512-UZ1VpFvXf9J06YG9xQBdnzU+kthors6KjhMAl6f4gH4usHyh31rUf2DLGInT8RFYIReYXNSydgPY0V2LuWgl7A==} + '@eslint/js@9.39.0': + resolution: {integrity: sha512-BIhe0sW91JGPiaF1mOuPy5v8NflqfjIcDNpC+LbW9f609WVRX1rArrhi6Z2ymvrAry9jw+5POTj4t2t62o8Bmw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/markdown@7.5.0': @@ -478,12 +476,8 @@ packages: resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/plugin-kit@0.3.5': - resolution: {integrity: sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/plugin-kit@0.4.0': - resolution: {integrity: sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==} + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@faker-js/faker@10.1.0': @@ -538,10 +532,6 @@ packages: resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} engines: {node: '>=8.0.0'} - '@oxc-project/runtime@0.95.0': - resolution: {integrity: sha512-qJS5pNepwMGnafO9ayKGz7rfPQgUBuunHpnP1//9Qa0zK3oT3t1EhT+I+pV9MUA+ZKez//OFqxCxf1vijCKb2Q==} - engines: {node: ^20.19.0 || >=22.12.0} - '@oxc-project/types@0.95.0': resolution: {integrity: sha512-vACy7vhpMPhjEJhULNxrdR0D943TkA/MigMpJCHmBHvMXxRStRi/dPtTlfQ3uDwWSzRpT8z+7ImjZVf8JWBocQ==} @@ -634,91 +624,91 @@ packages: '@quansync/fs@0.1.5': resolution: {integrity: sha512-lNS9hL2aS2NZgNW7BBj+6EBl4rOf8l+tQ0eRY6JWCI8jI2kc53gSoqbjojU0OnAWhzoXiOjFyGsHcDGePB3lhA==} - '@rolldown/binding-android-arm64@1.0.0-beta.44': - resolution: {integrity: sha512-g9ejDOehJFhxC1DIXQuZQ9bKv4lRDioOTL42cJjFjqKPl1L7DVb9QQQE1FxokGEIMr6FezLipxwnzOXWe7DNPg==} + '@rolldown/binding-android-arm64@1.0.0-beta.45': + resolution: {integrity: sha512-bfgKYhFiXJALeA/riil908+2vlyWGdwa7Ju5S+JgWZYdR4jtiPOGdM6WLfso1dojCh+4ZWeiTwPeV9IKQEX+4g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.0-beta.44': - resolution: {integrity: sha512-PxAW1PXLPmCzfhfKIS53kwpjLGTUdIfX4Ht+l9mj05C3lYCGaGowcNsYi2rdxWH24vSTmeK+ajDNRmmmrK0M7g==} + '@rolldown/binding-darwin-arm64@1.0.0-beta.45': + resolution: {integrity: sha512-xjCv4CRVsSnnIxTuyH1RDJl5OEQ1c9JYOwfDAHddjJDxCw46ZX9q80+xq7Eok7KC4bRSZudMJllkvOKv0T9SeA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-beta.44': - resolution: {integrity: sha512-/CtQqs1oO9uSb5Ju60rZvsdjE7Pzn8EK2ISAdl2jedjMzeD/4neNyCbwyJOAPzU+GIQTZVyrFZJX+t7HXR1R/g==} + '@rolldown/binding-darwin-x64@1.0.0-beta.45': + resolution: {integrity: sha512-ddcO9TD3D/CLUa/l8GO8LHzBOaZqWg5ClMy3jICoxwCuoz47h9dtqPsIeTiB6yR501LQTeDsjA4lIFd7u3Ljfw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.0-beta.44': - resolution: {integrity: sha512-V5Q5W9c4+2GJ4QabmjmVV6alY97zhC/MZBaLkDtHwGy3qwzbM4DYgXUbun/0a8AH5hGhuU27tUIlYz6ZBlvgOA==} + '@rolldown/binding-freebsd-x64@1.0.0-beta.45': + resolution: {integrity: sha512-MBTWdrzW9w+UMYDUvnEuh0pQvLENkl2Sis15fHTfHVW7ClbGuez+RWopZudIDEGkpZXdeI4CkRXk+vdIIebrmg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.44': - resolution: {integrity: sha512-X6adjkHeFqKsTU0FXdNN9HY4LDozPqIfHcnXovE5RkYLWIjMWuc489mIZ6iyhrMbCqMUla9IOsh5dvXSGT9o9A==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.45': + resolution: {integrity: sha512-4YgoCFiki1HR6oSg+GxxfzfnVCesQxLF1LEnw9uXS/MpBmuog0EOO2rYfy69rWP4tFZL9IWp6KEfGZLrZ7aUog==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.44': - resolution: {integrity: sha512-kRRKGZI4DXWa6ANFr3dLA85aSVkwPdgXaRjfanwY84tfc3LncDiIjyWCb042e3ckPzYhHSZ3LmisO+cdOIYL6Q==} + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.45': + resolution: {integrity: sha512-LE1gjAwQRrbCOorJJ7LFr10s5vqYf5a00V5Ea9wXcT2+56n5YosJkcp8eQ12FxRBv2YX8dsdQJb+ZTtYJwb6XQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.44': - resolution: {integrity: sha512-hMtiN9xX1NhxXBa2U3Up4XkVcsVp2h73yYtMDY59z9CDLEZLrik9RVLhBL5QtoX4zZKJ8HZKJtWuGYvtmkCbIQ==} + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.45': + resolution: {integrity: sha512-tdy8ThO/fPp40B81v0YK3QC+KODOmzJzSUOO37DinQxzlTJ026gqUSOM8tzlVixRbQJltgVDCTYF8HNPRErQTA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.44': - resolution: {integrity: sha512-rd1LzbpXQuR8MTG43JB9VyXDjG7ogSJbIkBpZEHJ8oMKzL6j47kQT5BpIXrg3b5UVygW9QCI2fpFdMocT5Kudg==} + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.45': + resolution: {integrity: sha512-lS082ROBWdmOyVY/0YB3JmsiClaWoxvC+dA8/rbhyB9VLkvVEaihLEOr4CYmrMse151C4+S6hCw6oa1iewox7g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - '@rolldown/binding-linux-x64-musl@1.0.0-beta.44': - resolution: {integrity: sha512-qI2IiPqmPRW25exXkuQr3TlweCDc05YvvbSDRPCuPsWkwb70dTiSoXn8iFxT4PWqTi71wWHg1Wyta9PlVhX5VA==} + '@rolldown/binding-linux-x64-musl@1.0.0-beta.45': + resolution: {integrity: sha512-Hi73aYY0cBkr1/SvNQqH8Cd+rSV6S9RB5izCv0ySBcRnd/Wfn5plguUoGYwBnhHgFbh6cPw9m2dUVBR6BG1gxA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - '@rolldown/binding-openharmony-arm64@1.0.0-beta.44': - resolution: {integrity: sha512-+vHvEc1pL5iJRFlldLC8mjm6P4Qciyfh2bh5ZI6yxDQKbYhCHRKNURaKz1mFcwxhVL5YMYsLyaqM3qizVif9MQ==} + '@rolldown/binding-openharmony-arm64@1.0.0-beta.45': + resolution: {integrity: sha512-fljEqbO7RHHogNDxYtTzr+GNjlfOx21RUyGmF+NrkebZ8emYYiIqzPxsaMZuRx0rgZmVmliOzEp86/CQFDKhJQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.0-beta.44': - resolution: {integrity: sha512-XSgLxRrtFj6RpTeMYmmQDAwHjKseYGKUn5LPiIdW4Cq+f5SBSStL2ToBDxkbdxKPEbCZptnLPQ/nfKcAxrC8Xg==} + '@rolldown/binding-wasm32-wasi@1.0.0-beta.45': + resolution: {integrity: sha512-ZJDB7lkuZE9XUnWQSYrBObZxczut+8FZ5pdanm8nNS1DAo8zsrPuvGwn+U3fwU98WaiFsNrA4XHngesCGr8tEQ==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.44': - resolution: {integrity: sha512-cF1LJdDIX02cJrFrX3wwQ6IzFM7I74BYeKFkzdcIA4QZ0+2WA7/NsKIgjvrunupepWb1Y6PFWdRlHSaz5AW1Wg==} + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.45': + resolution: {integrity: sha512-zyzAjItHPUmxg6Z8SyRhLdXlJn3/D9KL5b9mObUrBHhWS/GwRH4665xCiFqeuktAhhWutqfc+rOV2LjK4VYQGQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.44': - resolution: {integrity: sha512-5uaJonDafhHiMn+iEh7qUp3QQ4Gihv3lEOxKfN8Vwadpy0e+5o28DWI42DpJ9YBYMrVy4JOWJ/3etB/sptpUwA==} + '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.45': + resolution: {integrity: sha512-wODcGzlfxqS6D7BR0srkJk3drPwXYLu7jPHN27ce2c4PUnVVmJnp9mJzUQGT4LpmHmmVdMZ+P6hKvyTGBzc1CA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.44': - resolution: {integrity: sha512-vsqhWAFJkkmgfBN/lkLCWTXF1PuPhMjfnAyru48KvF7mVh2+K7WkKYHezF3Fjz4X/mPScOcIv+g6cf6wnI6eWg==} + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.45': + resolution: {integrity: sha512-wiU40G1nQo9rtfvF9jLbl79lUgjfaD/LTyUEw2Wg/gdF5OhjzpKMVugZQngO+RNdwYaNj+Fs+kWBWfp4VXPMHA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@rolldown/pluginutils@1.0.0-beta.44': - resolution: {integrity: sha512-g6eW7Zwnr2c5RADIoqziHoVs6b3W5QTQ4+qbpfjbkMJ9x+8Og211VW/oot2dj9dVwaK/UyC6Yo+02gV+wWQVNg==} + '@rolldown/pluginutils@1.0.0-beta.45': + resolution: {integrity: sha512-Le9ulGCrD8ggInzWw/k2J8QcbPz7eGIOWqfJ2L+1R0Opm7n6J37s2hiDWlh6LJN0Lk9L5sUzMvRHKW7UxBZsQA==} '@rollup/rollup-android-arm-eabi@4.52.5': resolution: {integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==} @@ -843,6 +833,9 @@ packages: peerDependencies: eslint: '>=9.0.0' + '@toon-format/spec@1.3.0': + resolution: {integrity: sha512-uZrR+aML7i6K1Lt8pedx24rxLKZbg2NjcDO/jVuBqjfQ/Is1kKHpyMMwCg88zQuXGQIgjogh7MbsNkmD5WNlxQ==} + '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} @@ -867,8 +860,8 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@24.9.1': - resolution: {integrity: sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==} + '@types/node@24.9.2': + resolution: {integrity: sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==} '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} @@ -936,8 +929,8 @@ packages: resolution: {integrity: sha512-yNEQvPcVrK9sIe637+I0jD6leluPxzwJKx/Haw6F4H77CdDsszUn5V3o96LPziXkSNE2B83+Z3mjqGKBK/R6Gg==} engines: {node: '>= 20'} - '@vitest/eslint-plugin@1.3.25': - resolution: {integrity: sha512-7qM/FrA2VyUmrorP0TQ/Oqhn6wsAcktg6euBn0XmpgF0yT2mDxjziu2QLy86i2mOJ41Wtt55z6aUWo+bfmyAeg==} + '@vitest/eslint-plugin@1.4.0': + resolution: {integrity: sha512-TMzJ0Vqdsc71stblzI0ZdqSnt6Bp4mJ+amD3Hv3qhKK82hBUnznYfnLwA80gdGfe5V24ysndMOoSGrol6fyvbA==} engines: {node: '>=18'} peerDependencies: eslint: '>=8.57.0' @@ -949,11 +942,11 @@ packages: vitest: optional: true - '@vitest/expect@4.0.3': - resolution: {integrity: sha512-v3eSDx/bF25pzar6aEJrrdTXJduEBU3uSGXHslIdGIpJVP8tQQHV6x1ZfzbFQ/bLIomLSbR/2ZCfnaEGkWkiVQ==} + '@vitest/expect@4.0.6': + resolution: {integrity: sha512-5j8UUlBVhOjhj4lR2Nt9sEV8b4WtbcYh8vnfhTNA2Kn5+smtevzjNq+xlBuVhnFGXiyPPNzGrOVvmyHWkS5QGg==} - '@vitest/mocker@4.0.3': - resolution: {integrity: sha512-evZcRspIPbbiJEe748zI2BRu94ThCBE+RkjCpVF8yoVYuTV7hMe+4wLF/7K86r8GwJHSmAPnPbZhpXWWrg1qbA==} + '@vitest/mocker@4.0.6': + resolution: {integrity: sha512-3COEIew5HqdzBFEYN9+u0dT3i/NCwppLnO1HkjGfAP1Vs3vti1Hxm/MvcbC4DAn3Szo1M7M3otiAaT83jvqIjA==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0-0 @@ -963,20 +956,20 @@ packages: vite: optional: true - '@vitest/pretty-format@4.0.3': - resolution: {integrity: sha512-N7gly/DRXzxa9w9sbDXwD9QNFYP2hw90LLLGDobPNwiWgyW95GMxsCt29/COIKKh3P7XJICR38PSDePenMBtsw==} + '@vitest/pretty-format@4.0.6': + resolution: {integrity: sha512-4vptgNkLIA1W1Nn5X4x8rLJBzPiJwnPc+awKtfBE5hNMVsoAl/JCCPPzNrbf+L4NKgklsis5Yp2gYa+XAS442g==} - '@vitest/runner@4.0.3': - resolution: {integrity: sha512-1/aK6fPM0lYXWyGKwop2Gbvz1plyTps/HDbIIJXYtJtspHjpXIeB3If07eWpVH4HW7Rmd3Rl+IS/+zEAXrRtXA==} + '@vitest/runner@4.0.6': + resolution: {integrity: sha512-trPk5qpd7Jj+AiLZbV/e+KiiaGXZ8ECsRxtnPnCrJr9OW2mLB72Cb824IXgxVz/mVU3Aj4VebY+tDTPn++j1Og==} - '@vitest/snapshot@4.0.3': - resolution: {integrity: sha512-amnYmvZ5MTjNCP1HZmdeczAPLRD6iOm9+2nMRUGxbe/6sQ0Ymur0NnR9LIrWS8JA3wKE71X25D6ya/3LN9YytA==} + '@vitest/snapshot@4.0.6': + resolution: {integrity: sha512-PaYLt7n2YzuvxhulDDu6c9EosiRuIE+FI2ECKs6yvHyhoga+2TBWI8dwBjs+IeuQaMtZTfioa9tj3uZb7nev1g==} - '@vitest/spy@4.0.3': - resolution: {integrity: sha512-82vVL8Cqz7rbXaNUl35V2G7xeNMAjBdNOVaHbrzznT9BmiCiPOzhf0FhU3eP41nP1bLDm/5wWKZqkG4nyU95DQ==} + '@vitest/spy@4.0.6': + resolution: {integrity: sha512-g9jTUYPV1LtRPRCQfhbMintW7BTQz1n6WXYQYRQ25qkyffA4bjVXjkROokZnv7t07OqfaFKw1lPzqKGk1hmNuQ==} - '@vitest/utils@4.0.3': - resolution: {integrity: sha512-qV6KJkq8W3piW6MDIbGOmn1xhvcW4DuA07alqaQ+vdx7YA49J85pnwnxigZVQFQw3tWnQNRKWwhz5wbP6iv/GQ==} + '@vitest/utils@4.0.6': + resolution: {integrity: sha512-bG43VS3iYKrMIZXBo+y8Pti0O7uNju3KvNn6DrQWhQQKcLavMB+0NZfO1/QBAEbq0MaQ3QjNsnnXlGQvsh0Z6A==} '@vue/compiler-core@3.5.22': resolution: {integrity: sha512-jQ0pFPmZwTEiRNSb+i9Ow/I/cHv2tXYqsnHKKyCQ08irI2kdF5qmYedmF8si8mA7zepUFmJ2hqzS8CQmNOWOkQ==} @@ -1003,8 +996,8 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - ai@5.0.80: - resolution: {integrity: sha512-g1o6pjxm1eTtyh295dRhsg0gvZaHFlSo2oruWrK2rIR7KafWEhNB2A2/aJ9hyPT9AMI8JnQJyto1Tl9DMqwc9w==} + ai@5.0.86: + resolution: {integrity: sha512-ooHwNTkLdedFf98iQhtSc5btc/P4UuXuOpYneoifq0190vqosLunNdW8Hs6CiE0Am7YOGNplDK56JIPlHZIL4w==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 @@ -1049,8 +1042,8 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - baseline-browser-mapping@2.8.20: - resolution: {integrity: sha512-JMWsdF+O8Orq3EMukbUN1QfbLK9mX2CkUmQBcW2T0s8OmdAUL5LLM/6wFwSrqXzlXB13yhyK9gTKS1rIizOduQ==} + baseline-browser-mapping@2.8.23: + resolution: {integrity: sha512-616V5YX4bepJFzNyOfce5Fa8fDJMfoxzOIzDCZwaGL8MKVpFrXqfNUoIpRn9YMI5pXf/VKgzjB4htFMsFKKdiQ==} hasBin: true birpc@2.6.1: @@ -1099,8 +1092,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001751: - resolution: {integrity: sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==} + caniuse-lite@1.0.30001753: + resolution: {integrity: sha512-Bj5H35MD/ebaOV4iDLqPEtiliTN29qkGtEHCwawWn4cYm+bPJM2NsaP30vtZcnERClMzp52J4+aw2UNbK4o+zw==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -1237,8 +1230,8 @@ packages: oxc-resolver: optional: true - electron-to-chromium@1.5.240: - resolution: {integrity: sha512-OBwbZjWgrCOH+g6uJsA2/7Twpas2OlepS9uvByJjR2datRDuKGYeD+nP8lBBks2qnB7bGJNHDUx7c/YLaT3QMQ==} + electron-to-chromium@1.5.244: + resolution: {integrity: sha512-OszpBN7xZX4vWMPJwB9illkN/znA8M36GQqQxi6MNy9axWxhOfJyZZJtSLQCpEFLHP2xK33BiWx9aIuIEXVCcw==} empathic@2.0.0: resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} @@ -1255,8 +1248,8 @@ packages: es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - esbuild@0.25.11: - resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==} + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} engines: {node: '>=18'} hasBin: true @@ -1338,8 +1331,8 @@ packages: typescript: optional: true - eslint-plugin-jsdoc@61.1.9: - resolution: {integrity: sha512-X2AzSGbq1CzBRgKcVAu2qzOV9ogqygkUDk5AX6eNK5G+kY3I5Op5E5b99fE+FN0/bGnk2KGcsMIG6ZLF+di69A==} + eslint-plugin-jsdoc@61.1.11: + resolution: {integrity: sha512-c+NQQOFd+ZTjFt0pfFMB8OTumExg0vf8mlJsOtLj6qTDGewtLh7bhwoDgBg6rIiTziYc8N4u4dYmSdAIn0yTEQ==} engines: {node: '>=20.11.0'} peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 @@ -1383,11 +1376,11 @@ packages: peerDependencies: eslint: '>=6.0.0' - eslint-plugin-unicorn@61.0.2: - resolution: {integrity: sha512-zLihukvneYT7f74GNbVJXfWIiNQmkc/a9vYBTE4qPkQZswolWNdu+Wsp9sIXno1JOzdn6OUwLPd19ekXVkahRA==} + eslint-plugin-unicorn@62.0.0: + resolution: {integrity: sha512-HIlIkGLkvf29YEiS/ImuDZQbP12gWyx5i3C6XrRxMvVdqMroCI9qoVYCoIl17ChN+U89pn9sVwLxhIWj5nEc7g==} engines: {node: ^20.10.0 || >=21.0.0} peerDependencies: - eslint: '>=9.29.0' + eslint: '>=9.38.0' eslint-plugin-unused-imports@4.3.0: resolution: {integrity: sha512-ZFBmXMGBYfHttdRtOG9nFFpmUvMtbHSjsKrS20vdWdbfiVYsO3yA2SGYy9i9XmZJDfMGBflZGBCm70SEnFQtOA==} @@ -1436,8 +1429,8 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.38.0: - resolution: {integrity: sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==} + eslint@9.39.0: + resolution: {integrity: sha512-iy2GE3MHrYTL5lrCtMZ0X1KLEKKUjmK0kzwcnefhR66txcEmXZD2YWgR5GNdcEwkNx3a0siYkSvl0vIC+Svjmg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -1584,8 +1577,8 @@ packages: resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} engines: {node: '>=18'} - globals@16.4.0: - resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} + globals@16.5.0: + resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} engines: {node: '>=18'} globrex@0.1.2: @@ -1675,11 +1668,6 @@ packages: resolution: {integrity: sha512-+LexoTRyYui5iOhJGn13N9ZazL23nAHGkXsa1p/C8yeq79WRfLBag6ZZ0FQG2aRoc9yfo59JT9EYCQonOkHKkQ==} engines: {node: '>=20.0.0'} - jsesc@3.0.2: - resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} - engines: {node: '>=6'} - hasBin: true - jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -1914,8 +1902,8 @@ packages: node-mock-http@1.0.3: resolution: {integrity: sha512-jN8dK25fsfnMrVsEhluUTPkBFY+6ybu7jSB1n+ri/vOGjJxU8J9CZhpSGkHXSkFjtUhbmoncG/YG9ta5Ludqog==} - node-releases@2.0.26: - resolution: {integrity: sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==} + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} @@ -1932,8 +1920,8 @@ packages: object-deep-merge@2.0.0: resolution: {integrity: sha512-3DC3UMpeffLTHiuXSy/UG4NOIYTLlY9u3V82+djSCLYClWobZiS4ivYzpIUWrRY/nfsJ8cWsKyG3QfyLePmhvg==} - ofetch@1.4.1: - resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==} + ofetch@1.5.1: + resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} ohash@2.0.11: resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} @@ -2061,8 +2049,8 @@ packages: resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} hasBin: true - regjsparser@0.12.0: - resolution: {integrity: sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==} + regjsparser@0.13.0: + resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==} hasBin: true reserved-identifiers@1.2.0: @@ -2080,8 +2068,8 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rolldown-plugin-dts@0.17.1: - resolution: {integrity: sha512-dQfoYD9kwSau7UQPg0UubprCDcwWeEKYd9SU9O2MpOdKy3VHy3/DaDF+x6w9+KE/w6J8qxkHVjwG1K2QmmQAFA==} + rolldown-plugin-dts@0.17.3: + resolution: {integrity: sha512-8mGnNUVNrqEdTnrlcaDxs4sAZg0No6njO+FuhQd4L56nUbJO1tHxOoKDH3mmMJg7f/BhEj/1KjU5W9kZ9zM/kQ==} engines: {node: '>=20.18.0'} peerDependencies: '@ts-macro/tsc': ^0.3.6 @@ -2099,8 +2087,8 @@ packages: vue-tsc: optional: true - rolldown@1.0.0-beta.44: - resolution: {integrity: sha512-gcqgyCi3g93Fhr49PKvymE8PoaGS0sf6ajQrsYaQ8o5de6aUEbD6rJZiJbhOfpcqOnycgsAsUNPYri1h25NgsQ==} + rolldown@1.0.0-beta.45: + resolution: {integrity: sha512-iMmuD72XXLf26Tqrv1cryNYLX6NNPLhZ3AmNkSf8+xda0H+yijjGJ+wVT9UdBUHOpKzq9RjKtQKRCWoEKQQBZQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -2227,8 +2215,8 @@ packages: peerDependencies: typescript: '>=4.0.0' - tsdown@0.15.10: - resolution: {integrity: sha512-8zbSN4GW7ZzhjIYl/rWrruGzl1cJiDtAjb8l5XVF2cVme1+aDLVcExw+Ph4gNcfdGg6ZfYPh5kmcpIfh5xHisw==} + tsdown@0.15.12: + resolution: {integrity: sha512-c8VLlQm8/lFrOAg5VMVeN4NAbejZyVQkzd+ErjuaQgJFI/9MhR9ivr0H/CM7UlOF1+ELlF6YaI7sU/4itgGQ8w==} engines: {node: '>=20.19.0'} hasBin: true peerDependencies: @@ -2237,6 +2225,7 @@ packages: typescript: ^5.0.0 unplugin-lightningcss: ^0.4.0 unplugin-unused: ^0.5.0 + unrun: ^0.2.1 peerDependenciesMeta: '@arethetypeswrong/core': optional: true @@ -2248,6 +2237,8 @@ packages: optional: true unplugin-unused: optional: true + unrun: + optional: true tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -2290,13 +2281,8 @@ packages: unist-util-visit@5.0.0: resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} - unrun@0.2.0: - resolution: {integrity: sha512-iaCxWG/6kmjP3wUTBheowjFm6LuI8fd/A3Uz7DbMoz8HvQsJThh7tWZKWJfVltOSK3LuIJFzepr7g6fbuhUasw==} - engines: {node: '>=20.19.0'} - hasBin: true - - unstorage@1.17.1: - resolution: {integrity: sha512-KKGwRTT0iVBCErKemkJCLs7JdxNVfqTPc/85ae1XES0+bsHbc/sFBfVi5kJp156cc51BHinIH2l3k0EZ24vOBQ==} + unstorage@1.17.2: + resolution: {integrity: sha512-cKEsD6iBWJgOMJ6vW1ID/SYuqNf8oN4yqRk8OYqaVQ3nnkJXOT1PSpaMh2QfzLs78UN5kSNRD2c/mgjT8tX7+w==} peerDependencies: '@azure/app-configuration': ^1.8.0 '@azure/cosmos': ^4.2.0 @@ -2413,18 +2399,18 @@ packages: yaml: optional: true - vitest@4.0.3: - resolution: {integrity: sha512-IUSop8jgaT7w0g1yOM/35qVtKjr/8Va4PrjzH1OUb0YH4c3OXB2lCZDkMAB6glA8T5w8S164oJGsbcmAecr4sA==} + 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': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.3 - '@vitest/browser-preview': 4.0.3 - '@vitest/browser-webdriverio': 4.0.3 - '@vitest/ui': 4.0.3 + '@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: @@ -2492,45 +2478,38 @@ packages: snapshots: - '@ai-sdk/anthropic@2.0.37(zod@4.1.12)': + '@ai-sdk/anthropic@2.0.40(zod@4.1.12)': dependencies: '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.12(zod@4.1.12) + '@ai-sdk/provider-utils': 3.0.15(zod@4.1.12) zod: 4.1.12 - '@ai-sdk/gateway@2.0.1(zod@4.1.12)': + '@ai-sdk/gateway@2.0.5(zod@4.1.12)': dependencies: '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.12(zod@4.1.12) + '@ai-sdk/provider-utils': 3.0.15(zod@4.1.12) '@vercel/oidc': 3.0.3 zod: 4.1.12 - '@ai-sdk/google@2.0.23(zod@4.1.12)': + '@ai-sdk/google@2.0.26(zod@4.1.12)': dependencies: '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.12(zod@4.1.12) + '@ai-sdk/provider-utils': 3.0.15(zod@4.1.12) zod: 4.1.12 - '@ai-sdk/openai-compatible@1.0.23(zod@4.1.12)': + '@ai-sdk/openai-compatible@1.0.25(zod@4.1.12)': dependencies: '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.13(zod@4.1.12) + '@ai-sdk/provider-utils': 3.0.15(zod@4.1.12) zod: 4.1.12 - '@ai-sdk/openai@2.0.53(zod@4.1.12)': + '@ai-sdk/openai@2.0.59(zod@4.1.12)': dependencies: '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.12(zod@4.1.12) + '@ai-sdk/provider-utils': 3.0.15(zod@4.1.12) zod: 4.1.12 - '@ai-sdk/provider-utils@3.0.12(zod@4.1.12)': - dependencies: - '@ai-sdk/provider': 2.0.0 - '@standard-schema/spec': 1.0.0 - eventsource-parser: 3.0.6 - zod: 4.1.12 - - '@ai-sdk/provider-utils@3.0.13(zod@4.1.12)': + '@ai-sdk/provider-utils@3.0.15(zod@4.1.12)': dependencies: '@ai-sdk/provider': 2.0.0 '@standard-schema/spec': 1.0.0 @@ -2541,51 +2520,51 @@ snapshots: dependencies: json-schema: 0.4.0 - '@ai-sdk/xai@2.0.28(zod@4.1.12)': + '@ai-sdk/xai@2.0.30(zod@4.1.12)': dependencies: - '@ai-sdk/openai-compatible': 1.0.23(zod@4.1.12) + '@ai-sdk/openai-compatible': 1.0.25(zod@4.1.12) '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.13(zod@4.1.12) + '@ai-sdk/provider-utils': 3.0.15(zod@4.1.12) zod: 4.1.12 - '@antfu/eslint-config@6.1.0(@vue/compiler-sfc@3.5.22)(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.3(@types/debug@4.1.12)(@types/node@24.9.1)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1))': + '@antfu/eslint-config@6.2.0(@vue/compiler-sfc@3.5.22)(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.6(@types/debug@4.1.12)(@types/node@24.9.2)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1))': dependencies: '@antfu/install-pkg': 1.1.0 '@clack/prompts': 0.11.0 - '@eslint-community/eslint-plugin-eslint-comments': 4.5.0(eslint@9.38.0(jiti@2.6.1)) + '@eslint-community/eslint-plugin-eslint-comments': 4.5.0(eslint@9.39.0(jiti@2.6.1)) '@eslint/markdown': 7.5.0 - '@stylistic/eslint-plugin': 5.5.0(eslint@9.38.0(jiti@2.6.1)) - '@typescript-eslint/eslint-plugin': 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) - '@vitest/eslint-plugin': 1.3.25(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.3(@types/debug@4.1.12)(@types/node@24.9.1)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1)) + '@stylistic/eslint-plugin': 5.5.0(eslint@9.39.0(jiti@2.6.1)) + '@typescript-eslint/eslint-plugin': 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + '@vitest/eslint-plugin': 1.4.0(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.6(@types/debug@4.1.12)(@types/node@24.9.2)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1)) ansis: 4.2.0 cac: 6.7.14 - eslint: 9.38.0(jiti@2.6.1) - eslint-config-flat-gitignore: 2.1.0(eslint@9.38.0(jiti@2.6.1)) + eslint: 9.39.0(jiti@2.6.1) + eslint-config-flat-gitignore: 2.1.0(eslint@9.39.0(jiti@2.6.1)) eslint-flat-config-utils: 2.1.4 - eslint-merge-processors: 2.0.0(eslint@9.38.0(jiti@2.6.1)) - eslint-plugin-antfu: 3.1.1(eslint@9.38.0(jiti@2.6.1)) - eslint-plugin-command: 3.3.1(eslint@9.38.0(jiti@2.6.1)) - eslint-plugin-import-lite: 0.3.0(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-jsdoc: 61.1.9(eslint@9.38.0(jiti@2.6.1)) - eslint-plugin-jsonc: 2.21.0(eslint@9.38.0(jiti@2.6.1)) - eslint-plugin-n: 17.23.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + eslint-merge-processors: 2.0.0(eslint@9.39.0(jiti@2.6.1)) + eslint-plugin-antfu: 3.1.1(eslint@9.39.0(jiti@2.6.1)) + eslint-plugin-command: 3.3.1(eslint@9.39.0(jiti@2.6.1)) + eslint-plugin-import-lite: 0.3.0(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + eslint-plugin-jsdoc: 61.1.11(eslint@9.39.0(jiti@2.6.1)) + eslint-plugin-jsonc: 2.21.0(eslint@9.39.0(jiti@2.6.1)) + eslint-plugin-n: 17.23.1(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) eslint-plugin-no-only-tests: 3.3.0 - eslint-plugin-perfectionist: 4.15.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-pnpm: 1.3.0(eslint@9.38.0(jiti@2.6.1)) - eslint-plugin-regexp: 2.10.0(eslint@9.38.0(jiti@2.6.1)) - eslint-plugin-toml: 0.12.0(eslint@9.38.0(jiti@2.6.1)) - eslint-plugin-unicorn: 61.0.2(eslint@9.38.0(jiti@2.6.1)) - eslint-plugin-unused-imports: 4.3.0(@typescript-eslint/eslint-plugin@8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1)) - eslint-plugin-vue: 10.5.1(@stylistic/eslint-plugin@5.5.0(eslint@9.38.0(jiti@2.6.1)))(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.38.0(jiti@2.6.1))) - eslint-plugin-yml: 1.19.0(eslint@9.38.0(jiti@2.6.1)) - eslint-processor-vue-blocks: 2.0.0(@vue/compiler-sfc@3.5.22)(eslint@9.38.0(jiti@2.6.1)) - globals: 16.4.0 + eslint-plugin-perfectionist: 4.15.1(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + eslint-plugin-pnpm: 1.3.0(eslint@9.39.0(jiti@2.6.1)) + eslint-plugin-regexp: 2.10.0(eslint@9.39.0(jiti@2.6.1)) + eslint-plugin-toml: 0.12.0(eslint@9.39.0(jiti@2.6.1)) + eslint-plugin-unicorn: 62.0.0(eslint@9.39.0(jiti@2.6.1)) + eslint-plugin-unused-imports: 4.3.0(@typescript-eslint/eslint-plugin@8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.0(jiti@2.6.1)) + eslint-plugin-vue: 10.5.1(@stylistic/eslint-plugin@5.5.0(eslint@9.39.0(jiti@2.6.1)))(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.0(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.0(jiti@2.6.1))) + eslint-plugin-yml: 1.19.0(eslint@9.39.0(jiti@2.6.1)) + eslint-processor-vue-blocks: 2.0.0(@vue/compiler-sfc@3.5.22)(eslint@9.39.0(jiti@2.6.1)) + globals: 16.5.0 jsonc-eslint-parser: 2.4.1 local-pkg: 1.1.2 parse-gitignore: 2.0.0 toml-eslint-parser: 0.10.0 - vue-eslint-parser: 10.2.0(eslint@9.38.0(jiti@2.6.1)) + vue-eslint-parser: 10.2.0(eslint@9.39.0(jiti@2.6.1)) yaml-eslint-parser: 1.3.0 transitivePeerDependencies: - '@eslint/json' @@ -2665,104 +2644,104 @@ snapshots: esquery: 1.6.0 jsdoc-type-pratt-parser: 6.10.0 - '@es-joy/resolve.exports@1.0.0': {} + '@es-joy/resolve.exports@1.2.0': {} - '@esbuild/aix-ppc64@0.25.11': + '@esbuild/aix-ppc64@0.25.12': optional: true - '@esbuild/android-arm64@0.25.11': + '@esbuild/android-arm64@0.25.12': optional: true - '@esbuild/android-arm@0.25.11': + '@esbuild/android-arm@0.25.12': optional: true - '@esbuild/android-x64@0.25.11': + '@esbuild/android-x64@0.25.12': optional: true - '@esbuild/darwin-arm64@0.25.11': + '@esbuild/darwin-arm64@0.25.12': optional: true - '@esbuild/darwin-x64@0.25.11': + '@esbuild/darwin-x64@0.25.12': optional: true - '@esbuild/freebsd-arm64@0.25.11': + '@esbuild/freebsd-arm64@0.25.12': optional: true - '@esbuild/freebsd-x64@0.25.11': + '@esbuild/freebsd-x64@0.25.12': optional: true - '@esbuild/linux-arm64@0.25.11': + '@esbuild/linux-arm64@0.25.12': optional: true - '@esbuild/linux-arm@0.25.11': + '@esbuild/linux-arm@0.25.12': optional: true - '@esbuild/linux-ia32@0.25.11': + '@esbuild/linux-ia32@0.25.12': optional: true - '@esbuild/linux-loong64@0.25.11': + '@esbuild/linux-loong64@0.25.12': optional: true - '@esbuild/linux-mips64el@0.25.11': + '@esbuild/linux-mips64el@0.25.12': optional: true - '@esbuild/linux-ppc64@0.25.11': + '@esbuild/linux-ppc64@0.25.12': optional: true - '@esbuild/linux-riscv64@0.25.11': + '@esbuild/linux-riscv64@0.25.12': optional: true - '@esbuild/linux-s390x@0.25.11': + '@esbuild/linux-s390x@0.25.12': optional: true - '@esbuild/linux-x64@0.25.11': + '@esbuild/linux-x64@0.25.12': optional: true - '@esbuild/netbsd-arm64@0.25.11': + '@esbuild/netbsd-arm64@0.25.12': optional: true - '@esbuild/netbsd-x64@0.25.11': + '@esbuild/netbsd-x64@0.25.12': optional: true - '@esbuild/openbsd-arm64@0.25.11': + '@esbuild/openbsd-arm64@0.25.12': optional: true - '@esbuild/openbsd-x64@0.25.11': + '@esbuild/openbsd-x64@0.25.12': optional: true - '@esbuild/openharmony-arm64@0.25.11': + '@esbuild/openharmony-arm64@0.25.12': optional: true - '@esbuild/sunos-x64@0.25.11': + '@esbuild/sunos-x64@0.25.12': optional: true - '@esbuild/win32-arm64@0.25.11': + '@esbuild/win32-arm64@0.25.12': optional: true - '@esbuild/win32-ia32@0.25.11': + '@esbuild/win32-ia32@0.25.12': optional: true - '@esbuild/win32-x64@0.25.11': + '@esbuild/win32-x64@0.25.12': optional: true - '@eslint-community/eslint-plugin-eslint-comments@4.5.0(eslint@9.38.0(jiti@2.6.1))': + '@eslint-community/eslint-plugin-eslint-comments@4.5.0(eslint@9.39.0(jiti@2.6.1))': dependencies: escape-string-regexp: 4.0.0 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) ignore: 5.3.2 - '@eslint-community/eslint-utils@4.9.0(eslint@9.38.0(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.0(jiti@2.6.1))': dependencies: - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/compat@1.4.0(eslint@9.38.0(jiti@2.6.1))': + '@eslint/compat@1.4.1(eslint@9.39.0(jiti@2.6.1))': dependencies: - '@eslint/core': 0.16.0 + '@eslint/core': 0.17.0 optionalDependencies: - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) '@eslint/config-array@0.21.1': dependencies: @@ -2772,15 +2751,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/config-helpers@0.4.1': + '@eslint/config-helpers@0.4.2': dependencies: - '@eslint/core': 0.16.0 + '@eslint/core': 0.17.0 - '@eslint/core@0.15.2': + '@eslint/core@0.16.0': dependencies: '@types/json-schema': 7.0.15 - '@eslint/core@0.16.0': + '@eslint/core@0.17.0': dependencies: '@types/json-schema': 7.0.15 @@ -2798,12 +2777,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.38.0': {} + '@eslint/js@9.39.0': {} '@eslint/markdown@7.5.0': dependencies: '@eslint/core': 0.16.0 - '@eslint/plugin-kit': 0.4.0 + '@eslint/plugin-kit': 0.4.1 github-slugger: 2.0.0 mdast-util-from-markdown: 2.0.2 mdast-util-frontmatter: 2.0.1 @@ -2816,14 +2795,9 @@ snapshots: '@eslint/object-schema@2.1.7': {} - '@eslint/plugin-kit@0.3.5': + '@eslint/plugin-kit@0.4.1': dependencies: - '@eslint/core': 0.15.2 - levn: 0.4.1 - - '@eslint/plugin-kit@0.4.0': - dependencies: - '@eslint/core': 0.16.0 + '@eslint/core': 0.17.0 levn: 0.4.1 '@faker-js/faker@10.1.0': {} @@ -2874,8 +2848,6 @@ snapshots: '@opentelemetry/api@1.9.0': {} - '@oxc-project/runtime@0.95.0': {} - '@oxc-project/types@0.95.0': {} '@parcel/watcher-android-arm64@2.5.1': @@ -2944,51 +2916,51 @@ snapshots: dependencies: quansync: 0.2.11 - '@rolldown/binding-android-arm64@1.0.0-beta.44': + '@rolldown/binding-android-arm64@1.0.0-beta.45': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-beta.44': + '@rolldown/binding-darwin-arm64@1.0.0-beta.45': optional: true - '@rolldown/binding-darwin-x64@1.0.0-beta.44': + '@rolldown/binding-darwin-x64@1.0.0-beta.45': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-beta.44': + '@rolldown/binding-freebsd-x64@1.0.0-beta.45': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.44': + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.45': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.44': + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.45': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.44': + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.45': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.44': + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.45': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-beta.44': + '@rolldown/binding-linux-x64-musl@1.0.0-beta.45': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-beta.44': + '@rolldown/binding-openharmony-arm64@1.0.0-beta.45': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-beta.44': + '@rolldown/binding-wasm32-wasi@1.0.0-beta.45': dependencies: '@napi-rs/wasm-runtime': 1.0.7 optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.44': + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.45': optional: true - '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.44': + '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.45': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.44': + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.45': optional: true - '@rolldown/pluginutils@1.0.0-beta.44': {} + '@rolldown/pluginutils@1.0.0-beta.45': {} '@rollup/rollup-android-arm-eabi@4.52.5': optional: true @@ -3060,16 +3032,18 @@ snapshots: '@standard-schema/spec@1.0.0': {} - '@stylistic/eslint-plugin@5.5.0(eslint@9.38.0(jiti@2.6.1))': + '@stylistic/eslint-plugin@5.5.0(eslint@9.39.0(jiti@2.6.1))': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@2.6.1)) '@typescript-eslint/types': 8.46.2 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) eslint-visitor-keys: 4.2.1 espree: 10.4.0 estraverse: 5.3.0 picomatch: 4.0.3 + '@toon-format/spec@1.3.0': {} + '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 @@ -3096,21 +3070,21 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node@24.9.1': + '@types/node@24.9.2': dependencies: undici-types: 7.16.0 '@types/unist@3.0.3': {} - '@typescript-eslint/eslint-plugin@8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.46.2 - '@typescript-eslint/type-utils': 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/type-utils': 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.46.2 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 @@ -3119,14 +3093,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.46.2 '@typescript-eslint/types': 8.46.2 '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.46.2 debug: 4.4.3 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -3149,13 +3123,13 @@ snapshots: dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.46.2 '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.3 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) ts-api-utils: 2.1.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: @@ -3179,13 +3153,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@2.6.1)) '@typescript-eslint/scope-manager': 8.46.2 '@typescript-eslint/types': 8.46.2 '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3) - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -3197,54 +3171,54 @@ snapshots: '@vercel/oidc@3.0.3': {} - '@vitest/eslint-plugin@1.3.25(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.3(@types/debug@4.1.12)(@types/node@24.9.1)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1))': + '@vitest/eslint-plugin@1.4.0(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.6(@types/debug@4.1.12)(@types/node@24.9.2)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1))': dependencies: '@typescript-eslint/scope-manager': 8.46.2 - '@typescript-eslint/utils': 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.38.0(jiti@2.6.1) + '@typescript-eslint/utils': 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.0(jiti@2.6.1) optionalDependencies: typescript: 5.9.3 - vitest: 4.0.3(@types/debug@4.1.12)(@types/node@24.9.1)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1) + vitest: 4.0.6(@types/debug@4.1.12)(@types/node@24.9.2)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1) transitivePeerDependencies: - supports-color - '@vitest/expect@4.0.3': + '@vitest/expect@4.0.6': dependencies: '@standard-schema/spec': 1.0.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.0.3 - '@vitest/utils': 4.0.3 + '@vitest/spy': 4.0.6 + '@vitest/utils': 4.0.6 chai: 6.2.0 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.3(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1))': + '@vitest/mocker@4.0.6(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1))': dependencies: - '@vitest/spy': 4.0.3 + '@vitest/spy': 4.0.6 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.1.12(@types/node@24.9.1)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1) + vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1) - '@vitest/pretty-format@4.0.3': + '@vitest/pretty-format@4.0.6': dependencies: tinyrainbow: 3.0.3 - '@vitest/runner@4.0.3': + '@vitest/runner@4.0.6': dependencies: - '@vitest/utils': 4.0.3 + '@vitest/utils': 4.0.6 pathe: 2.0.3 - '@vitest/snapshot@4.0.3': + '@vitest/snapshot@4.0.6': dependencies: - '@vitest/pretty-format': 4.0.3 + '@vitest/pretty-format': 4.0.6 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.0.3': {} + '@vitest/spy@4.0.6': {} - '@vitest/utils@4.0.3': + '@vitest/utils@4.0.6': dependencies: - '@vitest/pretty-format': 4.0.3 + '@vitest/pretty-format': 4.0.6 tinyrainbow: 3.0.3 '@vue/compiler-core@3.5.22': @@ -3285,11 +3259,11 @@ snapshots: acorn@8.15.0: {} - ai@5.0.80(zod@4.1.12): + ai@5.0.86(zod@4.1.12): dependencies: - '@ai-sdk/gateway': 2.0.1(zod@4.1.12) + '@ai-sdk/gateway': 2.0.5(zod@4.1.12) '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.12(zod@4.1.12) + '@ai-sdk/provider-utils': 3.0.15(zod@4.1.12) '@opentelemetry/api': 1.9.0 zod: 4.1.12 @@ -3336,7 +3310,7 @@ snapshots: magic-string: 0.30.21 mdbox: 0.1.1 mlly: 1.8.0 - ofetch: 1.4.1 + ofetch: 1.5.1 pathe: 2.0.3 perfect-debounce: 2.0.0 pkg-types: 2.3.0 @@ -3348,7 +3322,7 @@ snapshots: balanced-match@1.0.2: {} - baseline-browser-mapping@2.8.20: {} + baseline-browser-mapping@2.8.23: {} birpc@2.6.1: {} @@ -3369,10 +3343,10 @@ snapshots: browserslist@4.27.0: dependencies: - baseline-browser-mapping: 2.8.20 - caniuse-lite: 1.0.30001751 - electron-to-chromium: 1.5.240 - node-releases: 2.0.26 + baseline-browser-mapping: 2.8.23 + caniuse-lite: 1.0.30001753 + electron-to-chromium: 1.5.244 + node-releases: 2.0.27 update-browserslist-db: 1.1.4(browserslist@4.27.0) builtin-modules@5.0.0: {} @@ -3412,7 +3386,7 @@ snapshots: callsites@3.1.0: {} - caniuse-lite@1.0.30001751: {} + caniuse-lite@1.0.30001753: {} ccount@2.0.1: {} @@ -3513,7 +3487,7 @@ snapshots: dts-resolver@2.1.2: {} - electron-to-chromium@1.5.240: {} + electron-to-chromium@1.5.244: {} empathic@2.0.0: {} @@ -3526,34 +3500,34 @@ snapshots: es-module-lexer@1.7.0: {} - esbuild@0.25.11: + esbuild@0.25.12: optionalDependencies: - '@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 + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 escalade@3.2.0: {} @@ -3563,68 +3537,68 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-compat-utils@0.5.1(eslint@9.38.0(jiti@2.6.1)): + eslint-compat-utils@0.5.1(eslint@9.39.0(jiti@2.6.1)): dependencies: - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) semver: 7.7.3 - eslint-compat-utils@0.6.5(eslint@9.38.0(jiti@2.6.1)): + eslint-compat-utils@0.6.5(eslint@9.39.0(jiti@2.6.1)): dependencies: - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) semver: 7.7.3 - eslint-config-flat-gitignore@2.1.0(eslint@9.38.0(jiti@2.6.1)): + eslint-config-flat-gitignore@2.1.0(eslint@9.39.0(jiti@2.6.1)): dependencies: - '@eslint/compat': 1.4.0(eslint@9.38.0(jiti@2.6.1)) - eslint: 9.38.0(jiti@2.6.1) + '@eslint/compat': 1.4.1(eslint@9.39.0(jiti@2.6.1)) + eslint: 9.39.0(jiti@2.6.1) eslint-flat-config-utils@2.1.4: dependencies: pathe: 2.0.3 - eslint-json-compat-utils@0.2.1(eslint@9.38.0(jiti@2.6.1))(jsonc-eslint-parser@2.4.1): + eslint-json-compat-utils@0.2.1(eslint@9.39.0(jiti@2.6.1))(jsonc-eslint-parser@2.4.1): dependencies: - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) esquery: 1.6.0 jsonc-eslint-parser: 2.4.1 - eslint-merge-processors@2.0.0(eslint@9.38.0(jiti@2.6.1)): + eslint-merge-processors@2.0.0(eslint@9.39.0(jiti@2.6.1)): dependencies: - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) - eslint-plugin-antfu@3.1.1(eslint@9.38.0(jiti@2.6.1)): + eslint-plugin-antfu@3.1.1(eslint@9.39.0(jiti@2.6.1)): dependencies: - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) - eslint-plugin-command@3.3.1(eslint@9.38.0(jiti@2.6.1)): + eslint-plugin-command@3.3.1(eslint@9.39.0(jiti@2.6.1)): dependencies: '@es-joy/jsdoccomment': 0.50.2 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) - eslint-plugin-es-x@7.8.0(eslint@9.38.0(jiti@2.6.1)): + eslint-plugin-es-x@7.8.0(eslint@9.39.0(jiti@2.6.1)): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 - eslint: 9.38.0(jiti@2.6.1) - eslint-compat-utils: 0.5.1(eslint@9.38.0(jiti@2.6.1)) + eslint: 9.39.0(jiti@2.6.1) + eslint-compat-utils: 0.5.1(eslint@9.39.0(jiti@2.6.1)) - eslint-plugin-import-lite@0.3.0(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3): + eslint-plugin-import-lite@0.3.0(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@2.6.1)) '@typescript-eslint/types': 8.46.2 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) optionalDependencies: typescript: 5.9.3 - eslint-plugin-jsdoc@61.1.9(eslint@9.38.0(jiti@2.6.1)): + eslint-plugin-jsdoc@61.1.11(eslint@9.39.0(jiti@2.6.1)): dependencies: '@es-joy/jsdoccomment': 0.76.0 - '@es-joy/resolve.exports': 1.0.0 + '@es-joy/resolve.exports': 1.2.0 are-docs-informative: 0.0.2 comment-parser: 1.4.1 debug: 4.4.3 escape-string-regexp: 4.0.0 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) espree: 10.4.0 esquery: 1.6.0 html-entities: 2.6.0 @@ -3636,13 +3610,13 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-jsonc@2.21.0(eslint@9.38.0(jiti@2.6.1)): + eslint-plugin-jsonc@2.21.0(eslint@9.39.0(jiti@2.6.1)): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@2.6.1)) diff-sequences: 27.5.1 - eslint: 9.38.0(jiti@2.6.1) - eslint-compat-utils: 0.6.5(eslint@9.38.0(jiti@2.6.1)) - eslint-json-compat-utils: 0.2.1(eslint@9.38.0(jiti@2.6.1))(jsonc-eslint-parser@2.4.1) + eslint: 9.39.0(jiti@2.6.1) + eslint-compat-utils: 0.6.5(eslint@9.39.0(jiti@2.6.1)) + eslint-json-compat-utils: 0.2.1(eslint@9.39.0(jiti@2.6.1))(jsonc-eslint-parser@2.4.1) espree: 10.4.0 graphemer: 1.4.0 jsonc-eslint-parser: 2.4.1 @@ -3651,12 +3625,12 @@ snapshots: transitivePeerDependencies: - '@eslint/json' - eslint-plugin-n@17.23.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3): + eslint-plugin-n@17.23.1(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@2.6.1)) enhanced-resolve: 5.18.3 - eslint: 9.38.0(jiti@2.6.1) - eslint-plugin-es-x: 7.8.0(eslint@9.38.0(jiti@2.6.1)) + eslint: 9.39.0(jiti@2.6.1) + eslint-plugin-es-x: 7.8.0(eslint@9.39.0(jiti@2.6.1)) get-tsconfig: 4.13.0 globals: 15.15.0 globrex: 0.1.2 @@ -3668,105 +3642,105 @@ snapshots: eslint-plugin-no-only-tests@3.3.0: {} - eslint-plugin-perfectionist@4.15.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3): + eslint-plugin-perfectionist@4.15.1(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3): dependencies: '@typescript-eslint/types': 8.46.2 - '@typescript-eslint/utils': 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.38.0(jiti@2.6.1) + '@typescript-eslint/utils': 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.0(jiti@2.6.1) natural-orderby: 5.0.0 transitivePeerDependencies: - supports-color - typescript - eslint-plugin-pnpm@1.3.0(eslint@9.38.0(jiti@2.6.1)): + eslint-plugin-pnpm@1.3.0(eslint@9.39.0(jiti@2.6.1)): dependencies: empathic: 2.0.0 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) jsonc-eslint-parser: 2.4.1 pathe: 2.0.3 pnpm-workspace-yaml: 1.3.0 tinyglobby: 0.2.15 yaml-eslint-parser: 1.3.0 - eslint-plugin-regexp@2.10.0(eslint@9.38.0(jiti@2.6.1)): + eslint-plugin-regexp@2.10.0(eslint@9.39.0(jiti@2.6.1)): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 comment-parser: 1.4.1 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) jsdoc-type-pratt-parser: 4.8.0 refa: 0.12.1 regexp-ast-analysis: 0.7.1 scslre: 0.3.0 - eslint-plugin-toml@0.12.0(eslint@9.38.0(jiti@2.6.1)): + eslint-plugin-toml@0.12.0(eslint@9.39.0(jiti@2.6.1)): dependencies: debug: 4.4.3 - eslint: 9.38.0(jiti@2.6.1) - eslint-compat-utils: 0.6.5(eslint@9.38.0(jiti@2.6.1)) + eslint: 9.39.0(jiti@2.6.1) + eslint-compat-utils: 0.6.5(eslint@9.39.0(jiti@2.6.1)) lodash: 4.17.21 toml-eslint-parser: 0.10.0 transitivePeerDependencies: - supports-color - eslint-plugin-unicorn@61.0.2(eslint@9.38.0(jiti@2.6.1)): + eslint-plugin-unicorn@62.0.0(eslint@9.39.0(jiti@2.6.1)): dependencies: '@babel/helper-validator-identifier': 7.28.5 - '@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0(jiti@2.6.1)) - '@eslint/plugin-kit': 0.3.5 + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@2.6.1)) + '@eslint/plugin-kit': 0.4.1 change-case: 5.4.4 ci-info: 4.3.1 clean-regexp: 1.0.0 core-js-compat: 3.46.0 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) esquery: 1.6.0 find-up-simple: 1.0.1 - globals: 16.4.0 + globals: 16.5.0 indent-string: 5.0.0 is-builtin-module: 5.0.0 jsesc: 3.1.0 pluralize: 8.0.0 regexp-tree: 0.1.27 - regjsparser: 0.12.0 + regjsparser: 0.13.0 semver: 7.7.3 strip-indent: 4.1.1 - eslint-plugin-unused-imports@4.3.0(@typescript-eslint/eslint-plugin@8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1)): + eslint-plugin-unused-imports@4.3.0(@typescript-eslint/eslint-plugin@8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.0(jiti@2.6.1)): dependencies: - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) optionalDependencies: - '@typescript-eslint/eslint-plugin': 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-vue@10.5.1(@stylistic/eslint-plugin@5.5.0(eslint@9.38.0(jiti@2.6.1)))(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.38.0(jiti@2.6.1))): + eslint-plugin-vue@10.5.1(@stylistic/eslint-plugin@5.5.0(eslint@9.39.0(jiti@2.6.1)))(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.0(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.0(jiti@2.6.1))): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0(jiti@2.6.1)) - eslint: 9.38.0(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@2.6.1)) + eslint: 9.39.0(jiti@2.6.1) natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 6.1.2 semver: 7.7.3 - vue-eslint-parser: 10.2.0(eslint@9.38.0(jiti@2.6.1)) + vue-eslint-parser: 10.2.0(eslint@9.39.0(jiti@2.6.1)) xml-name-validator: 4.0.0 optionalDependencies: - '@stylistic/eslint-plugin': 5.5.0(eslint@9.38.0(jiti@2.6.1)) - '@typescript-eslint/parser': 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + '@stylistic/eslint-plugin': 5.5.0(eslint@9.39.0(jiti@2.6.1)) + '@typescript-eslint/parser': 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-yml@1.19.0(eslint@9.38.0(jiti@2.6.1)): + eslint-plugin-yml@1.19.0(eslint@9.39.0(jiti@2.6.1)): dependencies: debug: 4.4.3 diff-sequences: 27.5.1 escape-string-regexp: 4.0.0 - eslint: 9.38.0(jiti@2.6.1) - eslint-compat-utils: 0.6.5(eslint@9.38.0(jiti@2.6.1)) + eslint: 9.39.0(jiti@2.6.1) + eslint-compat-utils: 0.6.5(eslint@9.39.0(jiti@2.6.1)) natural-compare: 1.4.0 yaml-eslint-parser: 1.3.0 transitivePeerDependencies: - supports-color - eslint-processor-vue-blocks@2.0.0(@vue/compiler-sfc@3.5.22)(eslint@9.38.0(jiti@2.6.1)): + eslint-processor-vue-blocks@2.0.0(@vue/compiler-sfc@3.5.22)(eslint@9.39.0(jiti@2.6.1)): dependencies: '@vue/compiler-sfc': 3.5.22 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) eslint-scope@8.4.0: dependencies: @@ -3777,16 +3751,16 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.38.0(jiti@2.6.1): + eslint@9.39.0(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.21.1 - '@eslint/config-helpers': 0.4.1 - '@eslint/core': 0.16.0 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.38.0 - '@eslint/plugin-kit': 0.4.0 + '@eslint/js': 9.39.0 + '@eslint/plugin-kit': 0.4.1 '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 @@ -3942,7 +3916,7 @@ snapshots: globals@15.15.0: {} - globals@16.4.0: {} + globals@16.5.0: {} globrex@0.1.2: {} @@ -4011,8 +3985,6 @@ snapshots: jsdoc-type-pratt-parser@6.10.0: {} - jsesc@3.0.2: {} - jsesc@3.1.0: {} json-buffer@3.0.1: {} @@ -4422,7 +4394,7 @@ snapshots: node-mock-http@1.0.3: {} - node-releases@2.0.26: {} + node-releases@2.0.27: {} normalize-path@3.0.0: {} @@ -4440,7 +4412,7 @@ snapshots: object-deep-merge@2.0.0: {} - ofetch@1.4.1: + ofetch@1.5.1: dependencies: destr: 2.0.5 node-fetch-native: 1.6.7 @@ -4559,9 +4531,9 @@ snapshots: regexp-tree@0.1.27: {} - regjsparser@0.12.0: + regjsparser@0.13.0: dependencies: - jsesc: 3.0.2 + jsesc: 3.1.0 reserved-identifiers@1.2.0: {} @@ -4571,7 +4543,7 @@ snapshots: reusify@1.1.0: {} - rolldown-plugin-dts@0.17.1(rolldown@1.0.0-beta.44)(typescript@5.9.3): + rolldown-plugin-dts@0.17.3(rolldown@1.0.0-beta.45)(typescript@5.9.3): dependencies: '@babel/generator': 7.28.5 '@babel/parser': 7.28.5 @@ -4582,32 +4554,32 @@ snapshots: dts-resolver: 2.1.2 get-tsconfig: 4.13.0 magic-string: 0.30.21 - rolldown: 1.0.0-beta.44 + rolldown: 1.0.0-beta.45 optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - oxc-resolver - supports-color - rolldown@1.0.0-beta.44: + rolldown@1.0.0-beta.45: dependencies: '@oxc-project/types': 0.95.0 - '@rolldown/pluginutils': 1.0.0-beta.44 + '@rolldown/pluginutils': 1.0.0-beta.45 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-beta.44 - '@rolldown/binding-darwin-arm64': 1.0.0-beta.44 - '@rolldown/binding-darwin-x64': 1.0.0-beta.44 - '@rolldown/binding-freebsd-x64': 1.0.0-beta.44 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.44 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.44 - '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.44 - '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.44 - '@rolldown/binding-linux-x64-musl': 1.0.0-beta.44 - '@rolldown/binding-openharmony-arm64': 1.0.0-beta.44 - '@rolldown/binding-wasm32-wasi': 1.0.0-beta.44 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.44 - '@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.44 - '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.44 + '@rolldown/binding-android-arm64': 1.0.0-beta.45 + '@rolldown/binding-darwin-arm64': 1.0.0-beta.45 + '@rolldown/binding-darwin-x64': 1.0.0-beta.45 + '@rolldown/binding-freebsd-x64': 1.0.0-beta.45 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.45 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.45 + '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.45 + '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.45 + '@rolldown/binding-linux-x64-musl': 1.0.0-beta.45 + '@rolldown/binding-openharmony-arm64': 1.0.0-beta.45 + '@rolldown/binding-wasm32-wasi': 1.0.0-beta.45 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.45 + '@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.45 + '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.45 rollup@4.52.5: dependencies: @@ -4731,7 +4703,7 @@ snapshots: picomatch: 4.0.3 typescript: 5.9.3 - tsdown@0.15.10(typescript@5.9.3): + tsdown@0.15.12(typescript@5.9.3): dependencies: ansis: 4.2.0 cac: 6.7.14 @@ -4740,14 +4712,13 @@ snapshots: diff: 8.0.2 empathic: 2.0.0 hookable: 5.5.3 - rolldown: 1.0.0-beta.44 - rolldown-plugin-dts: 0.17.1(rolldown@1.0.0-beta.44)(typescript@5.9.3) + rolldown: 1.0.0-beta.45 + rolldown-plugin-dts: 0.17.3(rolldown@1.0.0-beta.45)(typescript@5.9.3) semver: 7.7.3 tinyexec: 1.0.1 tinyglobby: 0.2.15 tree-kill: 1.2.2 unconfig: 7.3.3 - unrun: 0.2.0 optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -4762,7 +4733,7 @@ snapshots: tsx@4.20.6: dependencies: - esbuild: 0.25.11 + esbuild: 0.25.12 get-tsconfig: 4.13.0 optionalDependencies: fsevents: 2.3.3 @@ -4805,13 +4776,7 @@ snapshots: unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 - unrun@0.2.0: - dependencies: - '@oxc-project/runtime': 0.95.0 - rolldown: 1.0.0-beta.44 - synckit: 0.11.11 - - unstorage@1.17.1: + unstorage@1.17.2: dependencies: anymatch: 3.1.3 chokidar: 4.0.3 @@ -4819,7 +4784,7 @@ snapshots: h3: 1.15.4 lru-cache: 10.4.3 node-fetch-native: 1.6.7 - ofetch: 1.4.1 + ofetch: 1.5.1 ufo: 1.6.1 untyped@2.0.0: @@ -4842,30 +4807,30 @@ snapshots: util-deprecate@1.0.2: {} - vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1): + vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1): dependencies: - esbuild: 0.25.11 + esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 rollup: 4.52.5 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 24.9.1 + '@types/node': 24.9.2 fsevents: 2.3.3 jiti: 2.6.1 tsx: 4.20.6 yaml: 2.8.1 - vitest@4.0.3(@types/debug@4.1.12)(@types/node@24.9.1)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1): + vitest@4.0.6(@types/debug@4.1.12)(@types/node@24.9.2)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1): dependencies: - '@vitest/expect': 4.0.3 - '@vitest/mocker': 4.0.3(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1)) - '@vitest/pretty-format': 4.0.3 - '@vitest/runner': 4.0.3 - '@vitest/snapshot': 4.0.3 - '@vitest/spy': 4.0.3 - '@vitest/utils': 4.0.3 + '@vitest/expect': 4.0.6 + '@vitest/mocker': 4.0.6(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1)) + '@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 @@ -4877,11 +4842,11 @@ snapshots: tinyexec: 0.3.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.1.12(@types/node@24.9.1)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1) + vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(tsx@4.20.6)(yaml@2.8.1) why-is-node-running: 2.3.0 optionalDependencies: '@types/debug': 4.1.12 - '@types/node': 24.9.1 + '@types/node': 24.9.2 transitivePeerDependencies: - jiti - less @@ -4896,10 +4861,10 @@ snapshots: - tsx - yaml - vue-eslint-parser@10.2.0(eslint@9.38.0(jiti@2.6.1)): + vue-eslint-parser@10.2.0(eslint@9.39.0(jiti@2.6.1)): dependencies: debug: 4.4.3 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.39.0(jiti@2.6.1) eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 espree: 10.4.0