From f73f8e8757b6f9074e31c4c0c68f4d617e568ca1 Mon Sep 17 00:00:00 2001 From: Kirill Zaytsev Date: Sat, 28 Dec 2024 19:39:48 +0400 Subject: [PATCH 1/4] feat: Event target serialization basics --- package.json | 6 +- src/vue/host/events.ts | 41 +++++-- src/vue/remote/createRemoteRenderer.ts | 2 +- tests/e2e/events-serializing.e2e.ts | 9 +- tests/integration/index.test.ts | 6 + types/events.d.ts | 12 +- yarn.lock | 164 ++++++++++--------------- 7 files changed, 126 insertions(+), 114 deletions(-) diff --git a/package.json b/package.json index bf83753..efe2a8f 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "@remote-ui/rpc": "^1.4.5" }, "peerDependencies": { - "vue": "^3.4.15" + "vue": "^3.4" }, "devDependencies": { "@babel/core": "^7.23.9", @@ -72,7 +72,7 @@ "@typescript-eslint/parser": "^6.19.1", "@vitejs/plugin-vue": "^5.0.4", "@vitest/coverage-istanbul": "^2.1.6", - "@vue/compiler-sfc": "^3.4.15", + "@vue/compiler-sfc": "^3.5.13", "@vue/language-server": "^2.1.10", "cors": "^2.8.5", "eslint": "^8.56.0", @@ -95,7 +95,7 @@ "vite": "^5.4.11", "vite-plugin-dts": "^4.3.0", "vitest": "^2.1.5", - "vue": "^3.4.15" + "vue": "^3.5.13" }, "publishConfig": { "access": "public" diff --git a/src/vue/host/events.ts b/src/vue/host/events.ts index 7fc3a32..d0bd18a 100644 --- a/src/vue/host/events.ts +++ b/src/vue/host/events.ts @@ -1,22 +1,49 @@ import type { - SerializedEvent, - SerializedFile, SerializedDataTransfer, - SerializedEventType, - SerializedInputEvent, SerializedDragEvent, + SerializedEvent, + SerializedEventType, + SerializedFile, SerializedFocusEvent, + SerializedInputEvent, SerializedKeyboardEvent, SerializedMouseEvent, SerializedPointerEvent, + SerializedTarget, SerializedTouch, SerializedTouchEvent, SerializedWheelEvent, } from '~types/events' +export const serializeTarget = (target: EventTarget): SerializedTarget => { + switch (true) { + case target instanceof HTMLInputElement: + case target instanceof HTMLSelectElement: + case target instanceof HTMLTextAreaElement: + return { + value: target.value, + ...(target instanceof HTMLInputElement && { checked: target.checked }), + ...(target instanceof HTMLSelectElement && { + selectedIndex: target.selectedIndex, + selectedOptions: [...target.selectedOptions].map(option => ({ + value: option.value, + text: option.text, + selected: option.selected, + })), + }), + } + case target instanceof HTMLElement: + return {} + } + + return {} +} + export const serializeBaseEvent = (event: Event): SerializedEvent => { return { type: event.type, + target: event.target ? serializeTarget(event.target) : null, + currentTarget: event.currentTarget ? serializeTarget(event.currentTarget) : null, bubbles: event.bubbles, cancelable: event.cancelable, composed: event.composed, @@ -55,12 +82,8 @@ export const serializeDragEvent = (event: DragEvent): SerializedDragEvent => { export const serializeInputEvent = (event: InputEvent): SerializedInputEvent => { return { ...serializeBaseEvent(event), - isTrusted: event.isTrusted, data: event.data, - target: { - value: (event.target as HTMLInputElement | HTMLTextAreaElement).value, - }, - } + } as SerializedInputEvent } export const serializeFocusEvent = (event: FocusEvent): SerializedFocusEvent => { diff --git a/src/vue/remote/createRemoteRenderer.ts b/src/vue/remote/createRemoteRenderer.ts index d4d2c00..2ec4d72 100644 --- a/src/vue/remote/createRemoteRenderer.ts +++ b/src/vue/remote/createRemoteRenderer.ts @@ -31,7 +31,7 @@ const nextSibling = (node: Node) => } const setElementText = ( - element: Component, + element: Root | Component, text: string ) => { const [node] = element.children diff --git a/tests/e2e/events-serializing.e2e.ts b/tests/e2e/events-serializing.e2e.ts index a94e7b3..2f31dc1 100644 --- a/tests/e2e/events-serializing.e2e.ts +++ b/tests/e2e/events-serializing.e2e.ts @@ -24,6 +24,14 @@ test('serialized InputEvent', async ({ page }) => { expect(await getSerializedEvent(page, 'input')).toEqual(expect.objectContaining({ type: 'input', + target: { + checked: false, + value: 'playwright@microsoft.com', + }, + currentTarget: { + checked: false, + value: 'playwright@microsoft.com', + }, bubbles: true, cancelable: false, composed: true, @@ -31,7 +39,6 @@ test('serialized InputEvent', async ({ page }) => { defaultPrevented: false, eventPhase: 2, isTrusted: true, - target: { value: 'playwright@microsoft.com' }, })) }) diff --git a/tests/integration/index.test.ts b/tests/integration/index.test.ts index 8ef58dd..bbcf791 100644 --- a/tests/integration/index.test.ts +++ b/tests/integration/index.test.ts @@ -175,6 +175,8 @@ describe('vue', () => { expect(onClick).toHaveBeenCalledTimes(1) expect(onClick).toHaveBeenCalledWith({ type: 'click', + target: {}, + currentTarget: {}, bubbles: true, button: 0, cancelable: true, @@ -235,6 +237,8 @@ describe('vue', () => { expect(onClick).toHaveBeenCalledTimes(1) expect(onClick).toHaveBeenCalledWith({ type: 'click', + target: {}, + currentTarget: {}, bubbles: false, cancelable: false, composed: false, @@ -273,6 +277,8 @@ describe('vue', () => { expect(onClick).toHaveBeenCalledTimes(1) expect(onClick).toHaveBeenCalledWith({ type: 'click', + target: {}, + currentTarget: {}, bubbles: true, button: 0, cancelable: true, diff --git a/types/events.d.ts b/types/events.d.ts index 38284ac..d4e1478 100644 --- a/types/events.d.ts +++ b/types/events.d.ts @@ -1,5 +1,7 @@ export interface SerializedEvent { type: Event['type']; + target: SerializedTarget | null; + currentTarget: SerializedTarget | null; bubbles: Event['bubbles']; cancelable: Event['cancelable']; composed: Event['composed']; @@ -23,12 +25,16 @@ export interface SerializedDataTransfer { files: SerializedFile[]; } +export interface SerializedTarget {} + +export interface SerializedInputEventTarget { + value: string; +} + export interface SerializedInputEvent extends SerializedEvent { isTrusted: InputEvent['isTrusted']; data: InputEvent['data']; - target: { - value: HTMLInputElement['value'] | HTMLTextAreaElement['value']; - }; + target: SerializedInputEventTarget; } export interface SerializedDragEvent extends SerializedMouseEvent { diff --git a/yarn.lock b/yarn.lock index 325d718..c4761f5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -165,7 +165,7 @@ chalk "^2.4.2" js-tokens "^4.0.0" -"@babel/parser@^7.23.6", "@babel/parser@^7.23.9": +"@babel/parser@^7.23.9": version "7.23.9" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.9.tgz#7b903b6149b0f8fa7ad564af646c4c38a77fc44b" integrity sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA== @@ -1470,17 +1470,6 @@ resolved "https://registry.yarnpkg.com/@vscode/l10n/-/l10n-0.0.18.tgz#916d3a5e960dbab47c1c56f58a7cb5087b135c95" integrity sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ== -"@vue/compiler-core@3.4.15": - version "3.4.15" - resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.4.15.tgz#be20d1bbe19626052500b48969302cb6f396d36e" - integrity sha512-XcJQVOaxTKCnth1vCxEChteGuwG6wqnUHxAm1DO3gCz0+uXKaJNx8/digSz4dLALCy8n2lKq24jSUs8segoqIw== - dependencies: - "@babel/parser" "^7.23.6" - "@vue/shared" "3.4.15" - entities "^4.5.0" - estree-walker "^2.0.2" - source-map-js "^1.0.2" - "@vue/compiler-core@3.5.13": version "3.5.13" resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.5.13.tgz#b0ae6c4347f60c03e849a05d34e5bf747c9bda05" @@ -1492,15 +1481,7 @@ estree-walker "^2.0.2" source-map-js "^1.2.0" -"@vue/compiler-dom@3.4.15": - version "3.4.15" - resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.4.15.tgz#753f5ed55f78d33dff04701fad4d76ff0cf81ee5" - integrity sha512-wox0aasVV74zoXyblarOM3AZQz/Z+OunYcIHe1OsGclCHt8RsRm04DObjefaI82u6XDzv+qGWZ24tIsRAIi5MQ== - dependencies: - "@vue/compiler-core" "3.4.15" - "@vue/shared" "3.4.15" - -"@vue/compiler-dom@^3.4.0", "@vue/compiler-dom@^3.5.0": +"@vue/compiler-dom@3.5.13", "@vue/compiler-dom@^3.4.0", "@vue/compiler-dom@^3.5.0": version "3.5.13" resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz#bb1b8758dbc542b3658dda973b98a1c9311a8a58" integrity sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA== @@ -1508,28 +1489,28 @@ "@vue/compiler-core" "3.5.13" "@vue/shared" "3.5.13" -"@vue/compiler-sfc@3.4.15", "@vue/compiler-sfc@^3.4.15": - version "3.4.15" - resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.4.15.tgz#4e5811e681955fcec886cebbec483f6ae463a64b" - integrity sha512-LCn5M6QpkpFsh3GQvs2mJUOAlBQcCco8D60Bcqmf3O3w5a+KWS5GvYbrrJBkgvL1BDnTp+e8q0lXCLgHhKguBA== +"@vue/compiler-sfc@3.5.13", "@vue/compiler-sfc@^3.5.13": + version "3.5.13" + resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz#461f8bd343b5c06fac4189c4fef8af32dea82b46" + integrity sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ== dependencies: - "@babel/parser" "^7.23.6" - "@vue/compiler-core" "3.4.15" - "@vue/compiler-dom" "3.4.15" - "@vue/compiler-ssr" "3.4.15" - "@vue/shared" "3.4.15" + "@babel/parser" "^7.25.3" + "@vue/compiler-core" "3.5.13" + "@vue/compiler-dom" "3.5.13" + "@vue/compiler-ssr" "3.5.13" + "@vue/shared" "3.5.13" estree-walker "^2.0.2" - magic-string "^0.30.5" - postcss "^8.4.33" - source-map-js "^1.0.2" + magic-string "^0.30.11" + postcss "^8.4.48" + source-map-js "^1.2.0" -"@vue/compiler-ssr@3.4.15": - version "3.4.15" - resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.4.15.tgz#a910a5b89ba4f0a776e40b63d69bdae2f50616cf" - integrity sha512-1jdeQyiGznr8gjFDadVmOJqZiLNSsMa5ZgqavkPZ8O2wjHv0tVuAEsw5hTdUoUW4232vpBbL/wJhzVW/JwY1Uw== +"@vue/compiler-ssr@3.5.13": + version "3.5.13" + resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz#e771adcca6d3d000f91a4277c972a996d07f43ba" + integrity sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA== dependencies: - "@vue/compiler-dom" "3.4.15" - "@vue/shared" "3.4.15" + "@vue/compiler-dom" "3.5.13" + "@vue/shared" "3.5.13" "@vue/compiler-vue2@^2.7.16": version "2.7.16" @@ -1607,42 +1588,38 @@ vscode-languageserver-textdocument "^1.0.11" vscode-uri "^3.0.8" -"@vue/reactivity@3.4.15": - version "3.4.15" - resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.4.15.tgz#ad9d9b83f5398d2e8660ad5cfc0f171e7679a9a1" - integrity sha512-55yJh2bsff20K5O84MxSvXKPHHt17I2EomHznvFiJCAZpJTNW8IuLj1xZWMLELRhBK3kkFV/1ErZGHJfah7i7w== +"@vue/reactivity@3.5.13": + version "3.5.13" + resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.5.13.tgz#b41ff2bb865e093899a22219f5b25f97b6fe155f" + integrity sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg== dependencies: - "@vue/shared" "3.4.15" + "@vue/shared" "3.5.13" -"@vue/runtime-core@3.4.15": - version "3.4.15" - resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.4.15.tgz#f81e2fd2108ea41a6d5c61c2462b11dfb754fdf0" - integrity sha512-6E3by5m6v1AkW0McCeAyhHTw+3y17YCOKG0U0HDKDscV4Hs0kgNT5G+GCHak16jKgcCDHpI9xe5NKb8sdLCLdw== +"@vue/runtime-core@3.5.13": + version "3.5.13" + resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.5.13.tgz#1fafa4bf0b97af0ebdd9dbfe98cd630da363a455" + integrity sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw== dependencies: - "@vue/reactivity" "3.4.15" - "@vue/shared" "3.4.15" + "@vue/reactivity" "3.5.13" + "@vue/shared" "3.5.13" -"@vue/runtime-dom@3.4.15": - version "3.4.15" - resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.4.15.tgz#108ef86aa7334ead5d6b9c56a7d93679e1e45406" - integrity sha512-EVW8D6vfFVq3V/yDKNPBFkZKGMFSvZrUQmx196o/v2tHKdwWdiZjYUBS+0Ez3+ohRyF8Njwy/6FH5gYJ75liUw== +"@vue/runtime-dom@3.5.13": + version "3.5.13" + resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz#610fc795de9246300e8ae8865930d534e1246215" + integrity sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog== dependencies: - "@vue/runtime-core" "3.4.15" - "@vue/shared" "3.4.15" + "@vue/reactivity" "3.5.13" + "@vue/runtime-core" "3.5.13" + "@vue/shared" "3.5.13" csstype "^3.1.3" -"@vue/server-renderer@3.4.15": - version "3.4.15" - resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.4.15.tgz#34438f998e6f6370fac78883a75efe136631957f" - integrity sha512-3HYzaidu9cHjrT+qGUuDhFYvF/j643bHC6uUN9BgM11DVy+pM6ATsG6uPBLnkwOgs7BpJABReLmpL3ZPAsUaqw== +"@vue/server-renderer@3.5.13": + version "3.5.13" + resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.5.13.tgz#429ead62ee51de789646c22efe908e489aad46f7" + integrity sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA== dependencies: - "@vue/compiler-ssr" "3.4.15" - "@vue/shared" "3.4.15" - -"@vue/shared@3.4.15": - version "3.4.15" - resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.4.15.tgz#e7d2ea050c667480cb5e1a6df2ac13bcd03a8f30" - integrity sha512-KzfPTxVaWfB+eGcGdbSf4CWdaXcGDqckoeXUh7SB3fZdEtzPCK2Vq9B/lRRL3yutax/LWITz+SwvgyOxz5V75g== + "@vue/compiler-ssr" "3.5.13" + "@vue/shared" "3.5.13" "@vue/shared@3.5.13", "@vue/shared@^3.4.0", "@vue/shared@^3.5.0": version "3.5.13" @@ -4285,13 +4262,6 @@ magic-string@^0.30.3: dependencies: "@jridgewell/sourcemap-codec" "^1.4.15" -magic-string@^0.30.5: - version "0.30.5" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.5.tgz#1994d980bd1c8835dc6e78db7cbd4ae4f24746f9" - integrity sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA== - dependencies: - "@jridgewell/sourcemap-codec" "^1.4.15" - magicast@^0.3.5: version "0.3.5" resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.3.5.tgz#8301c3c7d66704a0771eb1bad74274f0ec036739" @@ -4830,6 +4800,11 @@ picocolors@^1.1.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + picomatch@^2.2.2, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" @@ -4888,15 +4863,6 @@ postcss-selector-parser@^6.0.15: cssesc "^3.0.0" util-deprecate "^1.0.2" -postcss@^8.4.33: - version "8.4.33" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.33.tgz#1378e859c9f69bf6f638b990a0212f43e2aaa742" - integrity sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg== - dependencies: - nanoid "^3.3.7" - picocolors "^1.0.0" - source-map-js "^1.0.2" - postcss@^8.4.38: version "8.4.38" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.38.tgz#b387d533baf2054288e337066d81c6bee9db9e0e" @@ -4915,6 +4881,15 @@ postcss@^8.4.43: picocolors "^1.1.0" source-map-js "^1.2.1" +postcss@^8.4.48: + version "8.4.49" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.49.tgz#4ea479048ab059ab3ae61d082190fabfd994fe19" + integrity sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA== + dependencies: + nanoid "^3.3.7" + picocolors "^1.1.1" + source-map-js "^1.2.1" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -5420,11 +5395,6 @@ slash@^4.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== -source-map-js@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" - integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== - source-map-js@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" @@ -6274,16 +6244,16 @@ vue-eslint-parser@^9.4.2: lodash "^4.17.21" semver "^7.3.6" -vue@^3.4.15: - version "3.4.15" - resolved "https://registry.yarnpkg.com/vue/-/vue-3.4.15.tgz#91f979844ffca9239dff622ba4c79c5d5524b88c" - integrity sha512-jC0GH4KkWLWJOEQjOpkqU1bQsBwf4R1rsFtw5GQJbjHVKWDzO6P0nWWBTmjp1xSemAioDFj1jdaK1qa3DnMQoQ== +vue@^3.5.13: + version "3.5.13" + resolved "https://registry.yarnpkg.com/vue/-/vue-3.5.13.tgz#9f760a1a982b09c0c04a867903fc339c9f29ec0a" + integrity sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ== dependencies: - "@vue/compiler-dom" "3.4.15" - "@vue/compiler-sfc" "3.4.15" - "@vue/runtime-dom" "3.4.15" - "@vue/server-renderer" "3.4.15" - "@vue/shared" "3.4.15" + "@vue/compiler-dom" "3.5.13" + "@vue/compiler-sfc" "3.5.13" + "@vue/runtime-dom" "3.5.13" + "@vue/server-renderer" "3.5.13" + "@vue/shared" "3.5.13" w3c-xmlserializer@^5.0.0: version "5.0.0" From b5bdf8e4040f8ff582bc0b95c69ce9a4d0dcb9bb Mon Sep 17 00:00:00 2001 From: Kirill Zaytsev Date: Sat, 28 Dec 2024 22:03:07 +0400 Subject: [PATCH 2/4] fix: Fixed child node insertion --- src/dom/remote/context.ts | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/dom/remote/context.ts b/src/dom/remote/context.ts index 54d62ed..4ea4bbe 100644 --- a/src/dom/remote/context.ts +++ b/src/dom/remote/context.ts @@ -298,24 +298,28 @@ const insertBefore = ( throw new Error('Cannot insert a node that was not created by this remote root') } - const currentParent = child.parent - const currentIndex = currentParent?.children.indexOf(child) ?? -1 + if (before && before.id === child.id) return + if (before && !parent.children.includes(before)) { + throw new DOMException( + 'Cannot add a child before an element that is not a child of the target parent.', + 'HierarchyRequestError' + ) + } - return update(context, parent, (channel) => { - const beforeIndex = before == null - ? parent.children.length - 1 - : parent.children.indexOf(before) + const oldIndex = parent.children.indexOf(child) ?? -1 + const oldParent = child.parent - channel( - ACTION_INSERT_CHILD, - parent.id, - beforeIndex < currentIndex || currentIndex < 0 - ? beforeIndex - : beforeIndex - 1, - child.serialize(), - currentParent ? currentParent.id : false - ) - }, () => insert(context, parent, child, before)) + const beforeIndex = before ? parent.children.indexOf(before) : -1 + + return update(context, parent, (channel) => channel( + ACTION_INSERT_CHILD, + parent.id, + beforeIndex < 0 + ? parent.children.length + : oldIndex < 0 || oldIndex > beforeIndex ? beforeIndex : beforeIndex - 1, + child.serialize(), + oldParent ? oldParent.id : false + ), () => insert(context, parent, child, before)) } /** @TODO: Объединение удаления нескольких узлов в один запрос */ From 496e6e4817dbb85f989ada847b2b1a66243feef5 Mon Sep 17 00:00:00 2001 From: Kirill Zaytsev Date: Sat, 28 Dec 2024 22:15:55 +0400 Subject: [PATCH 3/4] feat: Added print method to RemoteComment, RemoteComponent and RemoteText --- src/dom/remote/tree.ts | 4 ++++ src/dom/remote/tree/comment.ts | 1 + src/dom/remote/tree/component.ts | 29 +++++++++++++++++++++++++++- src/dom/remote/tree/text.ts | 1 + tests/integration/dom/remote.test.ts | 4 ++++ 5 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/dom/remote/tree.ts b/src/dom/remote/tree.ts index ba2ac15..16d2602 100644 --- a/src/dom/remote/tree.ts +++ b/src/dom/remote/tree.ts @@ -137,6 +137,7 @@ export interface RemoteComment extends Rem update (text: string): void | Promise; remove (): void | Promise; serialize (): SerializedComment; + print (): string; } export type RemoteComponentOption< @@ -218,6 +219,8 @@ export interface RemoteComponent< remove (): void | Promise; serialize (): SerializedComponent>; + + print (): string; } export interface RemoteFragment extends RemoteNode { @@ -280,6 +283,7 @@ export interface RemoteText extends Remote update (text: string): void | Promise; serialize (): SerializedText; remove (): void | Promise; + print (): string; } export type UnknownComponent = RemoteComponent diff --git a/src/dom/remote/tree/comment.ts b/src/dom/remote/tree/comment.ts index 2f5e0fd..ba50fb4 100644 --- a/src/dom/remote/tree/comment.ts +++ b/src/dom/remote/tree/comment.ts @@ -27,6 +27,7 @@ export const createRemoteComment = ( ), serialize: () => ({ id, kind: KIND_COMMENT, text: data.text }), remove: () => node.parent?.removeChild(node), + print: () => `Comment(${data.text})`, } as RemoteComment context.collect(node) diff --git a/src/dom/remote/tree/component.ts b/src/dom/remote/tree/component.ts index 26ef17f..5198389 100644 --- a/src/dom/remote/tree/component.ts +++ b/src/dom/remote/tree/component.ts @@ -103,6 +103,8 @@ export function createRemoteComponent c.serialize()), }), + + print: () => _print(id, type, data.properties.original as PropertiesOf, data.children), } as RemoteComponent context.collect(node) @@ -237,4 +239,29 @@ function serializeProperty (property: unknown) { return isRemoteFragment(property) ? property.serialize() : property -} \ No newline at end of file +} + +function _print >( + id: string, + type: T | RemoteComponentDescriptor, + _properties: PropertiesOf | null | undefined, + children: ReadonlyArray< + | RemoteComment + | RemoteComponent, R> + | RemoteText + | string + > +) { + const _head = `${typeof type === 'string' ? type : type.type}:${id}` + const _children = children.map(c => typeof c === 'string' ? c : c.print()) + const _body = _children.length > 0 ? `\n${_indent(_children.join(',\n'))}\n` : '' + + return `${_head}[${_body}]` +} + +function _indent (text: string) { + return text + .split('\n') + .map(line => ` ${line}`) + .join('\n') +} diff --git a/src/dom/remote/tree/text.ts b/src/dom/remote/tree/text.ts index 5e5ed41..6c2d036 100644 --- a/src/dom/remote/tree/text.ts +++ b/src/dom/remote/tree/text.ts @@ -27,6 +27,7 @@ export const createRemoteText = ( ), serialize: () => ({ id, kind: KIND_TEXT, text: data.text }), remove: () => node.parent?.removeChild(node), + print: () => `Text(${data.text})`, } as RemoteText context.collect(node) diff --git a/tests/integration/dom/remote.test.ts b/tests/integration/dom/remote.test.ts index 13ade70..7101e9c 100644 --- a/tests/integration/dom/remote.test.ts +++ b/tests/integration/dom/remote.test.ts @@ -45,6 +45,7 @@ describe('dom/remote', () => { expect(comment.id).toEqual('1') expect(comment.text).toEqual('v-if') + expect(comment.print()).toEqual('Comment(v-if)') }) }) @@ -68,6 +69,7 @@ describe('dom/remote', () => { expect(card.progenitor).toBeNull() expect(card.parent).toBeNull() expect(card.children).toEqual([]) + expect(card.print()).toEqual('VCard:1[]') }) test('creates component with children', () => { @@ -83,6 +85,7 @@ describe('dom/remote', () => { expect(card.children).toHaveLength(2) expect((card.children[0] as UnknownComponent).type).toEqual('VImage') expect((card.children[1] as UnknownComponent).type).toEqual('VButton') + expect(card.print()).toEqual('VCard:3[\n VImage:1[],\n VButton:2[]\n]') }) test('creates component with single child', () => { @@ -157,6 +160,7 @@ describe('dom/remote', () => { expect(text.root).toEqual(root) expect(text.progenitor).toBeNull() expect(text.parent).toBeNull() + expect(text.print()).toEqual('Text()') }) }) From b5ef645341d3405178d7a59d52358ac62c2ad4bb Mon Sep 17 00:00:00 2001 From: Kirill Zaytsev Date: Sat, 28 Dec 2024 22:26:33 +0400 Subject: [PATCH 4/4] ci: ubuntu-latest image replaced with ubuntu-22.04 --- .github/workflows/tests.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2f64995..93fc7e8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,7 +8,7 @@ concurrency: jobs: eslint: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 strategy: matrix: @@ -42,7 +42,7 @@ jobs: needs: eslint timeout-minutes: 60 - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 strategy: matrix: @@ -88,7 +88,7 @@ jobs: needs: [eslint, tests] timeout-minutes: 60 - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 strategy: matrix: @@ -114,10 +114,10 @@ jobs: key: ${{ runner.OS }}-node-${{ matrix.node-version }}-yarn-${{ hashFiles('**/yarn.lock') }} restore-keys: | ${{ runner.OS }}-node-${{ matrix.node-version }}-yarn- - + - name: Install Playwright Browsers run: npx playwright install chromium firefox --with-deps - + - name: Build e2e example app run: yarn e2e:build