From b62d9836ffc0b9b79ca0b074740ddf7cd2cbbadc Mon Sep 17 00:00:00 2001 From: Caio Pizzol Date: Thu, 22 Jan 2026 17:58:16 -0300 Subject: [PATCH] chore: switch from jsdom to happy-dom for perf --- packages/super-editor/package.json | 1 + .../core/inputRules/docx-paste/docx-paste.js | 12 +-- .../inputRules/docx-paste/docx-paste.test.js | 6 +- .../google-docs-paste/google-docs-paste.js | 5 +- .../inputRules/html/transform-copied-lists.js | 2 +- .../presentation-editor/dom/HiddenHost.ts | 19 +++-- .../extensions/tab/helpers/tabDecorations.js | 15 ++-- packages/super-editor/vite.config.js | 3 +- pnpm-lock.yaml | 75 ++++++++++++++----- pnpm-workspace.yaml | 1 + 10 files changed, 97 insertions(+), 42 deletions(-) diff --git a/packages/super-editor/package.json b/packages/super-editor/package.json index a4900bca0a..bfe1b8386c 100644 --- a/packages/super-editor/package.json +++ b/packages/super-editor/package.json @@ -126,6 +126,7 @@ "@vitejs/plugin-vue": "catalog:", "@vue/test-utils": "catalog:", "canvas": "catalog:", + "happy-dom": "catalog:", "postcss-nested": "catalog:", "postcss-nested-import": "catalog:", "prosemirror-test-builder": "catalog:", diff --git a/packages/super-editor/src/core/inputRules/docx-paste/docx-paste.js b/packages/super-editor/src/core/inputRules/docx-paste/docx-paste.js index c9410c43fb..54120bcbfd 100644 --- a/packages/super-editor/src/core/inputRules/docx-paste/docx-paste.js +++ b/packages/super-editor/src/core/inputRules/docx-paste/docx-paste.js @@ -147,7 +147,7 @@ export const handleDocxPaste = (html, editor, view) => { Object.keys(textStyles).forEach((key) => { const styleValue = textStyles[key]; if (styleValue) { - item.style[key] = styleValue; + item.style.setProperty(key, styleValue); } }); item.setAttribute('data-text-styles', JSON.stringify(textStyles)); @@ -157,7 +157,7 @@ export const handleDocxPaste = (html, editor, view) => { Object.keys(textStyles).forEach((key) => { const styleValue = textStyles[key]; if (styleValue) { - child.style[key] = styleValue; + child.style.setProperty(key, styleValue); } }); } @@ -166,10 +166,10 @@ export const handleDocxPaste = (html, editor, view) => { // Marks if (resolvedStyle['font-weight'] === 'bold') { - item.style.fontWeight = 'bold'; + item.style.setProperty('font-weight', 'bold'); for (const child of item.children) { if (child.style) { - child.style.fontWeight = 'bold'; + child.style.setProperty('font-weight', 'bold'); } } } @@ -288,10 +288,10 @@ const transformWordLists = (container, editor) => { Object.keys(textStyles).forEach((key) => { const styleValue = textStyles[key]; if (styleValue) { - pElement.style[key] = styleValue; + pElement.style.setProperty(key, styleValue); for (const child of pElement.children) { if (child.style) { - child.style[key] = styleValue; + child.style.setProperty(key, styleValue); } } } diff --git a/packages/super-editor/src/core/inputRules/docx-paste/docx-paste.test.js b/packages/super-editor/src/core/inputRules/docx-paste/docx-paste.test.js index ff7b9d001e..7f751f9889 100644 --- a/packages/super-editor/src/core/inputRules/docx-paste/docx-paste.test.js +++ b/packages/super-editor/src/core/inputRules/docx-paste/docx-paste.test.js @@ -99,11 +99,11 @@ describe('handleDocxPaste', () => {
    -
  1. - First item +
  2. + First item
-

+

2. Second item

diff --git a/packages/super-editor/src/core/inputRules/google-docs-paste/google-docs-paste.js b/packages/super-editor/src/core/inputRules/google-docs-paste/google-docs-paste.js index 33de203ac0..d323ca1f26 100644 --- a/packages/super-editor/src/core/inputRules/google-docs-paste/google-docs-paste.js +++ b/packages/super-editor/src/core/inputRules/google-docs-paste/google-docs-paste.js @@ -158,7 +158,10 @@ function getNestedLists(nodes) { function mergeSeparateLists(container) { const tempCont = container.cloneNode(true); - const rootLevelLists = Array.from(tempCont.querySelectorAll('ol:not(ol ol):not(ul ol)') || []); + // Find root-level ordered lists (not nested inside other lists) + // Note: Using filter instead of complex :not() selectors for better browser compatibility + const allOls = Array.from(tempCont.querySelectorAll('ol') || []); + const rootLevelLists = allOls.filter((ol) => !ol.parentElement?.closest('ol, ul')); const mainList = rootLevelLists.find((list) => !list.getAttribute('start')) || rootLevelLists[0]; const hasStartAttr = rootLevelLists.some((list) => list.getAttribute('start') !== null); diff --git a/packages/super-editor/src/core/inputRules/html/transform-copied-lists.js b/packages/super-editor/src/core/inputRules/html/transform-copied-lists.js index 818fd9cb22..3fb146fed5 100644 --- a/packages/super-editor/src/core/inputRules/html/transform-copied-lists.js +++ b/packages/super-editor/src/core/inputRules/html/transform-copied-lists.js @@ -38,7 +38,7 @@ export const transformListsInCopiedContent = (html) => { const li = child.cloneNode(true); li.setAttribute('aria-level', level + 1); - li.style['list-style-type'] = getListStyleType(numFmt, lvlText); + li.style.setProperty('list-style-type', getListStyleType(numFmt, lvlText)); // if current level not open, create new list if (!stack.length || stack[stack.length - 1].level < level) { diff --git a/packages/super-editor/src/core/presentation-editor/dom/HiddenHost.ts b/packages/super-editor/src/core/presentation-editor/dom/HiddenHost.ts index 921c0b7a00..9cfdb9078c 100644 --- a/packages/super-editor/src/core/presentation-editor/dom/HiddenHost.ts +++ b/packages/super-editor/src/core/presentation-editor/dom/HiddenHost.ts @@ -22,17 +22,20 @@ export function createHiddenHost(doc: Document, widthPx: number): HTMLElement { const host = doc.createElement('div'); host.className = 'presentation-editor__hidden-host'; - host.style.position = 'fixed'; - host.style.left = '-9999px'; - host.style.top = '0'; - host.style.width = `${widthPx}px`; + host.style.setProperty('position', 'fixed'); + host.style.setProperty('left', '-9999px'); + host.style.setProperty('top', '0'); + // Only set valid (non-negative) width values + if (widthPx >= 0) { + host.style.setProperty('width', `${widthPx}px`); + } host.style.setProperty('overflow-anchor', 'none'); - host.style.pointerEvents = 'none'; + host.style.setProperty('pointer-events', 'none'); // DO NOT use visibility:hidden - it prevents focusing! // Instead use opacity:0 and z-index to hide while keeping focusable - host.style.opacity = '0'; - host.style.zIndex = '-1'; - host.style.userSelect = 'none'; + host.style.setProperty('opacity', '0'); + host.style.setProperty('z-index', '-1'); + host.style.setProperty('user-select', 'none'); // DO NOT set aria-hidden="true" on this element. // This hidden host contains the actual ProseMirror editor which must remain accessible // to screen readers and keyboard navigation. The viewport (#viewportHost) is aria-hidden diff --git a/packages/super-editor/src/extensions/tab/helpers/tabDecorations.js b/packages/super-editor/src/extensions/tab/helpers/tabDecorations.js index 4d769f1245..731fa0530d 100644 --- a/packages/super-editor/src/extensions/tab/helpers/tabDecorations.js +++ b/packages/super-editor/src/extensions/tab/helpers/tabDecorations.js @@ -265,13 +265,18 @@ export function measureRangeWidth(view, from, to, coordCache = null, domPosCache range.setEnd(toRef.node, toRef.offset); const rect = range.getBoundingClientRect(); range.detach?.(); - return rect.width || 0; + // If getBoundingClientRect returns 0 (e.g., HappyDOM), fall back to coordsAtPos + if (rect.width > 0) { + return rect.width; + } } catch { - const startLeft = getLeftCoord(view, from, coordCache, domPosCache); - const endLeft = getLeftCoord(view, to, coordCache, domPosCache); - if (startLeft == null || endLeft == null) return 0; - return Math.max(0, endLeft - startLeft); + // Fall through to coordsAtPos fallback } + // Fallback: use view.coordsAtPos difference (works in test mocks and when Range fails) + const startLeft = getLeftCoord(view, from, coordCache, domPosCache); + const endLeft = getLeftCoord(view, to, coordCache, domPosCache); + if (startLeft == null || endLeft == null) return 0; + return Math.max(0, endLeft - startLeft); } export function getIndentWidth(view, paragraphStartPos, indentAttrs = {}, coordCache = null, domPosCache = null) { diff --git a/packages/super-editor/vite.config.js b/packages/super-editor/vite.config.js index 4d24e7f37d..e0036dddb6 100644 --- a/packages/super-editor/vite.config.js +++ b/packages/super-editor/vite.config.js @@ -25,7 +25,8 @@ export default defineConfig(({ mode }) => { minWorkers, maxWorkers, globals: true, - environment: 'jsdom', + // Use happy-dom for faster tests (set VITEST_DOM=jsdom to use jsdom) + environment: process.env.VITEST_DOM || 'happy-dom', retry: 2, testTimeout: 20000, hookTimeout: 10000, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 88de72e54b..7fccaf5358 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -84,6 +84,9 @@ catalogs: eventemitter3: specifier: ^5.0.1 version: 5.0.1 + happy-dom: + specifier: ^20.3.4 + version: 20.3.4 he: specifier: ^1.2.0 version: 1.2.0 @@ -294,7 +297,7 @@ importers: version: 8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@vitest/coverage-v8': specifier: 'catalog:' - version: 3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2)) + version: 3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(happy-dom@20.3.4)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2)) eslint: specifier: 'catalog:' version: 9.39.1(jiti@2.6.1) @@ -345,7 +348,7 @@ importers: version: 0.24.0(patch_hash=b69b54a87bfd9531260555cfb2fda7c94e6f75c124e3a3fae26d64272bbe86ff)(rollup@4.53.3)(vite@7.2.7(@types/node@22.19.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(happy-dom@20.3.4)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) optionalDependencies: canvas: specifier: 'catalog:' @@ -450,7 +453,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(happy-dom@20.3.4)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) vue: specifier: 'catalog:' version: 3.5.25(typescript@5.9.3) @@ -475,7 +478,7 @@ importers: version: 8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@vitest/coverage-v8': specifier: 'catalog:' - version: 3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2)) + version: 3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(happy-dom@20.3.4)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2)) concurrently: specifier: 'catalog:' version: 9.2.1 @@ -499,7 +502,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(happy-dom@20.3.4)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) packages/layout-engine: {} @@ -512,7 +515,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(happy-dom@20.3.4)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) packages/layout-engine/layout-bridge: dependencies: @@ -549,7 +552,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(happy-dom@20.3.4)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) packages/layout-engine/layout-engine: dependencies: @@ -595,7 +598,7 @@ importers: devDependencies: vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(happy-dom@20.3.4)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) packages/layout-engine/pm-adapter: dependencies: @@ -635,7 +638,7 @@ importers: version: link:../painters/dom vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(happy-dom@20.3.4)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) packages/layout-engine/style-engine: dependencies: @@ -651,7 +654,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(happy-dom@20.3.4)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) packages/layout-engine/tests: dependencies: @@ -818,6 +821,9 @@ importers: canvas: specifier: 'catalog:' version: 3.2.0 + happy-dom: + specifier: 'catalog:' + version: 20.3.4 postcss-nested: specifier: 'catalog:' version: 6.2.0(postcss@8.5.6) @@ -841,7 +847,7 @@ importers: version: 0.24.0(patch_hash=b69b54a87bfd9531260555cfb2fda7c94e6f75c124e3a3fae26d64272bbe86ff)(rollup@4.53.3)(vite@7.2.7(@types/node@22.19.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(happy-dom@20.3.4)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) y-protocols: specifier: 'catalog:' version: 1.0.6(yjs@13.6.19) @@ -935,7 +941,7 @@ importers: version: 0.24.0(patch_hash=b69b54a87bfd9531260555cfb2fda7c94e6f75c124e3a3fae26d64272bbe86ff)(rollup@4.53.3)(vite@7.2.7(@types/node@22.19.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(happy-dom@20.3.4)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) xml-js: specifier: 'catalog:' version: 1.6.11 @@ -944,7 +950,7 @@ importers: devDependencies: vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(happy-dom@20.3.4)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) shared/common: devDependencies: @@ -959,7 +965,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(happy-dom@20.3.4)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) vue: specifier: 'catalog:' version: 3.5.25(typescript@5.9.3) @@ -2105,6 +2111,12 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/whatwg-mimetype@3.0.2': + resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==} + + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + '@typescript-eslint/eslint-plugin@8.49.0': resolution: {integrity: sha512-JXij0vzIaTtCwu6SxTh8qBc66kmf1xs7pI4UOiMDFVct6q86G0Zs7KRcEoJgY3Cav3x5Tq0MF5jwgpgLqgKG3A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3966,6 +3978,10 @@ packages: engines: {node: '>=0.4.7'} hasBin: true + happy-dom@20.3.4: + resolution: {integrity: sha512-rfbiwB6OKxZFIFQ7SRnCPB2WL9WhyXsFoTfecYgeCeFSOBxvkWLaXsdv5ehzJrfqwXQmDephAKWLRQoFoJwrew==} + engines: {node: '>=20.0.0'} + has-bigints@1.1.0: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} @@ -7070,6 +7086,10 @@ packages: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} + whatwg-mimetype@3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + whatwg-mimetype@4.0.0: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} engines: {node: '>=18'} @@ -8428,6 +8448,12 @@ snapshots: '@types/unist@3.0.3': {} + '@types/whatwg-mimetype@3.0.2': {} + + '@types/ws@8.18.1': + dependencies: + '@types/node': 22.19.2 + '@typescript-eslint/eslint-plugin@8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -8743,7 +8769,7 @@ snapshots: vite: 7.2.7(@types/node@22.19.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) vue: 3.5.25(typescript@5.9.3) - '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(happy-dom@20.3.4)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 @@ -8758,7 +8784,7 @@ snapshots: std-env: 3.10.0 test-exclude: 7.0.1 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(happy-dom@20.3.4)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - supports-color @@ -10746,6 +10772,18 @@ snapshots: optionalDependencies: uglify-js: 3.19.3 + happy-dom@20.3.4: + dependencies: + '@types/node': 22.19.2 + '@types/whatwg-mimetype': 3.0.2 + '@types/ws': 8.18.1 + entities: 4.5.0 + whatwg-mimetype: 3.0.0 + ws: 8.18.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + has-bigints@1.1.0: optional: true @@ -14211,7 +14249,7 @@ snapshots: tsx: 4.21.0 yaml: 2.8.2 - vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2): + vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(happy-dom@20.3.4)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0)(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 @@ -14239,6 +14277,7 @@ snapshots: optionalDependencies: '@types/debug': 4.1.12 '@types/node': 22.19.2 + happy-dom: 20.3.4 jsdom: 27.3.0(canvas@3.2.0)(postcss@8.5.6) transitivePeerDependencies: - jiti @@ -14310,6 +14349,8 @@ snapshots: dependencies: iconv-lite: 0.6.3 + whatwg-mimetype@3.0.0: {} + whatwg-mimetype@4.0.0: {} whatwg-url@15.1.0: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 50979a0616..baaa6fc6d9 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -32,6 +32,7 @@ catalog: eslint-plugin-import-x: ^4.16.1 eslint-plugin-jsdoc: ^54.1.0 eventemitter3: ^5.0.1 + happy-dom: ^20.3.4 he: ^1.2.0 husky: ^9.1.7 jimp: ^1.6.0