diff --git a/package.json b/package.json index 7a2f9bdd7c..3b55aa3ba0 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "test:superdoc": "vitest run --root ./packages/superdoc", "test:cov": "node scripts/test-cov.mjs", "type-check": "tsc -b --force tsconfig.references.json", - "rebuild:types": "pnpm run --filter=@superdoc/contracts --filter=@superdoc/geometry-utils --filter=@superdoc/style-engine --filter=@superdoc/pm-adapter --filter=@superdoc/measuring-dom --filter=@superdoc/layout-engine --filter=@superdoc/painter-dom --filter=@superdoc/layout-bridge build", + "rebuild:types": "pnpm run --filter=@superdoc/common --filter=@superdoc/word-layout --filter=@superdoc/contracts --filter=@superdoc/geometry-utils --filter=@superdoc/style-engine --filter=@superdoc/pm-adapter --filter=@superdoc/measuring-dom --filter=@superdoc/layout-engine --filter=@superdoc/painter-dom --filter=@superdoc/layout-bridge build", "validate:commands": "node scripts/validate-command-types.mjs", "unzip": "bash packages/super-editor/src/tests/helpers/unzip.sh", "dev": "pnpm --prefix packages/superdoc run dev", diff --git a/packages/layout-engine/measuring/dom/src/index.ts b/packages/layout-engine/measuring/dom/src/index.ts index c144d8e498..83d131bacf 100644 --- a/packages/layout-engine/measuring/dom/src/index.ts +++ b/packages/layout-engine/measuring/dom/src/index.ts @@ -70,7 +70,7 @@ import { DEFAULT_LIST_HANGING_PX as DEFAULT_LIST_HANGING, SPACE_SUFFIX_GAP_PX, } from '@superdoc/common/layout-constants'; -import { resolveListTextStartPx } from '@superdoc/common/list-marker-utils'; +import { resolveListTextStartPx, type MinimalMarker } from '@superdoc/common/list-marker-utils'; import { calculateRotatedBounds, normalizeRotation } from '@superdoc/geometry-utils'; import { toCssFontFamily } from '@superdoc/font-utils'; export { installNodeCanvasPolyfill } from './setup.js'; @@ -895,7 +895,7 @@ async function measureParagraphBlock(block: ParagraphBlock, maxWidth: number): P indentLeft, firstLine, hanging, - (markerText, marker) => { + (markerText: string, marker: MinimalMarker) => { const markerRun = { fontFamily: toCssFontFamily(marker.run?.fontFamily) ?? marker.run?.fontFamily ?? 'Arial', fontSize: marker.run?.fontSize ?? fallbackFontSize, 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', () => {
+
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/tsconfig.types.json b/packages/super-editor/tsconfig.types.json index e33fe33ff2..e1215386a9 100644 --- a/packages/super-editor/tsconfig.types.json +++ b/packages/super-editor/tsconfig.types.json @@ -2,7 +2,8 @@ "extends": "./tsconfig.build.json", "compilerOptions": { "composite": true, - "outDir": "dist-types" + "outDir": "dist", + "tsBuildInfoFile": "./dist/tsconfig.types.tsbuildinfo" }, "references": [ { "path": "../layout-engine/contracts/tsconfig.json" }, 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/packages/word-layout/tsconfig.json b/packages/word-layout/tsconfig.json index e2db4f901b..54ba67378f 100644 --- a/packages/word-layout/tsconfig.json +++ b/packages/word-layout/tsconfig.json @@ -5,7 +5,8 @@ "rootDir": "./src", "composite": true, "declaration": true, - "declarationMap": true + "declarationMap": true, + "tsBuildInfoFile": "./dist/tsconfig.tsbuildinfo" }, "include": ["src/**/*"] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 831267e50c..bddb2e276d 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:' @@ -459,7 +462,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) @@ -484,7 +487,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 @@ -508,7 +511,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: {} @@ -521,7 +524,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: @@ -558,7 +561,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: @@ -604,7 +607,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: @@ -644,7 +647,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: @@ -660,7 +663,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: @@ -827,6 +830,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) @@ -850,7 +856,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) @@ -944,7 +950,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 @@ -953,7 +959,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: @@ -968,7 +974,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) @@ -2922,6 +2928,12 @@ packages: '@types/urijs@1.19.26': resolution: {integrity: sha512-wkXrVzX5yoqLnndOwFsieJA7oKM8cNkOKJtf/3vVGSUFkWDKZvFHpIl9Pvqb/T9UsawBBFMTTD8xu7sK5MWuvg==} + '@types/whatwg-mimetype@3.0.2': + resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==} + + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} @@ -5250,6 +5262,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'} @@ -9397,6 +9413,10 @@ packages: engines: {node: '>=18'} deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation + 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'} @@ -12079,6 +12099,12 @@ snapshots: '@types/urijs@1.19.26': {} + '@types/whatwg-mimetype@3.0.2': {} + + '@types/ws@8.18.1': + dependencies: + '@types/node': 22.19.2 + '@types/yauzl@2.10.3': dependencies: '@types/node': 22.19.2 @@ -12406,7 +12432,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 @@ -12421,7 +12447,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 @@ -14998,6 +15024,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: {} has-flag@3.0.0: {} @@ -20201,7 +20239,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 @@ -20229,6 +20267,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 @@ -20306,6 +20345,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 diff --git a/shared/common/package.json b/shared/common/package.json index dce4e53ede..366d030402 100644 --- a/shared/common/package.json +++ b/shared/common/package.json @@ -33,6 +33,7 @@ "list-numbering" ], "scripts": { + "build": "tsc --project tsconfig.json --emitDeclarationOnly", "test": "vitest run", "test:watch": "vitest", "typecheck": "tsc --noEmit"