diff --git a/.changeset/perky-vans-yell.md b/.changeset/perky-vans-yell.md new file mode 100644 index 0000000..c85ae8f --- /dev/null +++ b/.changeset/perky-vans-yell.md @@ -0,0 +1,7 @@ +--- +'@tanstack/intent': patch +--- + +Refactor workspace pattern discovery to use a JSONC parser for Deno configs, support additional workspace config shapes, and cache workspace roots, parsed patterns, and resolved package directories during CLI commands. + +This also allows Deno workspace members with `deno.json` or `deno.jsonc` manifests to be resolved as workspace packages. diff --git a/package.json b/package.json index aeea99d..33064f6 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "tinyglobby": "^0.2.15", "typescript": "5.9.3", "vitest": "^4.0.17", - "yaml": "^2.7.0" + "yaml": "2.8.3" }, "overrides": {}, "dependencies": { diff --git a/packages/intent/package.json b/packages/intent/package.json index 78696a3..216da35 100644 --- a/packages/intent/package.json +++ b/packages/intent/package.json @@ -32,7 +32,8 @@ ], "dependencies": { "cac": "^6.7.14", - "yaml": "^2.7.0" + "jsonc-parser": "^3.3.1", + "yaml": "2.8.3" }, "devDependencies": { "@verdaccio/node-api": "6.0.0-6-next.76", diff --git a/packages/intent/src/cli-support.ts b/packages/intent/src/cli-support.ts index cf15b5e..21128b7 100644 --- a/packages/intent/src/cli-support.ts +++ b/packages/intent/src/cli-support.ts @@ -149,29 +149,32 @@ export async function resolveStaleTargets( } } - const { findPackagesWithSkills, findWorkspacePackages, findWorkspaceRoot } = + const { findWorkspaceRoot, getWorkspaceInfo } = await import('./workspace-patterns.js') const workspaceRoot = findWorkspaceRoot(resolvedRoot) - if (workspaceRoot) { - const packageDirsWithSkills = findPackagesWithSkills(workspaceRoot) - const allPackageDirs = findWorkspacePackages(workspaceRoot) + const workspaceInfo = workspaceRoot ? getWorkspaceInfo(workspaceRoot) : null + if (workspaceInfo) { const reports = await Promise.all( - packageDirsWithSkills.map((packageDir) => - checkStaleness(packageDir, readPackageName(packageDir), workspaceRoot), + workspaceInfo.packageDirsWithSkills.map((packageDir) => + checkStaleness( + packageDir, + readPackageName(packageDir), + workspaceInfo.root, + ), ), ) const { readIntentArtifacts } = await import('./artifact-coverage.js') - const artifacts = existsSync(join(workspaceRoot, '_artifacts')) - ? readIntentArtifacts(workspaceRoot) + const artifacts = existsSync(join(workspaceInfo.root, '_artifacts')) + ? readIntentArtifacts(workspaceInfo.root) : null const coverageSignals = buildWorkspaceCoverageSignals({ - artifactRoot: workspaceRoot, + artifactRoot: workspaceInfo.root, artifacts, - packageDirs: allPackageDirs, + packageDirs: workspaceInfo.packageDirs, }) if (coverageSignals.length > 0) { reports.push({ - library: relative(process.cwd(), workspaceRoot) || 'workspace', + library: relative(process.cwd(), workspaceInfo.root) || 'workspace', currentVersion: null, skillVersion: null, versionDrift: null, diff --git a/packages/intent/src/workspace-patterns.ts b/packages/intent/src/workspace-patterns.ts index 04997f8..a9851b8 100644 --- a/packages/intent/src/workspace-patterns.ts +++ b/packages/intent/src/workspace-patterns.ts @@ -1,5 +1,6 @@ import { existsSync, readFileSync, readdirSync } from 'node:fs' import { dirname, join } from 'node:path' +import { parse as parseJsonc, type ParseError } from 'jsonc-parser' import { parse as parseYaml } from 'yaml' import { findSkillFiles } from './utils.js' @@ -13,180 +14,231 @@ function normalizeWorkspacePatterns(patterns: Array): Array { ].sort((a, b) => a.localeCompare(b)) } -function parseWorkspacePatterns(value: unknown): Array | null { +function isRecord(value: unknown): value is Record { + return typeof value === 'object' && value !== null && !Array.isArray(value) +} + +function parseWorkspacePatternList( + value: unknown, + fieldName: string, +): Array | null { + if (value === undefined || value === null) { + return null + } + if (!Array.isArray(value)) { + throw new TypeError(`${fieldName} must be an array of strings`) + } + + if (value.some((pattern) => typeof pattern !== 'string')) { + throw new TypeError(`${fieldName} must be an array of strings`) + } + + return normalizeWorkspacePatterns(value) +} + +function parseWorkspacePatternField( + value: unknown, + fieldName: string, + nestedKey: string, +): Array | null { + if (value === undefined || value === null) { return null } - return normalizeWorkspacePatterns( - value.filter((pattern): pattern is string => typeof pattern === 'string'), + if (Array.isArray(value)) { + return parseWorkspacePatternList(value, fieldName) + } + + if (isRecord(value)) { + return parseWorkspacePatternList( + value[nestedKey], + `${fieldName}.${nestedKey}`, + ) + } + + throw new TypeError( + `${fieldName} must be an array of strings or an object with ${nestedKey}`, ) } -function hasPackageJson(dir: string): boolean { - return existsSync(join(dir, 'package.json')) +function hasWorkspaceManifest(dir: string): boolean { + return ( + existsSync(join(dir, 'package.json')) || + existsSync(join(dir, 'deno.json')) || + existsSync(join(dir, 'deno.jsonc')) + ) } -function stripJsonCommentsAndTrailingCommas(source: string): string { - let result = '' - let inString = false - let escaped = false - - for (let index = 0; index < source.length; index += 1) { - const char = source[index]! - const next = source[index + 1] - - if (inString) { - result += char - if (escaped) { - escaped = false - } else if (char === '\\') { - escaped = true - } else if (char === '"') { - inString = false - } - continue - } +function readYamlFile(path: string): unknown { + return parseYaml(readFileSync(path, 'utf8')) +} - if (char === '"') { - inString = true - result += char - continue - } +function readJsonFile(path: string): unknown { + return JSON.parse(readFileSync(path, 'utf8')) +} - if (char === '/' && next === '/') { - while (index < source.length && source[index] !== '\n') { - index += 1 - } - if (index < source.length) { - result += source[index]! - } - continue - } +function readJsoncFile(path: string): unknown { + const errors: Array = [] + const value = parseJsonc(readFileSync(path, 'utf8'), errors, { + allowTrailingComma: true, + }) - if (char === '/' && next === '*') { - const commentStart = index - index += 2 - while ( - index < source.length && - !(source[index] === '*' && source[index + 1] === '/') - ) { - index += 1 - } - if (index >= source.length) { - throw new SyntaxError( - `Unterminated block comment starting at position ${commentStart}`, + if (errors.length > 0) { + throw new SyntaxError( + errors + .map( + (error) => + `JSONC parse error ${error.error} at offset ${error.offset}`, ) - } - index += 1 - continue - } + .join('; '), + ) + } - if (char === ',') { - let lookahead = index + 1 - while (lookahead < source.length) { - const la = source[lookahead]! - if (/\s/.test(la)) { - lookahead += 1 - } else if (la === '/' && source[lookahead + 1] === '/') { - lookahead += 2 - while (lookahead < source.length && source[lookahead] !== '\n') { - lookahead += 1 - } - } else if (la === '/' && source[lookahead + 1] === '*') { - lookahead += 2 - while ( - lookahead < source.length && - !(source[lookahead] === '*' && source[lookahead + 1] === '/') - ) { - lookahead += 1 - } - lookahead += 2 - } else { - break - } - } - if (source[lookahead] === '}' || source[lookahead] === ']') { - continue - } - } + return value +} - result += char - } +function warnConfigError(path: string, err: unknown): void { + const verb = err instanceof SyntaxError ? 'parse' : 'read' + console.error( + `Warning: failed to ${verb} ${path}: ${err instanceof Error ? err.message : err}`, + ) +} - return result +type WorkspacePatternSource = { + fileName: string + read: (path: string) => unknown + getPatterns: (config: unknown) => Array | null } -function readJsonFile(path: string, jsonc = false): unknown { - const source = readFileSync(path, 'utf8') - return JSON.parse(jsonc ? stripJsonCommentsAndTrailingCommas(source) : source) +export type WorkspaceInfo = { + root: string + patterns: Array + packageDirs: Array + packageDirsWithSkills: Array } +const workspacePatternSources: Array = [ + { + fileName: 'pnpm-workspace.yaml', + read: readYamlFile, + getPatterns: (config) => + parseWorkspacePatternList( + isRecord(config) ? config.packages : undefined, + 'pnpm-workspace.yaml#packages', + ), + }, + { + fileName: 'package.json', + read: readJsonFile, + getPatterns: (config) => + parseWorkspacePatternField( + isRecord(config) ? config.workspaces : undefined, + 'package.json#workspaces', + 'packages', + ), + }, + { + fileName: 'deno.json', + read: readJsoncFile, + getPatterns: (config) => + parseWorkspacePatternField( + isRecord(config) ? config.workspace : undefined, + 'deno.json#workspace', + 'members', + ), + }, + { + fileName: 'deno.jsonc', + read: readJsoncFile, + getPatterns: (config) => + parseWorkspacePatternField( + isRecord(config) ? config.workspace : undefined, + 'deno.jsonc#workspace', + 'members', + ), + }, +] + +const workspacePatternsCache = new Map | null>() +const workspaceRootCache = new Map() +const workspacePackageDirsCache = new Map | null>() +const workspaceInfoCache = new Map() + export function readWorkspacePatterns(root: string): Array | null { - const pnpmWs = join(root, 'pnpm-workspace.yaml') - if (existsSync(pnpmWs)) { - try { - const config = parseYaml(readFileSync(pnpmWs, 'utf8')) as Record< - string, - unknown - > - const patterns = parseWorkspacePatterns(config.packages) - if (patterns) { - return patterns - } - } catch (err: unknown) { - const verb = err instanceof SyntaxError ? 'parse' : 'read' - console.error( - `Warning: failed to ${verb} ${pnpmWs}: ${err instanceof Error ? err.message : err}`, - ) - } + if (workspacePatternsCache.has(root)) { + return workspacePatternsCache.get(root) ?? null } - const pkgPath = join(root, 'package.json') - if (existsSync(pkgPath)) { - try { - const pkg = readJsonFile(pkgPath) as Record - const workspaces = pkg.workspaces as Record | undefined - const patterns = - parseWorkspacePatterns(workspaces) ?? - parseWorkspacePatterns(workspaces?.packages) - if (patterns) { - return patterns - } - } catch (err: unknown) { - const verb = err instanceof SyntaxError ? 'parse' : 'read' - console.error( - `Warning: failed to ${verb} ${pkgPath}: ${err instanceof Error ? err.message : err}`, - ) - } - } + const patterns = readWorkspacePatternsUncached(root) + workspacePatternsCache.set(root, patterns) + return patterns +} + +function readWorkspacePatternsUncached(root: string): Array | null { + for (const source of workspacePatternSources) { + const path = join(root, source.fileName) - for (const denoConfigName of ['deno.json', 'deno.jsonc']) { - const denoConfigPath = join(root, denoConfigName) - if (!existsSync(denoConfigPath)) { + if (!existsSync(path)) { continue } try { - const denoConfig = readJsonFile(denoConfigPath, true) as Record< - string, - unknown - > - const patterns = parseWorkspacePatterns(denoConfig.workspace) + const patterns = source.getPatterns(source.read(path)) if (patterns) { return patterns } } catch (err: unknown) { - const verb = err instanceof SyntaxError ? 'parse' : 'read' - console.error( - `Warning: failed to ${verb} ${denoConfigPath}: ${err instanceof Error ? err.message : err}`, - ) + warnConfigError(path, err) } } return null } +function readWorkspacePackageDirs(root: string): Array | null { + if (workspacePackageDirsCache.has(root)) { + return workspacePackageDirsCache.get(root) ?? null + } + + const patterns = readWorkspacePatterns(root) + if (!patterns) { + workspacePackageDirsCache.set(root, null) + return null + } + + const packageDirs = resolveWorkspacePackages(root, patterns) + workspacePackageDirsCache.set(root, packageDirs) + return packageDirs +} + +export function getWorkspaceInfo(root: string): WorkspaceInfo | null { + if (workspaceInfoCache.has(root)) { + return workspaceInfoCache.get(root) ?? null + } + + const patterns = readWorkspacePatterns(root) + if (!patterns) { + workspaceInfoCache.set(root, null) + return null + } + + const packageDirs = readWorkspacePackageDirs(root) ?? [] + const packageDirsWithSkills = packageDirs.filter((dir) => { + const skillsDir = join(dir, 'skills') + return existsSync(skillsDir) && findSkillFiles(skillsDir).length > 0 + }) + const info = { + root, + patterns, + packageDirs, + packageDirsWithSkills, + } + + workspaceInfoCache.set(root, info) + return info +} + export function resolveWorkspacePackages( root: string, patterns: Array, @@ -219,7 +271,7 @@ function resolveWorkspacePatternSegments( result: Set, ): void { if (segments.length === 0) { - if (hasPackageJson(dir)) { + if (hasWorkspaceManifest(dir)) { result.add(dir) } return @@ -271,31 +323,41 @@ function readChildDirectories(dir: string): Array { export function findWorkspaceRoot(start: string): string | null { let dir = start + const visited: Array = [] while (true) { + const cached = workspaceRootCache.get(dir) + if (cached !== undefined) { + for (const visitedDir of visited) { + workspaceRootCache.set(visitedDir, cached) + } + return cached + } + + visited.push(dir) + if (readWorkspacePatterns(dir)) { + for (const visitedDir of visited) { + workspaceRootCache.set(visitedDir, dir) + } return dir } const next = dirname(dir) - if (next === dir) return null + if (next === dir) { + for (const visitedDir of visited) { + workspaceRootCache.set(visitedDir, null) + } + return null + } dir = next } } export function findPackagesWithSkills(root: string): Array { - const patterns = readWorkspacePatterns(root) - if (!patterns) return [] - - return resolveWorkspacePackages(root, patterns).filter((dir) => { - const skillsDir = join(dir, 'skills') - return existsSync(skillsDir) && findSkillFiles(skillsDir).length > 0 - }) + return getWorkspaceInfo(root)?.packageDirsWithSkills ?? [] } export function findWorkspacePackages(root: string): Array { - const patterns = readWorkspacePatterns(root) - if (!patterns) return [] - - return resolveWorkspacePackages(root, patterns) + return readWorkspacePackageDirs(root) ?? [] } diff --git a/packages/intent/tests/workspace-patterns.test.ts b/packages/intent/tests/workspace-patterns.test.ts index aa31f42..cfb8338 100644 --- a/packages/intent/tests/workspace-patterns.test.ts +++ b/packages/intent/tests/workspace-patterns.test.ts @@ -12,6 +12,7 @@ import { findPackagesWithSkills, findWorkspacePackages, findWorkspaceRoot, + getWorkspaceInfo, readWorkspacePatterns, resolveWorkspacePackages, } from '../src/workspace-patterns.js' @@ -36,6 +37,15 @@ function writePackage(root: string, ...parts: Array): void { ) } +function writeDenoPackage(root: string, ...parts: Array): void { + const dir = join(root, ...parts) + mkdirSync(dir, { recursive: true }) + writeFileSync( + join(dir, 'deno.json'), + JSON.stringify({ name: parts.join('/') }), + ) +} + function writeDir(root: string, ...parts: Array): void { mkdirSync(join(root, ...parts), { recursive: true }) } @@ -80,6 +90,32 @@ describe('readWorkspacePatterns', () => { ]) }) + it('reads workspace patterns from package.json object-form workspaces', () => { + const root = createRoot() + + writeFileSync( + join(root, 'package.json'), + JSON.stringify({ + workspaces: { + packages: ['./packages/*/', 'apps\\*'], + }, + }), + ) + + expect(readWorkspacePatterns(root)).toEqual(['apps/*', 'packages/*']) + }) + + it('reads workspace patterns from pnpm-workspace.yaml', () => { + const root = createRoot() + + writeFileSync( + join(root, 'pnpm-workspace.yaml'), + ['packages:', ' - ./packages/*/', ' - apps\\*'].join('\n'), + ) + + expect(readWorkspacePatterns(root)).toEqual(['apps/*', 'packages/*']) + }) + it('reads workspace patterns from deno.json', () => { const root = createRoot() @@ -111,6 +147,21 @@ describe('readWorkspacePatterns', () => { expect(readWorkspacePatterns(root)).toEqual(['apps/*', 'packages/*']) }) + it('reads workspace patterns from Deno object-form workspace members', () => { + const root = createRoot() + + writeFileSync( + join(root, 'deno.json'), + JSON.stringify({ + workspace: { + members: ['./packages/*/', 'apps\\*'], + }, + }), + ) + + expect(readWorkspacePatterns(root)).toEqual(['apps/*', 'packages/*']) + }) + it('prefers package.json workspaces over Deno workspace config', () => { const root = createRoot() @@ -126,6 +177,43 @@ describe('readWorkspacePatterns', () => { expect(readWorkspacePatterns(root)).toEqual(['packages/*']) }) + it('falls back when a higher-priority config has no workspace field', () => { + const root = createRoot() + + writeFileSync(join(root, 'package.json'), JSON.stringify({ name: 'root' })) + writeFileSync( + join(root, 'deno.json'), + JSON.stringify({ workspace: ['packages/*'] }), + ) + + expect(readWorkspacePatterns(root)).toEqual(['packages/*']) + }) + + it('warns and falls back when package.json workspaces contains non-string entries', () => { + const root = createRoot() + const consoleErrorSpy = vi + .spyOn(console, 'error') + .mockImplementation(() => undefined) + + writeFileSync( + join(root, 'package.json'), + JSON.stringify({ workspaces: [123] }), + ) + writeFileSync( + join(root, 'deno.json'), + JSON.stringify({ workspace: ['packages/*'] }), + ) + + expect(readWorkspacePatterns(root)).toEqual(['packages/*']) + expect(consoleErrorSpy).toHaveBeenCalledWith( + expect.stringContaining( + `Warning: failed to read ${join(root, 'package.json')}`, + ), + ) + + consoleErrorSpy.mockRestore() + }) + it('warns and returns null for invalid Deno config', () => { const root = createRoot() const consoleErrorSpy = vi @@ -232,6 +320,19 @@ describe('resolveWorkspacePackages', () => { resolveWorkspacePackages(root, ['packages/*', '!packages/excluded']), ).toEqual([join(root, 'packages', 'alpha')]) }) + + it('resolves Deno-only workspace members', () => { + const root = createRoot() + + writeDenoPackage(root, 'packages', 'deno-lib') + writePackage(root, 'packages', 'node-lib') + writeDir(root, 'packages', 'not-a-package') + + expect(resolveWorkspacePackages(root, ['packages/*'])).toEqual([ + join(root, 'packages', 'deno-lib'), + join(root, 'packages', 'node-lib'), + ]) + }) }) describe('workspace helpers', () => { @@ -261,6 +362,13 @@ describe('workspace helpers', () => { withCwd(nestedDir) expect(findWorkspaceRoot(process.cwd())).toBe(root) + expect(getWorkspaceInfo(root)?.packageDirs).toEqual([ + join(root, 'packages', 'alpha'), + join(root, 'packages', 'beta'), + ]) + expect(getWorkspaceInfo(root)?.packageDirsWithSkills).toEqual([ + join(root, 'packages', 'alpha'), + ]) expect(findPackagesWithSkills(root)).toEqual([ join(root, 'packages', 'alpha'), ]) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 81eb432..54d65f1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -64,31 +64,34 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.0.17(@types/node@25.0.9)(happy-dom@20.3.1)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.2) + version: 4.0.17(@types/node@25.0.9)(happy-dom@20.3.1)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3) yaml: - specifier: ^2.7.0 - version: 2.8.2 + specifier: 2.8.3 + version: 2.8.3 benchmarks/intent: devDependencies: '@codspeed/vitest-plugin': specifier: ^5.0.1 - version: 5.2.0(tinybench@2.9.0)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.2))(vitest@4.0.17(@types/node@25.0.9)(happy-dom@20.3.1)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.2)) + version: 5.2.0(tinybench@2.9.0)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3))(vitest@4.0.17(@types/node@25.0.9)(happy-dom@20.3.1)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3)) typescript: specifier: 5.9.3 version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.0.17(@types/node@25.0.9)(happy-dom@20.3.1)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.2) + version: 4.0.17(@types/node@25.0.9)(happy-dom@20.3.1)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3) packages/intent: dependencies: cac: specifier: ^6.7.14 version: 6.7.14 + jsonc-parser: + specifier: ^3.3.1 + version: 3.3.1 yaml: - specifier: ^2.7.0 - version: 2.8.2 + specifier: 2.8.3 + version: 2.8.3 devDependencies: '@verdaccio/node-api': specifier: 6.0.0-6-next.76 @@ -2690,6 +2693,9 @@ packages: jsonc-parser@3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} @@ -4185,8 +4191,8 @@ packages: yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - yaml@2.8.2: - resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} + yaml@2.8.3: + resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} engines: {node: '>= 14.6'} hasBin: true @@ -4401,13 +4407,13 @@ snapshots: transitivePeerDependencies: - debug - '@codspeed/vitest-plugin@5.2.0(tinybench@2.9.0)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.2))(vitest@4.0.17(@types/node@25.0.9)(happy-dom@20.3.1)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.2))': + '@codspeed/vitest-plugin@5.2.0(tinybench@2.9.0)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3))(vitest@4.0.17(@types/node@25.0.9)(happy-dom@20.3.1)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3))': dependencies: '@codspeed/core': 5.2.0 tinybench: 2.9.0 - vitest: 4.0.17(@types/node@25.0.9)(happy-dom@20.3.1)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.2) + vitest: 4.0.17(@types/node@25.0.9)(happy-dom@20.3.1)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3) optionalDependencies: - vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3) transitivePeerDependencies: - debug @@ -5674,13 +5680,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.17(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.2))': + '@vitest/mocker@4.0.17(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3))': dependencies: '@vitest/spy': 4.0.17 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3) '@vitest/pretty-format@4.0.17': dependencies: @@ -7081,6 +7087,8 @@ snapshots: jsonc-parser@3.2.0: {} + jsonc-parser@3.3.1: {} + jsonfile@4.0.0: optionalDependencies: graceful-fs: 4.2.11 @@ -7464,7 +7472,7 @@ snapshots: tree-kill: 1.2.2 tsconfig-paths: 4.2.0 tslib: 2.8.1 - yaml: 2.8.2 + yaml: 2.8.3 yargs: 17.7.2 yargs-parser: 21.1.1 optionalDependencies: @@ -8387,7 +8395,7 @@ snapshots: typedoc-plugin-frontmatter@1.3.0(typedoc-plugin-markdown@4.9.0(typedoc@0.28.14(typescript@5.9.3))): dependencies: typedoc-plugin-markdown: 4.9.0(typedoc@0.28.14(typescript@5.9.3)) - yaml: 2.8.2 + yaml: 2.8.3 typedoc-plugin-markdown@4.9.0(typedoc@0.28.14(typescript@5.9.3)): dependencies: @@ -8400,7 +8408,7 @@ snapshots: markdown-it: 14.1.1 minimatch: 9.0.5 typescript: 5.9.3 - yaml: 2.8.2 + yaml: 2.8.3 typescript-eslint@8.56.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3): dependencies: @@ -8575,7 +8583,7 @@ snapshots: core-util-is: 1.0.2 extsprintf: 1.3.0 - vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.2): + vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3): dependencies: esbuild: 0.27.2 fdir: 6.5.0(picomatch@4.0.3) @@ -8588,12 +8596,12 @@ snapshots: fsevents: 2.3.3 jiti: 2.6.1 lightningcss: 1.32.0 - yaml: 2.8.2 + yaml: 2.8.3 - vitest@4.0.17(@types/node@25.0.9)(happy-dom@20.3.1)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.2): + vitest@4.0.17(@types/node@25.0.9)(happy-dom@20.3.1)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3): dependencies: '@vitest/expect': 4.0.17 - '@vitest/mocker': 4.0.17(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.2)) + '@vitest/mocker': 4.0.17(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3)) '@vitest/pretty-format': 4.0.17 '@vitest/runner': 4.0.17 '@vitest/snapshot': 4.0.17 @@ -8610,7 +8618,7 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 25.0.9 @@ -8690,7 +8698,7 @@ snapshots: yallist@4.0.0: {} - yaml@2.8.2: {} + yaml@2.8.3: {} yargs-parser@21.1.1: {}