feat: add getLocatorStringForElement and fix timeout in getCurrentPage

This commit is contained in:
Tommy D. Rossi
2025-11-21 22:27:48 +01:00
parent 17f6c48641
commit 35dbcab181
5 changed files with 430 additions and 7 deletions
+8
View File
@@ -1,5 +1,13 @@
# Changelog
## 0.0.8
### Patch Changes
- Added `getLocatorStringForElement` utility to `execute` tool context
- Helper generates Playwright locator strings for element handles
- Fixed bug where timeout was not correctly passed to `waitForEvent` in `getCurrentPage`
## 0.0.7
### Patch Changes
+2 -1
View File
@@ -1,7 +1,7 @@
{
"name": "playwriter",
"description": "",
"version": "0.0.7",
"version": "0.0.8",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -26,6 +26,7 @@
"author": "Tommaso De Rossi, morse <beats.by.morse@gmail.com>",
"license": "",
"devDependencies": {
"@mizchi/selector-generator": "1.50.0-next",
"@types/node": "^24.10.1",
"@vitest/ui": "^4.0.8",
"vite-node": "^5.0.0",
+34 -2
View File
@@ -51,6 +51,7 @@ interface VMContext {
searchString?: string | RegExp
contextLines?: number
}) => Promise<string>
getLocatorStringForElement: (element: any) => Promise<string>
resetPlaywright: () => Promise<{ page: Page; context: BrowserContext }>
require: NodeRequire
import: (specifier: string) => Promise<any>
@@ -58,6 +59,8 @@ interface VMContext {
type VMContextWithGlobals = VMContext & typeof usefulGlobals
type SelectorGenerator = typeof import('@mizchi/selector-generator')
const state: State = {
isConnected: false,
page: null,
@@ -125,7 +128,7 @@ async function ensureConnection(): Promise<{ browser: Browser; page: Page }> {
return { browser, page }
}
async function getCurrentPage() {
async function getCurrentPage(timeout = 5000) {
if (state.page) {
return state.page
}
@@ -202,7 +205,7 @@ server.tool(
async ({ code, timeout }) => {
await ensureConnection()
const page = await getCurrentPage()
const page = await getCurrentPage(timeout)
const context = state.context || page.context()
console.error('Executing code:', code)
@@ -277,12 +280,40 @@ server.tool(
throw new Error('accessibilitySnapshot is not available on this page')
}
const getLocatorStringForElement = async (element: any) => {
if (!element || typeof element.evaluate !== 'function') {
throw new Error(
'getLocatorStringForElement: argument must be a Playwright Locator or ElementHandle',
)
}
return await element.evaluate(async (el: any) => {
const WIN = globalThis as any
if (!WIN.__selectorGenerator) {
const module: SelectorGenerator = await import(
// @ts-ignore
'https://unpkg.com/@mizchi/selector-generator@1.50.0-next/dist/index.js'
)
WIN.__selectorGenerator = {
createSelectorGenerator: module.createSelectorGenerator,
toLocator: module.toLocator,
}
}
const { createSelectorGenerator, toLocator } =
WIN.__selectorGenerator as SelectorGenerator
const generator = createSelectorGenerator(WIN)
const result = generator(el)
return toLocator(result.selector, 'javascript')
})
}
let vmContextObj: VMContextWithGlobals = {
page,
context,
state,
console: customConsole,
accessibilitySnapshot,
getLocatorStringForElement,
resetPlaywright: async () => {
const { page: newPage, context: newContext } = await resetConnection()
@@ -294,6 +325,7 @@ server.tool(
state,
console: customConsole,
accessibilitySnapshot,
getLocatorStringForElement,
resetPlaywright: vmContextObj.resetPlaywright,
require,
import: vmContextObj.import,
+10
View File
@@ -91,6 +91,16 @@ Then you can use `page.locator(`aria-ref=${ref}`)` to get an element with a spec
IMPORTANT: notice that we do not add any quotes in `aria-ref`! it MUST be called without quotes
## getting selector for a locator identified by snapshot aria-ref
in some cases you want to get a selector for a locator you just identified using `const element = page.locator('aria-ref=${ref}')`. To do so you can use `await getLocatorStringForElement(element)`. This is useful if you need to find other elements of the same type in a list for example. If you know the selector you can usually change a bit the selector to find the other elements of the same type in the list or table
```js
const loc = page.locator('aria-ref=123');
console.log(await getLocatorStringForElement(loc));
// => "getByRole('button', { name: 'Save' })" or similar
```
## finding specific elements with snapshot
You can use `searchString` to find specific elements in the snapshot without reading the whole page structure. This is useful for finding forms, textareas, or specific text.
+376 -4
View File
@@ -25,7 +25,7 @@ importers:
version: 7.2.2(@types/node@24.10.1)(tsx@4.20.6)
vitest:
specifier: ^4.0.8
version: 4.0.8(@types/node@24.10.1)(@vitest/ui@4.0.8)(tsx@4.20.6)
version: 4.0.8(@types/node@24.10.1)(@vitest/ui@4.0.8)(jsdom@27.2.0)(tsx@4.20.6)
extension:
dependencies:
@@ -87,6 +87,9 @@ importers:
specifier: ^3
version: 3.25.76
devDependencies:
'@mizchi/selector-generator':
specifier: 1.50.0-next
version: 1.50.0-next
'@types/node':
specifier: ^24.10.1
version: 24.10.1
@@ -98,10 +101,22 @@ importers:
version: 5.0.0(@types/node@24.10.1)(tsx@4.20.6)
vitest:
specifier: ^4.0.8
version: 4.0.8(@types/node@24.10.1)(@vitest/ui@4.0.8)(tsx@4.20.6)
version: 4.0.8(@types/node@24.10.1)(@vitest/ui@4.0.8)(jsdom@27.2.0)(tsx@4.20.6)
packages:
'@acemir/cssom@0.9.23':
resolution: {integrity: sha512-2kJ1HxBKzPLbmhZpxBiTZggjtgCwKg1ma5RHShxvd6zgqhDEdEkzpiwe7jLkI2p2BrZvFCXIihdoMkl1H39VnA==}
'@asamuzakjp/css-color@4.1.0':
resolution: {integrity: sha512-9xiBAtLn4aNsa4mDnpovJvBn72tNEIACyvlqaNJ+ADemR+yeMJWnBudOi2qGDviJa7SwcDOU/TRh5dnET7qk0w==}
'@asamuzakjp/dom-selector@6.7.4':
resolution: {integrity: sha512-buQDjkm+wDPXd6c13534URWZqbz0RP5PAhXZ+LIoa5LgwInT9HVJvGIJivg75vi8I13CxDGdTnz+aY5YUJlIAA==}
'@asamuzakjp/nwsapi@2.3.9':
resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==}
'@babel/runtime@7.28.4':
resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==}
engines: {node: '>=6.9.0'}
@@ -161,6 +176,38 @@ packages:
'@changesets/write@0.4.0':
resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==}
'@csstools/color-helpers@5.1.0':
resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==}
engines: {node: '>=18'}
'@csstools/css-calc@2.1.4':
resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==}
engines: {node: '>=18'}
peerDependencies:
'@csstools/css-parser-algorithms': ^3.0.5
'@csstools/css-tokenizer': ^3.0.4
'@csstools/css-color-parser@3.1.0':
resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==}
engines: {node: '>=18'}
peerDependencies:
'@csstools/css-parser-algorithms': ^3.0.5
'@csstools/css-tokenizer': ^3.0.4
'@csstools/css-parser-algorithms@3.0.5':
resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==}
engines: {node: '>=18'}
peerDependencies:
'@csstools/css-tokenizer': ^3.0.4
'@csstools/css-syntax-patches-for-csstree@1.0.17':
resolution: {integrity: sha512-LCC++2h8pLUSPY+EsZmrrJ1EOUu+5iClpEiDhhdw3zRJpPbABML/N5lmRuBHjxtKm9VnRcsUzioyD0sekFMF0A==}
engines: {node: '>=18'}
'@csstools/css-tokenizer@3.0.4':
resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==}
engines: {node: '>=18'}
'@esbuild/aix-ppc64@0.21.5':
resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
engines: {node: '>=12'}
@@ -486,6 +533,10 @@ packages:
'@manypkg/get-packages@1.1.3':
resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==}
'@mizchi/selector-generator@1.50.0-next':
resolution: {integrity: sha512-4KHU48IuzEAh+xv3I2GYZXsarDQqh+WzVGYv0WYvQUK78R4cMMyxlydqIql28mfuHQH9L5pFBBJhPtyvxDm1RA==}
engines: {node: '>=22.*'}
'@modelcontextprotocol/sdk@1.21.1':
resolution: {integrity: sha512-UyLFcJLDvUuZbGnaQqXFT32CpPpGj7VS19roLut6gkQVhb439xUzYWbsUvdI3ZPL+2hnFosuugtYWE0Mcs1rmQ==}
engines: {node: '>=18'}
@@ -688,6 +739,10 @@ packages:
resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
engines: {node: '>= 0.6'}
agent-base@7.1.4:
resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
engines: {node: '>= 14'}
ajv-formats@3.0.1:
resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==}
peerDependencies:
@@ -730,6 +785,9 @@ packages:
resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==}
engines: {node: '>=4'}
bidi-js@1.0.3:
resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==}
binary-extensions@2.3.0:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
@@ -821,6 +879,18 @@ packages:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
css-tree@3.1.0:
resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==}
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
cssstyle@5.3.3:
resolution: {integrity: sha512-OytmFH+13/QXONJcC75QNdMtKpceNk3u8ThBjyyYjkEcy/ekBwR1mMAuNvi3gdBPW3N5TlCzQ0WZw8H0lN/bDw==}
engines: {node: '>=20'}
data-urls@6.0.0:
resolution: {integrity: sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==}
engines: {node: '>=20'}
date-fns@2.30.0:
resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==}
engines: {node: '>=0.11'}
@@ -834,6 +904,9 @@ packages:
supports-color:
optional: true
decimal.js@10.6.0:
resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==}
depd@2.0.0:
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
engines: {node: '>= 0.8'}
@@ -867,6 +940,10 @@ packages:
resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==}
engines: {node: '>=8.6'}
entities@6.0.1:
resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
engines: {node: '>=0.12'}
es-define-property@1.0.1:
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
engines: {node: '>= 0.4'}
@@ -1046,10 +1123,22 @@ packages:
resolution: {integrity: sha512-BIdolzGpDO9MQ4nu3AUuDwHZZ+KViNm+EZ75Ae55eMXMqLVhDFqEMXxtUe9Qh8hjL+pIna/frs2j6Y2yD5Ua/g==}
engines: {node: '>=16.9.0'}
html-encoding-sniffer@4.0.0:
resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==}
engines: {node: '>=18'}
http-errors@2.0.0:
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
engines: {node: '>= 0.8'}
http-proxy-agent@7.0.2:
resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
engines: {node: '>= 14'}
https-proxy-agent@7.0.6:
resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
engines: {node: '>= 14'}
human-id@4.1.2:
resolution: {integrity: sha512-v/J+4Z/1eIJovEBdlV5TYj1IR+ZiohcYGRY+qN/oC9dAfKzVT023N/Bgw37hrKCoVRBvk3bqyzpr2PP5YeTMSg==}
hasBin: true
@@ -1093,6 +1182,9 @@ packages:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
is-potential-custom-element-name@1.0.1:
resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
is-promise@4.0.0:
resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
@@ -1111,6 +1203,15 @@ packages:
resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
hasBin: true
jsdom@27.2.0:
resolution: {integrity: sha512-454TI39PeRDW1LgpyLPyURtB4Zx1tklSr6+OFOipsxGUH1WMTvk6C65JQdrj455+DP2uJ1+veBEHTGFKWVLFoA==}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
peerDependencies:
canvas: ^3.0.0
peerDependenciesMeta:
canvas:
optional: true
json-schema-traverse@1.0.0:
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
@@ -1130,6 +1231,10 @@ packages:
lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
lru-cache@11.2.2:
resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==}
engines: {node: 20 || >=22}
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
@@ -1137,6 +1242,9 @@ packages:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
mdn-data@2.12.2:
resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==}
media-typer@1.1.0:
resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==}
engines: {node: '>= 0.8'}
@@ -1230,6 +1338,9 @@ packages:
package-manager-detector@0.2.11:
resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==}
parse5@8.0.0:
resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==}
parseurl@1.3.3:
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
engines: {node: '>= 0.8'}
@@ -1294,6 +1405,10 @@ packages:
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
engines: {node: '>= 0.10'}
punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
qs@6.14.0:
resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
engines: {node: '>=0.6'}
@@ -1360,6 +1475,10 @@ packages:
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
saxes@6.0.0:
resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
engines: {node: '>=v12.22.7'}
semver@7.7.3:
resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==}
engines: {node: '>=10'}
@@ -1466,6 +1585,9 @@ packages:
resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
engines: {node: '>=10'}
symbol-tree@3.2.4:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
term-size@2.2.1:
resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==}
engines: {node: '>=8'}
@@ -1484,6 +1606,13 @@ packages:
resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==}
engines: {node: '>=14.0.0'}
tldts-core@7.0.18:
resolution: {integrity: sha512-jqJC13oP4FFAahv4JT/0WTDrCF9Okv7lpKtOZUGPLiAnNbACcSg8Y8T+Z9xthOmRBqi/Sob4yi0TE0miRCvF7Q==}
tldts@7.0.18:
resolution: {integrity: sha512-lCcgTAgMxQ1JKOWrVGo6E69Ukbnx4Gc1wiYLRf6J5NN4HRYJtCby1rPF8rkQ4a6qqoFBK5dvjJ1zJ0F7VfDSvw==}
hasBin: true
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
@@ -1496,6 +1625,14 @@ packages:
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
engines: {node: '>=6'}
tough-cookie@6.0.0:
resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==}
engines: {node: '>=16'}
tr46@6.0.0:
resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==}
engines: {node: '>=20'}
tree-kill@1.2.2:
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
hasBin: true
@@ -1651,6 +1788,26 @@ packages:
jsdom:
optional: true
w3c-xmlserializer@5.0.0:
resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
engines: {node: '>=18'}
webidl-conversions@8.0.0:
resolution: {integrity: sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA==}
engines: {node: '>=20'}
whatwg-encoding@3.1.1:
resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
engines: {node: '>=18'}
whatwg-mimetype@4.0.0:
resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
engines: {node: '>=18'}
whatwg-url@15.1.0:
resolution: {integrity: sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==}
engines: {node: '>=20'}
which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
@@ -1680,6 +1837,13 @@ packages:
utf-8-validate:
optional: true
xml-name-validator@5.0.0:
resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
engines: {node: '>=18'}
xmlchars@2.2.0:
resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
@@ -1720,6 +1884,30 @@ packages:
snapshots:
'@acemir/cssom@0.9.23':
optional: true
'@asamuzakjp/css-color@4.1.0':
dependencies:
'@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
'@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
'@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
'@csstools/css-tokenizer': 3.0.4
lru-cache: 11.2.2
optional: true
'@asamuzakjp/dom-selector@6.7.4':
dependencies:
'@asamuzakjp/nwsapi': 2.3.9
bidi-js: 1.0.3
css-tree: 3.1.0
is-potential-custom-element-name: 1.0.1
lru-cache: 11.2.2
optional: true
'@asamuzakjp/nwsapi@2.3.9':
optional: true
'@babel/runtime@7.28.4': {}
'@changesets/apply-release-plan@7.0.13':
@@ -1866,6 +2054,34 @@ snapshots:
human-id: 4.1.2
prettier: 2.8.8
'@csstools/color-helpers@5.1.0':
optional: true
'@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
dependencies:
'@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
'@csstools/css-tokenizer': 3.0.4
optional: true
'@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
dependencies:
'@csstools/color-helpers': 5.1.0
'@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
'@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
'@csstools/css-tokenizer': 3.0.4
optional: true
'@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)':
dependencies:
'@csstools/css-tokenizer': 3.0.4
optional: true
'@csstools/css-syntax-patches-for-csstree@1.0.17':
optional: true
'@csstools/css-tokenizer@3.0.4':
optional: true
'@esbuild/aix-ppc64@0.21.5':
optional: true
@@ -2051,6 +2267,8 @@ snapshots:
globby: 11.1.0
read-yaml-file: 1.1.0
'@mizchi/selector-generator@1.50.0-next': {}
'@modelcontextprotocol/sdk@1.21.1':
dependencies:
ajv: 8.17.1
@@ -2222,7 +2440,7 @@ snapshots:
sirv: 3.0.2
tinyglobby: 0.2.15
tinyrainbow: 3.0.3
vitest: 4.0.8(@types/node@24.10.1)(@vitest/ui@4.0.8)(tsx@4.20.6)
vitest: 4.0.8(@types/node@24.10.1)(@vitest/ui@4.0.8)(jsdom@27.2.0)(tsx@4.20.6)
'@vitest/utils@4.0.8':
dependencies:
@@ -2234,6 +2452,9 @@ snapshots:
mime-types: 3.0.1
negotiator: 1.0.0
agent-base@7.1.4:
optional: true
ajv-formats@3.0.1(ajv@8.17.1):
optionalDependencies:
ajv: 8.17.1
@@ -2270,6 +2491,11 @@ snapshots:
dependencies:
is-windows: 1.0.2
bidi-js@1.0.3:
dependencies:
require-from-string: 2.0.2
optional: true
binary-extensions@2.3.0: {}
body-parser@2.2.0:
@@ -2374,6 +2600,25 @@ snapshots:
shebang-command: 2.0.0
which: 2.0.2
css-tree@3.1.0:
dependencies:
mdn-data: 2.12.2
source-map-js: 1.2.1
optional: true
cssstyle@5.3.3:
dependencies:
'@asamuzakjp/css-color': 4.1.0
'@csstools/css-syntax-patches-for-csstree': 1.0.17
css-tree: 3.1.0
optional: true
data-urls@6.0.0:
dependencies:
whatwg-mimetype: 4.0.0
whatwg-url: 15.1.0
optional: true
date-fns@2.30.0:
dependencies:
'@babel/runtime': 7.28.4
@@ -2382,6 +2627,9 @@ snapshots:
dependencies:
ms: 2.1.3
decimal.js@10.6.0:
optional: true
depd@2.0.0: {}
detect-indent@6.1.0: {}
@@ -2409,6 +2657,9 @@ snapshots:
ansi-colors: 4.1.3
strip-ansi: 6.0.1
entities@6.0.1:
optional: true
es-define-property@1.0.1: {}
es-errors@1.3.0: {}
@@ -2648,6 +2899,11 @@ snapshots:
hono@4.10.6: {}
html-encoding-sniffer@4.0.0:
dependencies:
whatwg-encoding: 3.1.1
optional: true
http-errors@2.0.0:
dependencies:
depd: 2.0.0
@@ -2656,6 +2912,22 @@ snapshots:
statuses: 2.0.1
toidentifier: 1.0.1
http-proxy-agent@7.0.2:
dependencies:
agent-base: 7.1.4
debug: 4.4.3
transitivePeerDependencies:
- supports-color
optional: true
https-proxy-agent@7.0.6:
dependencies:
agent-base: 7.1.4
debug: 4.4.3
transitivePeerDependencies:
- supports-color
optional: true
human-id@4.1.2: {}
iconv-lite@0.6.3:
@@ -2686,6 +2958,9 @@ snapshots:
is-number@7.0.0: {}
is-potential-custom-element-name@1.0.1:
optional: true
is-promise@4.0.0: {}
is-subdir@1.2.0:
@@ -2701,6 +2976,34 @@ snapshots:
argparse: 1.0.10
esprima: 4.0.1
jsdom@27.2.0:
dependencies:
'@acemir/cssom': 0.9.23
'@asamuzakjp/dom-selector': 6.7.4
cssstyle: 5.3.3
data-urls: 6.0.0
decimal.js: 10.6.0
html-encoding-sniffer: 4.0.0
http-proxy-agent: 7.0.2
https-proxy-agent: 7.0.6
is-potential-custom-element-name: 1.0.1
parse5: 8.0.0
saxes: 6.0.0
symbol-tree: 3.2.4
tough-cookie: 6.0.0
w3c-xmlserializer: 5.0.0
webidl-conversions: 8.0.0
whatwg-encoding: 3.1.1
whatwg-mimetype: 4.0.0
whatwg-url: 15.1.0
ws: 8.18.3
xml-name-validator: 5.0.0
transitivePeerDependencies:
- bufferutil
- supports-color
- utf-8-validate
optional: true
json-schema-traverse@1.0.0: {}
jsonfile@4.0.0:
@@ -2717,12 +3020,18 @@ snapshots:
lodash@4.17.21: {}
lru-cache@11.2.2:
optional: true
magic-string@0.30.21:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
math-intrinsics@1.1.0: {}
mdn-data@2.12.2:
optional: true
media-typer@1.1.0: {}
merge-descriptors@2.0.0: {}
@@ -2788,6 +3097,11 @@ snapshots:
dependencies:
quansync: 0.2.11
parse5@8.0.0:
dependencies:
entities: 6.0.1
optional: true
parseurl@1.3.3: {}
path-exists@4.0.0: {}
@@ -2827,6 +3141,9 @@ snapshots:
forwarded: 0.2.0
ipaddr.js: 1.9.1
punycode@2.3.1:
optional: true
qs@6.14.0:
dependencies:
side-channel: 1.1.0
@@ -2915,6 +3232,11 @@ snapshots:
safer-buffer@2.1.2: {}
saxes@6.0.0:
dependencies:
xmlchars: 2.2.0
optional: true
semver@7.7.3: {}
send@1.2.0:
@@ -3031,6 +3353,9 @@ snapshots:
dependencies:
has-flag: 4.0.0
symbol-tree@3.2.4:
optional: true
term-size@2.2.1: {}
tinybench@2.9.0: {}
@@ -3044,6 +3369,14 @@ snapshots:
tinyrainbow@3.0.3: {}
tldts-core@7.0.18:
optional: true
tldts@7.0.18:
dependencies:
tldts-core: 7.0.18
optional: true
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
@@ -3052,6 +3385,16 @@ snapshots:
totalist@3.0.1: {}
tough-cookie@6.0.0:
dependencies:
tldts: 7.0.18
optional: true
tr46@6.0.0:
dependencies:
punycode: 2.3.1
optional: true
tree-kill@1.2.2: {}
tslib@2.8.1: {}
@@ -3134,7 +3477,7 @@ snapshots:
fsevents: 2.3.3
tsx: 4.20.6
vitest@4.0.8(@types/node@24.10.1)(@vitest/ui@4.0.8)(tsx@4.20.6):
vitest@4.0.8(@types/node@24.10.1)(@vitest/ui@4.0.8)(jsdom@27.2.0)(tsx@4.20.6):
dependencies:
'@vitest/expect': 4.0.8
'@vitest/mocker': 4.0.8(vite@7.2.2(@types/node@24.10.1)(tsx@4.20.6))
@@ -3159,6 +3502,7 @@ snapshots:
optionalDependencies:
'@types/node': 24.10.1
'@vitest/ui': 4.0.8(vitest@4.0.8)
jsdom: 27.2.0
transitivePeerDependencies:
- jiti
- less
@@ -3173,6 +3517,28 @@ snapshots:
- tsx
- yaml
w3c-xmlserializer@5.0.0:
dependencies:
xml-name-validator: 5.0.0
optional: true
webidl-conversions@8.0.0:
optional: true
whatwg-encoding@3.1.1:
dependencies:
iconv-lite: 0.6.3
optional: true
whatwg-mimetype@4.0.0:
optional: true
whatwg-url@15.1.0:
dependencies:
tr46: 6.0.0
webidl-conversions: 8.0.0
optional: true
which@2.0.2:
dependencies:
isexe: 2.0.0
@@ -3192,6 +3558,12 @@ snapshots:
ws@8.18.3: {}
xml-name-validator@5.0.0:
optional: true
xmlchars@2.2.0:
optional: true
y18n@5.0.8: {}
yargs-parser@21.1.1: {}